一、 Cmake介绍

Cmake是一种与平台无关的自动控制项目编译过程的工具(自动生成makefile文档)。只需要配置CMakeList.txt就可以自动的根据平台生成Makefile,方便的跨越多个平台进行编译。

CMakeList.txt注意大小写和s不然识别不成功

Cmake说明文档

cmake是什么?cmake的特性和编译原理(cmake原理和cmake编译过程)

【C++】Cmake使用教程(看这一篇就够了)-CSDN博客

不是已经有了makefile去实现编译控制,为什么还需要Cmake?

Maybe:控制编译的对象范围不同?

Answer:Cmake为了方便的自动生成可以跨平台的makefile,直接写makefile可以实现但是复杂。最重要的,Makefile不像人读的

二、 Cmake的常用语法

一般的,Cmake的编写分为几个部分:初始化、

1. 初始化:

添加cmake版本要求, 添加project名称和版本号

cmake_minimum_required (VERSION 2.8)
project (project_name VERSION 1.0)

2. 设置头文件路径:

指定头文件搜索路径:

include_directories (test_func test_func1)

3. 添加编译选项:

add_compile_options(-std=c++11 -Wall) 

或者使用set设置变量CMAKE_CXX_FLAGSCMAKE_C_FLAGS

set(CMAKE_CXX_FLAGS "-Wall")

4. 编译可执行文件:

4.1 直接编译.c文件

add_executable(main main.c testFunc.c)

4.2 将目录中的所有源文件存在变量中

一般的,Cmake中变量名称使用大写字符表示,${VAR}取出变量的值

aux_source_directory(. SRC_LIST)
add_executable(main ${SRC_LIST})

4.3 设置二进制文件的输出位置:

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

还可以使用SET_TARGET_PROPERTIES设置单个编译对象的输出路径,路径更精细。设置输出路径的颗粒度可以精细到每个编译的对象

5. 编译库文件:

5.1 编译源代码归档成动态库(SHARED)或静态库(STATIC)

add_library (libname SHARED ${SRC_LIST})
add_library (libname STATIC ${SRC_LIST})

5.2 设置最终生成的库的名字

set_target_properties (libname PROPERTIES OUTPUT_NAME "libname ")

5.3 设置库的输出路径

set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

同样可以使用SET_TARGET_PROPERTIES设置输出路径

6. 链接库:

6.1 在路径下查找库并把绝对路径存放在变量中

find_library(LIB_PATH libname HINTS ${PROJECT_SOURCE_DIR}/lib)

6.2 链接目标文件和库文件

target_link_libraries (target_file ${LIB_PATH})

7. 添加编译子目录(可选):

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
  • source_dir 源代码目录 指定一个具有cmakelist和源代码的目录,将其作为编译的子目录

  • binary_dir 二进制代码目录 指定cmake输出的二进制文件所在的目录

  • EXCLUDE_FROM_ALL标记 指定将添加的子目录从make all 中移除

添加编译子目录是为了让源码的编译结构更加清晰,可以更好的使用选项管理编译过程。新的目录路径下建立一个新的CMakeLists。

8. 安装规则(可选):

在编译完成之后,可以使用以下命令将编译好的源文件、头文件、测试用例等资源安装到Cmake指定的位置。

make install

8.1 安装动态库

install(TARGETS mylib
    LIBRARY DESTINATION lib
)

8.2 安装可执行文件

install(TARGETS test_mylib
    RUNTIME DESTINATION bin
)

8.3 安装头文件

install(FILES myheader.h
    DESTINATION include
)

9. 测试(可选)

CMake 提供了内建的测试功能,可以帮助开发者验证项目是否正确构建以及是否通过了各种测试。CMake 的测试功能依赖于 CTest,这是一个 CMake 的测试驱动工具,通常用于执行项目中的单元测试、集成测试等。以下是关于 CMake 测试的主要概念和使用方法。

9.1 启用测试

要启用 CMake 测试功能,首先需要在 CMakeLists.txt 文件中调用 enable_testing()。这将启用 ctest 测试命令。一旦启用测试,您就可以通过 add_test() 命令定义具体的测试。

enable_testing()

9.2 添加测试

使用 add_test() 命令来定义测试。该命令接受两个参数:测试名称和要执行的命令。

add_test(NAME MyTest COMMAND MyExecutable)

这个命令将会添加一个名为 MyTest 的测试,它会运行 MyExecutable 可执行文件。如果 MyExecutable 执行成功,测试将通过。

9.3 测试命令的参数

在 add_test() 命令中,您可以传递多个参数,供测试命令使用。例如,如果您的程序需要一些命令行参数,您可以这样做:

add_test(NAME TestWithArguments COMMAND MyExecutable arg1 arg2)

这样在运行测试时,MyExecutable 将以 arg1 和 arg2 作为参数执行。

9.4 测试期望的返回值

默认情况下,CMake 假定测试程序成功执行时返回 0,如果返回非 0 值,则认为测试失败。如果您的测试需要特定的返回值来表示成功,可以使用 add_test() 的第三个参数指定期望的返回值:

add_test(NAME TestWithExpectedReturnValue COMMAND MyExecutable)
set_tests_properties(TestWithExpectedReturnValue PROPERTIES WILL_FAIL TRUE)

9.5 测试输出

CTest 会捕获测试的标准输出(stdout)和标准错误(stderr)。如果您希望在测试中检查输出内容,可以使用 add_test() 的 –output-on-failure 标志来显示失败的输出。

ctest --output-on-failure

这样,如果测试失败,你将看到每个失败测试的详细输出。

9.6 测试属性

使用 set_tests_properties() 可以设置测试的额外属性。例如,您可以将某个测试标记为“预期失败”(WILL_FAIL),或者设置测试的超时时间(TIMEOUT)等。

set_tests_properties(MyTest PROPERTIES TIMEOUT 30)
set_tests_properties(MyTest PROPERTIES WILL_FAIL TRUE)
  • TIMEOUT:指定测试的超时时间(以秒为单位)。如果测试在此时间内没有结束,将被视为失败。
  • WILL_FAIL:标记该测试为预期失败。

10.Cmake其他操作

10.1 文件操作file

file MAKE_DIRECTORY path/to/directory)

10.2 判断语句 if

10.3 循环语句 foreach

foreach(ITEM ${LIST})
    dosomething
endforeach()

10.4 设置目标属性 SET_TARGET_PROPERTIES

SET_TARGET_PROPERTIES是 CMake 中的一个重要指令,用于设置目标(target)的各种属性,这里的目标可以是库(静态库、动态库),也可以是可执行文件。其基本语法如下:

SET_TARGET_PROPERTIES(target1 target2... PROPERTIES
    property1 value1
    property2 value2
   ...
)

常见属性及用途:

  1. ARCHIVE_OUTPUT_DIRECTORY: 设置静态库的输出目录。例如:

    SET_TARGET_PROPERTIES(mylib PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
    )
    

    这会将名为 mylib 的静态库输出到${CMAKE_BINARY_DIR}/lib目录下。

  2. LIBRARY_OUTPUT_DIRECTORY: 用于指定动态库的输出目录,用法和静态库类似:

    SET_TARGET_PROPERTIES(mylib PROPERTIES
    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
    )
    
  3. RUNTIME_OUTPUT_DIRECTORY: 设定可执行文件的输出目录。比如:

    SET_TARGET_PROPERTIES(myapp PROPERTIES
    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
    )
    
  4. POSITION_INDEPENDENT_CODE: 对于生成动态库或者希望被动态链接的目标很有用,设置为 ON 表示生成位置无关代码(PIC)。这是共享库编译时的常见需求,因为共享库需要能被加载到内存的不同位置,代码必须是位置无关的:

    SET_TARGET_PROPERTIES(mylib PROPERTIES
    POSITION_INDEPENDENT_CODE ON
    )
    
  5. INSTALL_RPATH: 正如前面提到的,和运行时库路径相关,用于设置安装后的可执行文件搜索动态库的路径。”$ORIGIN” 是一个常用值,表示可执行文件所在目录:

    SET_TARGET_PROPERTIES(test_mylib PROPERTIES
    INSTALL_RPATH "$ORIGIN"
    )
    
  6. INTERFACE_INCLUDE_DIRECTORIES: 在创建库时,用于指定库的使用者需要包含的头文件目录,方便其他项目链接该库时能正确找到头文件:

    SET_TARGET_PROPERTIES(mylib PROPERTIES
    INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/include
    )
    

三、Cmake使用

使用cmakelist宏变量和make的命令选项显示make的详细内容

cmake -DCMAKE_VERBOSE_MAKEFILE=ON ..
make VERBOSE=1