【个人收藏笔记】CMakeLists.txt 语法简明教程

    技术2024-06-23  103

    文章目录

    常用命令1. 指定cmake的最小版本2. 设置项目名称3. 设置编译类型4. 指定编译包含的源文件4.1 明确指定包含哪些源文件4.2 搜索所有的cpp文件4.3 自定义搜索规则 5. 查找指定的库文件6. 设置包含的目录7. 设置链接库搜索目录8. 设置target需要链接的库8.1 指定链接动态库或静态库8.2 指定全路径8.3 指定链接多个库 9. 设置变量9.1 set直接设置变量的值9.2 set追加设置变量的值9.3 list追加或删除变量的值 10. 条件控制10.1 if…elseif…else…endif10.2 while…endwhile10.3 foreach…endforeach 11.打印消息12.包含其他cmake文件 常用变量1. 预定义变量2. 环境变量3. 系统变量4.主要开关选项 项目实例1. 简单项目(单个源文件)2. 复杂项目(多个目录,多个源文件)3. 自定义编译选项4. ROS功能包自动生成的CMakeLists.txt模板 项目目录

    ├── demo项目目录 │ ├── CMakeLists.txt │ ├── include目录 │ │ ├── hello.h │ ├── src 目录 │ │ ├── hello.cpp │ ├── lib目录 │ ├── biuld目录 CMAKE_MINIMUM_REQUIRED(VERSION 3.14) #指定项目名称 PROJECT(HELLO) #将hello.cpp 赋值给SOURCE 变量 SET(SOURCE ${PROJECT_SOURCE_DIR}/src/hello.cpp) #指定头文件目录 INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include) #指定链接库文件目录 LINK_DIRECTORIES(${PROJECT_SOURCE_DIR}/lib) #将hello.cpp生成可执行文件hello ADD_EXECUTABLE(hello ${SOURCE}) #指定hello 链接库myprint TARGET_LINK_LIBRARIES(hello myprint)

    常用命令

    1. 指定cmake的最小版本

    # 最小版本为2.8,可不写 cmake_minimum_required(VERSION 2.8)

    2. 设置项目名称

    # 非强制性命令,会引入两个变量:demo_BINARY_DIR 、 demo_SOURCE_DIR # 同时cmake自动定义两个等价变量: PROJECT_BINARY_DIR 、 PROJECT_SOURCE_DIR project(demo)

    3. 设置编译类型

    add_executable(demo demo.cpp) # 生成可执行文件 add_library(common STATIC util.cpp) # 生成静态库 add_library(common SHARED util.cpp) # 生成动态库或共享库 在 Linux 下是: demo libcommon.a libcommon.so在 Windows 下是: demo.exe common.lib common.dll

    4. 指定编译包含的源文件

    4.1 明确指定包含哪些源文件

    add_library(demo demo.cpp test.cpp util.cpp)

    4.2 搜索所有的cpp文件

    aux_source_directory(dir VAR)发现一个目录下所有的源代码文件并将列表存储在一个变量中

    aux_source_directory(. SRC_LIST) # 搜索当前目录下的所有.cpp文件 add_library(demo ${SRC_LIST})

    4.3 自定义搜索规则

    file(GLOB SRC_LIST "*.cpp" "protocol/*.cpp") add_library(demo ${SRC_LIST}) # 或者 file(GLOB SRC_LIST "*.cpp") file(GLOB SRC_PROTOCOL_LIST "protocol/*.cpp") add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST}) # 或者 aux_source_directory(. SRC_LIST) aux_source_directory(protocol SRC_PROTOCOL_LIST) add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})

    5. 查找指定的库文件

    find_library(VAR name path)查找到指定的预编译库,并将它的路径存储在变量中。 默认的搜索路径为 cmake 包含的系统库,因此如果是 NDK 的公共库只需要指定库的 name 即可。

    find_library( # Sets the name of the path variable. log-lib # Specifies the name of the NDK library that # you want CMake to locate. log )

    类似的命令还有 find_file()、find_path()、find_program()、find_package()。

    6. 设置包含的目录

    include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include )

    Linux 下还可以通过如下方式设置包含的目录:

    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}")

    7. 设置链接库搜索目录

    link_directories( ${CMAKE_CURRENT_SOURCE_DIR}/libs )

    Linux 下还可以通过如下方式设置包含的目录:

    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_CURRENT_SOURCE_DIR}/libs")

    8. 设置target需要链接的库

    target_link_libraries( # 目标库 demo # 目标库需要链接的库 # log-lib 是上面 find_library 指定的变量名 ${log-lib} )

    在 Windows 下,系统会根据链接库目录,搜索xxx.lib 文件,Linux 下会搜索 xxx.so 或者 xxx.a 文件,如果都存在会优先链接动态库(so 后缀)。

    8.1 指定链接动态库或静态库

    target_link_libraries(demo libface.a) # 链接libface.a target_link_libraries(demo libface.so) # 链接libface.so

    8.2 指定全路径

    target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a) target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.so)

    8.3 指定链接多个库

    target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a boost_system.a boost_thread pthread)

    9. 设置变量

    9.1 set直接设置变量的值

    set(SRC_LIST main.cpp test.cpp) add_executable(demo ${SRC_LIST})

    9.2 set追加设置变量的值

    set(SRC_LIST main.cpp) set(SRC_LIST ${SRC_LIST} test.cpp) add_executable(demo ${SRC_LIST})

    9.3 list追加或删除变量的值

    set(SRC_LIST main.cpp) list(APPEND SRC_LIST test.cpp) list(REMOVE_ITEM SRC_LIST main.cpp) add_executable(demo ${SRC_LIST})

    10. 条件控制

    10.1 if…elseif…else…endif

    逻辑判断和比较:

    if (expression):expression 不为空(0,N,NO,OFF,FALSE,NOTFOUND)时为真if (not exp):与上面相反if (var1 AND var2)if (var1 OR var2)if (COMMAND cmd):如果 cmd 确实是命令并可调用为真if (EXISTS dir) if (EXISTS file):如果目录或文件存在为真if (file1 IS_NEWER_THAN file2):当 file1 比 file2 新,或 file1/file2 中有一个不存在时为真,文件名需使用全路径if (IS_DIRECTORY dir):当 dir 是目录时为真if (DEFINED var):如果变量被定义为真if (var MATCHES regex):给定的变量或者字符串能够匹配正则表达式 regex 时为真,此处 var 可以用 var 名,也可以用 ${var}if (string MATCHES regex)

    数字比较:

    if (variable LESS number):LESS 小于if (string LESS number)if (variable GREATER number):GREATER 大于if (string GREATER number)if (variable EQUAL number):EQUAL 等于if (string EQUAL number)

    字母表顺序比较:

    if (variable STRLESS string)if (string STRLESS string)if (variable STRGREATER string)if (string STRGREATER string)if (variable STREQUAL string)if (string STREQUAL string) if(MSVC) set(LINK_LIBS common) else() set(boost_thread boost_log.a boost_system.a) endif() target_link_libraries(demo ${LINK_LIBS}) # 或者 if(UNIX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fpermissive -g") else() add_definitions(-D_SCL_SECURE_NO_WARNINGS D_CRT_SECURE_NO_WARNINGS -D_WIN32_WINNT=0x601 -D_WINSOCK_DEPRECATED_NO_WARNINGS) endif() if(${CMAKE_BUILD_TYPE} MATCHES "debug") ... else() ... endif()

    10.2 while…endwhile

    while(condition) ... endwhile()

    10.3 foreach…endforeach

    foreach(loop_var RANGE start stop [step]) ... endforeach(loop_var)

    start 表示起始数,stop 表示终止数,step 表示步长,示例:

    foreach(i RANGE 1 9 2) message(${i}) endforeach(i) # 输出:13579

    11.打印消息

    message(${PROJECT_SOURCE_DIR}) message("build with debug mode") message(WARNING "this is warnning message") message(FATAL_ERROR "this build has many error") # FATAL_ERROR 会导致编译失败

    12.包含其他cmake文件

    include(./common.cmake) # 指定包含文件的全路径 include(def) # 在搜索路径中搜索def.cmake文件 set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # 设置include的搜索路径

    常用变量

    1. 预定义变量

    PROJECT_SOURCE_DIR:工程的根目录PROJECT_BINARY_DIR:运行 cmake 命令的目录,通常是 ${PROJECT_SOURCE_DIR}/buildPROJECT_NAME:返回通过 project 命令定义的项目名称CMAKE_CURRENT_SOURCE_DIR:当前处理的 CMakeLists.txt 所在的路径CMAKE_CURRENT_BINARY_DIR:target 编译目录CMAKE_CURRENT_LIST_DIR:CMakeLists.txt 的完整路径CMAKE_CURRENT_LIST_LINE:当前所在的行CMAKE_MODULE_PATH:定义自己的 cmake 模块所在的路径,SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake),然后可以用INCLUDE命令来调用自己的模块EXECUTABLE_OUTPUT_PATH:重新定义目标二进制可执行文件的存放位置LIBRARY_OUTPUT_PATH:重新定义目标链接库文件的存放位置

    2. 环境变量

    使用环境变量

    $ENV{Name}

    写入环境变量

    set(ENV{Name} value) # 这里没有“$”符号

    3. 系统变量

    ­CMAKE_MAJOR_VERSION:cmake 主版本号,比如 3.4.1 中的 3­CMAKE_MINOR_VERSION:cmake 次版本号,比如 3.4.1 中的 4­CMAKE_PATCH_VERSION:cmake 补丁等级,比如 3.4.1 中的 1­CMAKE_SYSTEM:系统名称,比如 Linux-­2.6.22­CMAKE_SYSTEM_NAME:不包含版本的系统名,比如 Linux­CMAKE_SYSTEM_VERSION:系统版本,比如 2.6.22­CMAKE_SYSTEM_PROCESSOR:处理器名称,比如 i686­UNIX:在所有的类 UNIX 平台下该值为 TRUE,包括 OS X 和 cygwin­WIN32:在所有的 win32 平台下该值为 TRUE,包括 cygwin

    4.主要开关选项

    ­BUILD_SHARED_LIBS:这个开关用来控制默认的库编译方式,如果不进行设置,使用 add_library 又没有指定库类型的情况下,默认编译生成的库都是静态库。如果 set(BUILD_SHARED_LIBS ON) 后,默认生成的为动态库­CMAKE_C_FLAGS:设置 C 编译选项,也可以通过指令 add_definitions() 添加­CMAKE_CXX_FLAGS:设置 C++ 编译选项,也可以通过指令 add_definitions()添加

    项目实例

    1. 简单项目(单个源文件)

    main.c

    #include <stdio.h> int main() { printf("Hello World!\n"); return 0; }

    CMakeLists.txt

    project(HELLO) add_executable(hello main.c)

    注意:命名必须是 CMakeLists.txt,注意大小写和不要漏字母

    编译和运行 在项目目录下新建一个build文件夹,依次执行:cd build cmake ..

    为什么要新建一个 build 文件夹? 一般我们采用 cmake 的 out-of-source 方式来构建(即生成的中间产物和源代码分离),这样做可以让生成的文件和源文件不会弄混,且目录结构看起来也会清晰明了。所以推荐使用这种方式,至于这个文件夹的命名并无限制,我们习惯命名为 build。

    2. 复杂项目(多个目录,多个源文件)

    demo 根目录下的 CMakeLists.txt 文件如下:

    cmake_minimum_required (VERSION 2.8) project(demo) aux_source_directory(. DIR_SRCS) # 添加math子目录 add_subdirectory(math) # 指定生成目标 add_executable(demo ${DIR_SRCS}) # 添加链接库 target_link_libraries(demo MathFunctions)

    math 目录下的 CMakeLists.txt 文件如下:

    aux_source_directory(. DIR_LIB_SRCS) # 生成链接库 add_library(MathFunctions ${DIR_LIB_SRCS})

    3. 自定义编译选项

    cmake 允许为项目增加编译选项,从而可以根据用户的环境和需求选择最合适的编译方案。

    例如,可以将 MathFunctions 库设为一个可选的库,如果该选项为 ON ,就使用该库定义的数学函数来进行运算,否则就调用标准库中的数学函数库。

    修改根目录下的 CMakeLists.txt 文件如下:

    # CMake 最低版本号要求 cmake_minimum_required (VERSION 2.8) # 项目信息 project (Demo) # 加入一个配置头文件,用于处理 CMake 对源码的设置 configure_file ( "${PROJECT_SOURCE_DIR}/config.h.in" "${PROJECT_BINARY_DIR}/config.h" ) # 是否使用自己的 MathFunctions 库 option (USE_MYMATH "Use provided math implementation" ON) # 是否加入 MathFunctions 库 if (USE_MYMATH) include_directories ("${PROJECT_SOURCE_DIR}/math") add_subdirectory (math) set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions) endif (USE_MYMATH) # 查找当前目录下的所有源文件 # 并将名称保存到 DIR_SRCS 变量 aux_source_directory(. DIR_SRCS) # 指定生成目标 add_executable(Demo ${DIR_SRCS}) target_link_libraries (Demo ${EXTRA_LIBS}) configure_file 命令用于加入一个配置头文件 config.h ,这个文件由 cmake 从 config.h.in 生成,通过这样的机制,将可以通过预定义一些参数和变量来控制代码的生成。option 命令添加了一个 USE_MYMATH 选项,并且默认值为 ON 。根据 USE_MYMATH 变量的值来决定是否使用我们自己编写的 MathFunctions 库。

    修改 main.cc 文件,让其根据 USE_MYMATH 的预定义值来决定是否调用标准库还是MathFunctions 库:

    #include "config.h" #ifdef USE_MYMATH #include "math/MathFunctions.h" #else #include <math.h> #endif int main(int argc, char *argv[]) { if (argc < 3){ printf("Usage: %s base exponent \n", argv[0]); return 1; } double base = atof(argv[1]); int exponent = atoi(argv[2]); #ifdef USE_MYMATH printf("Now we use our own Math library. \n"); double result = power(base, exponent); #else printf("Now we use the standard library. \n"); double result = pow(base, exponent); #endif printf("%g ^ %d is %g\n", base, exponent, result); return 0; }

    编写config.h.in文件: 注意 main.cc 的第一行,这里引用了一个 config.h 文件,这个文件预定义了 USE_MYMATH 的值。但我们并不直接编写这个文件,为了方便从 CMakeLists.txt 中导入配置,我们编写一个 config.h.in 文件,内容如下:

    #cmakedefine USE_MYMATH

    这样 cmake 会自动根据 CMakeLists.txt 配置文件中的设置自动生成 config.h 文件。

    4. ROS功能包自动生成的CMakeLists.txt模板

    cmake_minimum_required(VERSION 3.0.2) project(orocos_test) # add_compile_options(-std=c++11) find_package(catkin REQUIRED COMPONENTS roscpp ) #通过CMake的约定可以找到系统依赖关系 # find_package(Boost REQUIRED COMPONENTS system) ## 如果包有setup.py,则取消注释。这个宏确保安装其中声明的模块和全局脚本 # catkin_python_setup() ################################################ ## 声明ROS消息、服务和操作 ## ################################################ ## 在'msg'文件夹中生成消息 # add_message_files( # FILES # Message1.msg # Message2.msg # ) ## 在'srv'文件夹中生成服务 # add_service_files( # FILES # Service1.srv # Service2.srv # ) ## 在'action'文件夹中生成动作服务器 # add_action_files( # FILES # Action1.action # Action2.action # ) ## 使用此处列出的任何依赖项生成添加的消息和服务 # generate_messages( # DEPENDENCIES # std_msgs # 或其他含有msg的package # ) ################################################ ## 声明 ROS dynamic reconfigure parameters ## ################################################ ## 要在这个包中声明和构建动态重新配置参数,请遵循以下步骤: ## * In the file package.xml: ## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" ## * In this file (CMakeLists.txt): ## * add "dynamic_reconfigure" to find_package(catkin REQUIRED COMPONENTS ...) ## * uncomment the "generate_dynamic_reconfigure_options" section below and list every .cfg file to be processed ## 在“cfg”文件夹中生成动态重新配置参数 # generate_dynamic_reconfigure_options( # cfg/DynReconf1.cfg # cfg/DynReconf2.cfg # ) ################################### ## catkin specific configuration ## ################################### ## catkin_package宏为你的包生成cmake配置文件 ## 声明要传递给相关项目的内容 ## INCLUDE_DIRS: 如果包包含头文件,则取消注释 ## LIBRARIES: 在此项目中创建的依赖项目也需要的库 ## CATKIN_DEPENDS: 依赖于catkin_packages的项目也需要 ## DEPENDS: 此项目的系统依赖,依赖项目也需要 catkin_package( # INCLUDE_DIRS include # LIBRARIES orocos_test # CATKIN_DEPENDS orocos_kdl # DEPENDS system_lib ) ########### ## Build ## ########### ## 指定头文件的其他位置 ## 您的包位置应该列在其他位置之前 include_directories( # include ${catkin_INCLUDE_DIRS} ) ## 声明一个C++ library # add_library(${PROJECT_NAME} # src/${PROJECT_NAME}/orocos_test.cpp # ) ## 添加库的cmake目标依赖关系 ## 例如,代码可能需要在库生成之前生成 ## 从消息生成或动态重新配置 # add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) ## 声明一个c++可执行文件 ## 使用catkin_make,所有包都在单个CMake上下文中构建 ## 推荐的前缀确保包之间的目标名称不会冲突 # add_executable(${PROJECT_NAME}_node src/orocos_test_node.cpp) ## 重命名c++可执行文件没有前缀 ## 上面推荐的前缀会导致长目标名称,下面为方便用户使用而将目标重命名为短版本。 "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" # set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") ## 添加可执行文件的cmake目标依赖项,就像上面的库一样 # add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) ## 指定要链接库或可执行目标的库 # target_link_libraries(${PROJECT_NAME}_node # ${catkin_LIBRARIES} # ) ############# ## Install ## ############# # 所有安装目标都应该使用 catkin DESTINATION variables ## 将可执行脚本(Python等)标记为安装,而不是setup.py, 你可以选择目标: # catkin_install_python(PROGRAMS # scripts/my_python_script # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} # ) ## 标记要安装的可执行文件 # install(TARGETS ${PROJECT_NAME}_node # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} # ) ## 用于安装的标记库 # install(TARGETS ${PROJECT_NAME} # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} # RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} # ) ## 标记cpp头文件进行安装 # install(DIRECTORY include/${PROJECT_NAME}/ # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} # FILES_MATCHING PATTERN "*.h" # PATTERN ".svn" EXCLUDE # ) ## 标记其他需要安装的文件(例如launch和bag文件等) # install(FILES # # myfile1 # # myfile2 # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} # ) ############# ## Testing ## ############# ## 添加基于gtest的cpp测试目标和链接库 # catkin_add_gtest(${PROJECT_NAME}-test test/test_orocos_test.cpp) # if(TARGET ${PROJECT_NAME}-test) # target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) # endif() ## 添加要由python nosetests运行的文件夹 # catkin_add_nosetests(test)

    几个重要的编译配置项:

    include_directories:用于设置头文件的相对路径,全局路径默认是功能包的所在目录add_executable:用于设置需要编译的代码和生成的可执行文件target_link_libraries:用于设置链接库,通过该选项可以配置执行文件链接的库文件add_dependencies:用于设置依赖项

    版权声明:本文为博主「阿飞__」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/afei__/article/details/81201039

    Processed: 0.017, SQL: 9