《Cmake 实践》摘要


前言


第三章 初试cmake

3.1. 源码

  • 主要包括 main.cCMakeLists.txt
  • main.c
#include <stdio.h>
int main()
{
    printf("Hello World from t1 Main!\n");
    return 0;
}
  • CMakeLists.txt
PROJECT (HELLO)
SET(SRC_LIST "main.c")
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir " ${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})

3.2. 基本操作流程

  • 第一步,当前文件夹下执行 cmake .,生成 Makefile 文件。
    • 这样做是内部构建。
  • 第二步,执行 make
  • 第三步:通过 ./hello 运行程序。

3.3. CMakeLists.txt 文件的解释

  • PROJECT(projectname [CXX] [C] [Java]):指定工程名称,还可以指定语言。
    • 隐形定义了两个变量 <projectname>_BINARY_DIR<projectname>_SOURCE_DIR,指的都是工程所路径(猜测就是root CMakeLists.txt 所在路径)。
    • cmake 预定义了两个变量 PROJECT_BINARY_DIRPROJECT_SOURCE_DIR
      • 内部编译时与上面两个变量的功能相同。
      • 外部编译时表示的是编译目录,比如构建的build目录。
  • SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]]):显示定义变量,如果要使用VAR需要通过 ${} 来包裹。
    • 可以指定单个变量,也可以指定list。
    • SET(SRC_LIST main.c)
    • SET(SRC_LIST main.c t1.c t2.c)
  • MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...):终端输出用于定义的信息。
    • 包括三个类型:
      • SEND_ERROR 只输出错误,生成过程被跳过
      • STATUS输出前缀为-的信息
      • FATAL_ERROR立即终止所有cmake过程
  • ADD_EXECUTABLE(hello ${SRC_LIST}):生成一个名为 hello 的可执行文件

3.4. 基本语法规则

  • 变量使用 ${} 的方式取值,但是在 IF 控制语句中是直接使用变量名的。
  • 指令的基本格式是 指令(参数1 参数2 ...),参数使用括弧括起,参数之间使用空格或分号分开。
  • 指令是大小写无关,参数和变量是大小写相关
  • 如果文件名中有空格,那必须用双引号,如 set(SRC_LIST "fu nc.c")
  • 可以省略源文件的后缀,如 ADD_EXECUTABLE(t1 main) 就会自动寻找 main.c/main.cpp
    • 不推荐使用

3.5. 内部构建与外部构建

  • 猜测内部构建就是在CMakeLists文件所在路径执行cmake命令。
  • 推荐使用外部构建,即建立单独的文件夹,然后在里面执行 cmake 命令。
    • PROJECT_BINARY_DIR 在内部编译中与 PROJECT_SOURCE_DIR 相同,如果是外部编译则指的是外部编译坐在目录,比如 build 目录。

第四章 更好一点的Hello World

4.1. 源码

  • 项目文件结构如下
project
|_ src
|  |_ main.c
|  |_ CMakeLists.txt
|_ doc
|  |_ hello.txt
|_ bin
|  |_ hello
|_ COPYRIGHT
|_ README
|_ runhello.sh
|_ CMakeLists.txt
  • main.c 与前一节完全一样
#include <stdio.h>
int main()
{
    printf("Hello World from t1 Main!\n");
    return 0;
}
  • 有想个CMkakeLists.txt文件
// 根目录下 CMake Lists.txt 内容
PROJECT (HELLO)
ADD_SUBDIRECTORY(src bin)
INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/test2 )
INSTALL(PROGRAMS runhello.sh DESTINATION bin)
INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake/test2)

// src目录下 CMake Lists.txxt 内容
ADD_EXECUTABLE(hello main.c)
INSTALL(TARGETS hello RUNTIME DESTINATION bin)

4.2. 目标以及源码解释

  • 目标:
    • 将构建后的目标文件放入构建目录的bin子目录中
    • 最终安装这些文件:将 hello 二进制与 runshello.sh 安装到 /usr/bin,将doc目录的内容以及 COPYRIGHT/README 安装到当前项目路径下。
  • ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
    • 作用:向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置
    • EXCLUDE_FROM_ALL 参数的含义是将这个目录从编译过程中排除,例如工程example,一般会在工程建立完成后单独构建。
    • 上面的例子中 ADD_SUBDIRECTORY(src bin)src 子目录加入工程,并制定编译输出(包括中间结果)路径为bin目录。
      • 如果不指定 bin,那么默认放在 src目录中。
    • 可以通过SET指令修改EXECUTABLE_OUTPUT_PATHLIBRARY_OUTPUT_PATH 变量
      来指定最终的目标二进制的位置(不包含中间文件)。

4.3. INSTALL 命令详解

  • INSTALL 命令的作用:安装,猜测就是把目标文件、文件夹放到指定位置。
    • 基本流程:就是先 cmake ..make,最后再加上一步make install
  • 常用变量 CMAKE_INSTALL_PREFIX
    • 类似于 configure 脚本的 --prefix
    • 配合INSTALL命令中的 DESTINATION 构建安装路径
    • 默认定义是 /usr/local
    • 使用的时候就是 -DCMAKE_INSTALL_PREFIX=/usr
  • INSTALL 命令分类
    • TARGETS:目标文件,如二进制、动态库、静态库
    • FILES:普通文件
    • PROGRAMS:脚本
    • DIRECTORY:目录
  • TARGETS
    • TARGETS 后面跟的就是通过 ADD_EXECUTABLEADD_LIBRARY 定义的目标文件,包括二进制可执行文件、动态库、静态库。
    • ARCHIVE 特指静态库,LIBRARY 特指动态库,RUNTIME 特指可执行目标二进制。
    • DESTINATION 定义了安装路径。如果以/开头表示绝对路径,此时CMAKE_INSTALL_PREFIX无效;如果是相对路径,那么最终安装路径就是 ${CMAKE_INSTALL_PREFIX}/<DESTINATION 定义的路径>
INSTALL(TARGETS targets...
    [[ARCHIVE|LIBRARY|RUNTIME]
        [DESTINATION <dir>]
        [PERMISSIONS permissions...]
        [CONFIGURATIONS[Debug|Release|...]]
        [COMPONENT <component>]
        [OPTIONAL]
    ] [...])
  • TARGETS 命令举例
    • 将二进制myrun安装到 ${CMAKE_INSTALL_PREFIX}/bin
    • 将动态库mylib安装到 ${CMAKE_INSTALL_PREFIX}/lib
    • 将静态库mystaticlib安装到 ${CMAKE_INSTALL_PREFIX}/libstatic
INSTALL(TARGETS myrun mylib mystaticlib
    RUNTIME DESTINATION bin
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION libstatic
)
  • FILE:普通文件安装
    • 安装一般文件,并设置访问权限。
INSTALL(FILES files... DESTINATION <dir>
    [PERMISSIONS permissions...]
    [CONFIGURATIONS [Debug|Release|...]]
    [COMPONENT <component>]
    [RENAME <name>] [OPTIONAL])
  • PROGRAMS:非目标文件的可执行程序安装(例如脚本)
INSTALL(PROGRAMS files... DESTINATION <dir>
    [PERMISSIONS permissions...]
    [CONFIGURATIONS [Debug|Release|...]]
    [COMPONENT <component>]
    [RENAME <name>] [OPTIONAL])
  • DIRECTORY:目录安装
INSTALL(DIRECTORY dirs... DESTINATION <dir>
    [FILE_PERMISSIONS permissions...]
    [DIRECTORY_PERMISSIONS permissions...]
    [USE_SOURCE_PERMISSIONS]
    [CONFIGURATIONS [Debug|Release|...]]
    [COMPONENT <component>]
    [[PATTERN <pattern> | REGEX <regex>]
    [EXCLUDE] [PERMISSIONS permissions...]] [...])

第五章 静态库与动态库构建

  • 目标:
    • 建立一个静态库和动态库,提供 HelloFun 函数供其他程序编程使用,HelloFunc向终端输出 Hello World 字符串。
    • 安装头文件与共享库。

5.1. 源码

  • 建立 lib 文件夹,新建两个原文件,hello.c/hello.h
// main.c
#include "hello.h"
void HelloFunc() 
{
    printf("Hello World\n");
}


// main.h
#ifndef HELLO_H
#define HELLO_H
#include <stdio.h>
void HelloFunc();
#endif
  • CMakeLists.txt 有两个,分别在根目录和lib文件夹中
# 根目录
PROJECT(HELLOLIB)
ADD_SUBDIRECTORY(lib)


# lib 文件夹
SET(LIBHELLO_SRC hello.c)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})

5.2. ADD_LIBRARY & SET_TARGET_PROPERTIES 解析

  • ADD_LIBRARY 指令基本形式请参考下面代码
    • 假设libname是 hello,则默认获取的就是 libhello.so/libhello.a 文件。
    • SHARED指动态库(.so文件),STATIC指静态库(.a文件),MODULE使用dyld系统有效(如果不支持,则被当做动态库)。
    • 限制:libname 不能重复,因此如果想为一个库同时建立动态库与静态库,需要使用两个 ADD_LIBRARY,且两个名称必须不一样,则不能同时获取 libhello.so/libhello.a 文件。
ADD_LIBRARY(libname [SHARED|STATIC|MODULE]
    [EXCLUDE_FROM_ALL]
    source1 source2 ... sourceN)
  • SET_TARGET_PROPERTIES 指令
    • 同时获取 libhello.so/libhello.a 文件。
    • 指定动态库版本。
// 命令形式
SET_TARGET_PROPERTIES(target1 target2 ...
    PROPERTIES prop1 value1
    prop2 value2 ...)、

// 同时生成动态库与静态库
SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)

// 指定API版本与动态库版本
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)

第六章 如何使用外部共享库和头文件

  • 目标:编写程序使用上一届构建的共享库。

6.1. 源码

  • 构建src目录 ,包含 main.c
#include <hello.h>

int main(void)
{
    HelloFunc();

    return 0;
}
  • 有两个CMakeLists.txt,分别在根目录和src目录下
# 根目录
PROJECT(HELLO)
ADD_SUBDIRECTORY(src)

# src 目录
INCLUDE_DIRECTORIES(/usr/include/hello)
TARGET_LINK_LIBRARIES(main hello)
ADD_EXECUTABLE(main main.c)

6.2. INCLUDE_DIRECTORIES & LINK_DIRECTORIES & TARGET_LINK_LIBRARIES

  • INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)
    • 作用:向工程添加多个特定的头文件搜索路径。
    • 路径之间用空格分隔。
    • 如果路径包含空格,可以通过双引号括起来。
    • CMAKE_INCLUDE_DIRECTORIES_BEFORE:通过 SET 这个 cmake 变量为 on,可以将添加的头文件搜索路径放在已有路径的前面
    • 通过 AFTER 或者 BEFORE 参数,也可以控制是追加还是置前。
  • LINK_DIRECTORIES(directory1 directory2 ...)
    • 添加非标准的共享库搜索路径
    • 在工程内部同时存在共享库和可执行二进制,在编译时就需要指定一下这些共享库的路径
  • TARGET_LINK_LIBRARIES
    • 为 target 添加需要链接的共享库,可以是可执行文件,也可以是共享库。
TARGET_LINK_LIBRARIES(target library1
                    <debug | optimized> library2
                    ...)

6.3. 相关环境变量

  • 注意,这里是环境变量,而不是cmake变量。
  • CMAKE_INCLUDE_PATHCMAKE_LIBRARY_PATH
    • 主要是用来解决以前 autotools 工程中 --extra-include-dir 等参数的支持的。
  • INCLUDE_DIRECTORIES(/usr/include/hello) 等价于:
    • 新增环境变量 export CMAKE_INCLUDE_PATH=/usr/include/hello
    • 以及下面四句,寻找hello.h所在路径,并添加到cmake环境中。
    • CMAKE_INCLUDE_PATH 以及系统默认头文件目录 /usr/include/usr/local/include 中寻找。
FIND_PATH(myHeader hello.h)
IF(myHeader)
INCLUDE_DIRECTORY(${myHeader})
ENDIF(myHeader)
  • 类似的,CMAKE_LIBRARY_PATH 环境变量可与 FIND_LIBRARY 配合使用。

第七章 cmake 常用变量和常用环境变量

  • cmake变量引用方法:

    • 一般使用 ${} 引用,如果在IF等语句中,可以直接使用变量名。
  • cmake自定义变量的方式

    • 隐式定义,例如PROJECT指令会隐式定义 <projectname>_BINARY_DIR 变量。
    • 显示定义,通过SET指令,如SET(HELLO_SRC main.c)
  • cmake 常用变量

    • CMAKE_BINARY_DIR/PROJECT_BINARY_DIR/<projectname>_BINARY_DIR
      • 这三个变量指代的内容一致。
      • 如果是内部构建,则表示项目顶层目录;如果是外部构建,指的是工程编译发生的目录。
      • PROJECT_BINARY_DIR 稍有区别,但此处可理解为是一致的。
    • CMAKE_SOURCE_DIR/PROJECT_SOURCE_DIR/<projectname>_SOURCE_DIR
      • 这三个变量内容是一致的。
      • 不管什么构建方式,都指的是工程顶层目录。
    • CMAKE_CURRENT_SOURCE_DIR:当前处理的 CMakeLists.txt 所在的路径,比如上面我们提到的 src 子目录。
    • CMAKE_CURRRENT_BINARY_DIR
      • 如果是 in-source 编译,它跟 CMAKE_CURRENT_SOURCE_DIR 一致,如果是 out-ofsource 编译,他指的是 target 编译目录。
      • ADD_SUBDIRECTORY(src bin) 可以更改这个变量的值。
      • SET(EXECUTABLE_OUTPUT_PATH <新路径>) 并不会对这个变量造成影响,它仅仅修改了最终目标文件存放的路径
    • CMAKE_CURRENT_LIST_FILE:输出调用这个变量的 CMakeLists.txt 的完整路径
    • CMAKE_CURRENT_LIST_LINE:输出这个变量所在的行
    • CMAKE_MODULE_PATH:定义自己的 cmake 模块所在的路径
    • EXECUTABLE_OUTPUT_PATH/LIBRARY_OUTPUT_PATH:分别用来重新定义最终结果的存放目录
    • PROJECT_NAME:返回通过 PROJECT 指令定义的项目名称
  • cmake 调用环境变量的方式

    • 使用:$ENV{NAME}
    • 设置:SET(ENV{变量名} 值)
  • 还有一些,直接看网页吧。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值