cmake 学习笔记
最基础语法:cmake_minimum_required (VERSION 2.8) #设定 cmake 的最低版本要求 project (demo) #设定 工程名 add_executable(main main.c) #生成名为main的可执行文件, main.c是文件名 如果存在多个源文件,在后面加即可,用空格隔开
执行(之后的讲解就不再说执行的这步了)
cmake . # 编译文件到【当前目录(一定是)】下, .指定的是 CMakleLists.txt 的路径,也是工程的根目录! make # 链接生成可执行文件 ./main #执行文件进阶命令 (1)aux_source_directory,include_directories,set
aux_source_directory(. SRC_LIST) # 将 ./ 目录下的所有文件的路径 赋值给 SRC_LIST 变量(变量名随意取) add_executable(main ${SRC_LIST}) # 将 ./ 目录下的所有文件的路径包含,并生成可执行文件 # SET 的意思实际是 赋值 # 调用: ${prefix} SET( prefix ${ROOT_PATH}/src/shared ) # 设置前缀 SET( sources, main.c func.c # 设置包含文件 func2.c ) unset(prefix) #删除 prefix 变量 include_directories (test_func test_func1) #增加头文件搜索路径 [增加完成之后, 可以不用加路径,就可以直接include 头文件;相当于 vs 中的 额外包含路径] # 就是说,本来是 #include "test_func/func.h" 可以变为 #include "func.h"
案例:
文件目录:
main.c test_func/func.h test_func/func.c test_func1/func1.h test_func1/func1.h
CMakeLists.txt
cmake_minimum_required (VERSION 2.8) project (demo) include_directories (test_func test_func1) # 增加头文件搜索目录, main.c可以不用加 test_func和test_func1前缀就可以引用头文件 aux_source_directory (test_func SRC_LIST) # 将 test_func 目录下的文件添加到 SRC_LIST aux_source_directory (test_func1 SRC_LIST1) # 将 test_func1 目录下的文件添加到 SRC_LIST1 set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) # 指定生成可执行文件的目录,其中 EXECUTABLE_OUTPUT_PATH 和 PROJECT_SOURCE_DIR 是cmake 的预定义变量 # EXECUTABLE_OUTPUT_PATH 的是 可执行文件的存放目录 # PROJECT_SOURCE_DIR 根目录所在路径,即 CMakeLists.txt 所在目录 add_executable (main main.c ${SRC_LIST} ${SRC_LIST1}) # 生成可执行文件, 源文件包括 main.c,以及 test_func 和 test_func1目录下的所有文件 【注意:include_directories只是少写路径前缀,并将其添加到 SRC_List】(2)add_subdirectory
add_subdirectory(subDir outDir EXCLUDE_FROM_ALL) 详情: https://www.jianshu.com/p/07acea4e86a3 大概用法:根目录和子目录都存在 CMAKELIST.txt文件,其中 根目录中CMAKELIST.txt 调用这个函数, 即可对 subDir 子目录的 CMAKELIST.txt 进行编译 subDir 指定子目录,必填 outDir 执行子目录生成可执行文件的存放目录,选填【不填默认根目录】 EXCLUDE_FROM_ALL 即不生成可执行文件 选填 【【【注意: 执行子目录的 CMAKELISTS.txt 文件,其子目录的程序会继承根目录的变量。 但是,由于目录位置已经发送了变化,如果使用根目录的 目录变量,会报错!!!(3)编译动态库和静态库
文件:(不带后缀为文件夹)
build CMAKELIST.txt lib testFunc testFunc/func.h testFunc/func.c
CMakeLists.txt
cmake_minimum_required (VERSION 3.5) project (demo) set (SRC_LIST ${PROJECT_SOURCE_DIR}/testFunc/testFunc.c) add_library (testFunc_shared SHARED ${SRC_LIST}) add_library (testFunc_static STATIC ${SRC_LIST}) set_target_properties (testFunc_shared PROPERTIES OUTPUT_NAME "testFunc") set_target_properties (testFunc_static PROPERTIES OUTPUT_NAME "testFunc") set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
命令详解:
add_library: 生成动态库或者静态库
参数:
第一个:生成的库变量
第二个:指定是动态还是静态,不填(只有两个参数)默认静态STATIC
第三个:指定生成库的源文件列表(文件的相对或绝对路径组组成的列表)
set_target_properties: 设置目标变量的属性;
参数:第一个参数目标变量,testFunc_shared #库变量
第二个参数目标属性 PROPERTIES OUTPUT_NAME #同字面意思,属性输出名字,即库最终的名
第三个参数目标值 "testFunc"
注意:如果不设置名字,默认用 库变量的名字,即 testFunc_shared 最终获得动态库 libtestFunc_shared.so [库都要加前后缀, libxxx.a 或者 libxxx.so]
LIBRARY_OUTPUT_PATH : 预定义变量,用来指定库文件的默认输出路径
(4)调用动态库和静态库CMakeLists.txt
cmake_minimum_required (VERSION 3.5) project (demo) set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) set (SRC_LIST ${PROJECT_SOURCE_DIR}/src/main.c) # find testFunc.h include_directories (${PROJECT_SOURCE_DIR}/testFunc/inc) find_library(TESTFUNC_LIB NAMES testFunc HINTS ${PROJECT_SOURCE_DIR}/testFunc/lib) add_executable (main ${SRC_LIST}) target_link_libraries (main ${TESTFUNC_LIB})
命令详解:
find_library :查找库文件
参数: 第一个 库变量: TESTFUNC_LIB 查找成功后将库文件存入到这个变量 第二个 库名: NAMES testFunc 就是要搜索的库名,默认是动态库,也可显示指定是动静态库:testFunc.a, testFunc.so;可以指定多个库 NAMES lib1 lib2(可以不加NAMES,但是不建议,可读性不高) 第三个 搜索路径:"HINTS ${PROJECT_SOURCE_DIR}/testFunc/lib" , 即 搜索 ${PROJECT_SOURCE_DIR}/testFunc/lib 路径下的库文件 HINTS 可以替换为 PATHS find_library的好处是在执行cmake ..时就会去查找库是否存在,这样可以提前发现错误,不用等到链接时。 还有其他参数,可看: https://blog.csdn.net/comedate/article/details/109684446 target_link_libraries: 把目标文件与库文件进行链接 [注意是生成目标文件后](5)添加编译选项
cmake_minimum_required (VERSION 2.8) project (demo) set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) add_compile_options(-std=c++11 -Wall) #支持C++11标准 以及 强制输出所有报错信息 add_executable(main main.cpp)
add_compile_options 命令就是添加 编译的一些选项
(6)添加控制选项:控制 CMAKELIST.txt 文件运行流程(相当于 CMAKELSIT 的宏定义)
文件:
bin build CMAKELIST.txt src src/CMAKELIST.txt #子目录也有CMAKELIST.txt LIST.txt src/main1.c src/main2.c
外层 MAKELIST.txt 内容:
cmake_minimum_required(VERSION 3.5) project(demo) option(MYDEBUG "enable debug compilation" OFF) set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) add_subdirectory(src) #执行子目录src的CMAKELISTs.txt [该命令上面介绍过了]
参数详解:
option: 增加类似宏定义的变量
参数:第一个: option变量名
第二个:描述变量的字符串
第三个:option 的值,ON 或者 OFF(不填默认OFF)
内层 MAKELIST.txt
cmake_minimum_required (VERSION 3.5) add_executable(main1 main1.c) if (MYDEBUG) add_executable(main2 main2.c) else() message(STATUS "Currently is not in debug mode") endif()
参数详解:
这里使用 if-else 根据 MYDEBUG 来决定是否编译 main.c,如果MYDEBUG=OFF,if判断失败不编译
MYDEBUG 也可以用命令行定义:
cmake … -DMYDEBUG=ON && make #这样就可以达到控制效果
!注意:
option(MYDEBUG “enable debug compilation” OFF) 是 关闭 MYDEBUG
cmake … -DMYDEBUG=ON && make #是 打开 MYDEBUG
命令会先执行 option 再执行 -DMYDEBUG=ON, 也就是说,只要 option 默认是 OFF, 就可以用 -D 来控制改宏定义是否存在!!!
main.c
#includeint main(void) { #ifdef WWW1 printf("hello world1n"); #endif #ifdef WWW2 printf("hello world2n"); #endif return 0; }
外层 CMKAELIST.txt
cmake_minimum_required(VERSION 3.5) project(demo) set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) option(WWW1 "print one message" OFF) #这里定义关闭,有cmake 时指定是否打开 option(WWW2 "print another message" OFF) if (WWW1) add_definitions(-DWWW1) #如果打开了,那么增加 宏定义 endif() if (WWW2) add_definitions(-DWWW2) endif() add_executable(main main.c) #执行
注意: main.c代码中的 WWW1 宏定义就是 CMakeLists.txt 中的 add_definitions(-DWWW1)定义的 -DWWW1, 同时也是 cmake … DWWW1=ON 中的DWWW1;
执行cmake
cmake .. -DWWW1=ON -DWWW2=OFF && make cmake .. -DWWW1=OFF -DWWW2=ON && make cmake .. -DWWW1=ON -DWWW2=ON && make
命令详解:
通过 -DWWW1=ON 来添加控制选项,然后 运行到CMAKELIST.txt 里的 if (WWW1) == true,然后运行 add_definitions(-DWWW1) 最终达到 #defnie WWW1 的效果
注意:
这里有个小坑要注意下:假设有2个options叫A和B,先调用cmake设置了A,下次再调用cmake去设置B,如果没有删除上次执行cmake时产生的缓存文件,那么这次虽然没设置A,也会默认使用A上次的option值。
所以如果option有变化,要么删除上次执行cmake时产生的缓存文件,要么把所有的option都显式的指定其值。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)