【Cmake】CMakeLists.txt 语法教程

文章目录

常用命令

1. 指定cmake的最小版本

2. 设置项目名称

3. 设置编译类型

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

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

4.2 搜索所有的cpp文件(aux_source_directory)

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…endif

10.2 while…endwhile

10.3 foreach…endforeach

11.打印消息

12.包含其他cmake文件

常用变量

1. 预定义变量

2. 环境变量

3. 系统变量

4.主要开关选项

项目实例

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

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

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_library:生成动态库;STATIC:静态库 SHARED:动态库

add_executable(demo demo.cpp) # 生成可执行文件
add_library(common STATIC util.cpp) # 生成静态库
add_library(common SHARED util.cpp) # 生成动态库或共享库

#add_library(<name> [STATIC | SHARED | MODULE]
#            [EXCLUDE_FROM_ALL]
#            [source1] [source2 ...])
#name:创建的链接库的名称,在项目中必须是全局唯一的。
#STATIC、SHARED或MODULE可以指定要创建的库的类型。 STATIC代表静态链接库。 SHARED代表动态链接库。 MODULE库是未链接到其他目标的插件,但可以使用类似dlopen的功能在运行时动态加载。
#EXCLUDE_FROM_ALL如果给出,将在创建的目标上设置相应的属性。请参阅EXCLUDE_FROM_ALL
#source:创建链接库所依赖的源文件。
  • 在 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)

搜索指定路径下所有的源代码文件,并将列表存储在一个变量中

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

aux_source_directory(utils UTILS_SRC)   #将utils路径下的所有源文件存在UTILS_SRC变量中
aux_source_directory(. SRC_LIST) # 搜索当前目录下的所有.cpp文件,存到SRC_LIST变量中
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)

推荐方式:

list(APPEND MGCHEN_LINK_LIBS PUBLIC opencv_core)   #将opencv_core追加到MGCHEN_LINK_LIBS中
list(APPEND MGCHEN_LINK_LIBS PUBLIC opencv_imgproc)
list(APPEND MGCHEN_LINK_LIBS PUBLIC opencv_imgcodecs)
list(APPEND MGCHEN_LINK_LIBS PUBLIC opencv_highgui)
list(APPEND MGCHEN_LINK_LIBS PUBLIC opencv_ml)
list(APPEND MGCHEN_LINK_LIBS PUBLIC opencv_video)
list(APPEND MGCHEN_LINK_LIBS PUBLIC opencv_videoio)
list(APPEND MGCHEN_LINK_LIBS PUBLIC opencv_calib3d)
list(APPEND MGCHEN_LINK_LIBS PUBLIC CommonOcr)
list(APPEND MGCHEN_LINK_LIBS PUBLIC tengine)

target_link_libraries(mgchen ${MGCHEN_LINK_LIBS})

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追加或删除变量的值

list追加变量的值 APPEND:追加  REMOVE_ITEM:删除

set(SRC_LIST main.cpp)
list(APPEND SRC_LIST test.cpp) #将test.cpp追加到SRC_LIST中
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文件

用处:可以将一些指令放在一个专门.cmake文件中,这样cmakelist文件就会清爽一些,不至于所有指令都堆在一个cmakelist中。

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}/build
  • PROJECT_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重新定义目标链接库文件的存放位置
  • CMAKE_SOURCE_DIR:表示最顶层CMakeLists.txt的文件夹路径

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. 复杂项目(多个目录,多个cmakelist源文件)

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

    cmake_minimum_required (VERSION 2.8)
    project(demo)
    aux_source_directory(. DIR_SRCS)
    # 添加math子目录
    add_subdirectory(math) 
    #add_subdirectory指明本项目包含一个子目录/math,这样子目录下的CMakeLists.txt文件和源代码也会被处理
    
    # 指定生成目标
    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 库。
# option(<variable> "<help_text>" [value])
# variable 是变量名。
# help_text 是描述信息。
# value 是变量初始值,只能是 ON 或 OFF。
# option给变量赋值ON/OFF, 一般作为开关选项来使用
# eg.自定义编译选项
option(OPENGL_VIEW "Enable GLUT OpenGL point cloud view" ON)
if(OPENGL_VIEW)
   1xxxxx
else()
   2xxxxx
endif()

修改 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模板(暂未涉及这方面)

几个重要的编译配置项:

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

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

  • 9
    点赞
  • 95
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值