cmake 学习笔记

cmake 学习笔记,第1张

cmake 学习笔记

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 来控制改宏定义是否存在!!!

(6.1)add_definitions: 增加源代码的宏定义

main.c

#include 
int 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都显式的指定其值。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5714255.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存