1.简介
1.1 CMake编译项目主要是 通过编写CMakeList.txt文件项目的每个子文件夹下分别编写CMakeList.txt,通过CMake工具来根据CMakeList文件生成makefile,最后编译成可执行文件。
1.2 通过CMake可以编译不同版本的vs项目,方便在不同版本的vs之间进行项目的转移,CMake也可以在不同的平台编译项目。
2.基本语法
2.1 指定cmake的最小版本
cmake_minimum_required(VERSION 版本号)
2.2 设置项目的名称
project(项目名称)
//指定项目版本号
project(项目名称 VERSION 版本号)
//配置一个头文件,将版本号传递给源代码
configure_file(xx.h.in xx.h)
//xx.h.in 在源目录中创建一下内容,当 CMake 配置这个头文件时,@xx_VERSION_MAJOR@的值和 @xx_VERSION_MINOR@将被替换。
#define xx_VERSION_MAJOR @xx_VERSION_MAJOR@
#define xx_VERSION_MINOR @xx_VERSION_MINOR@
//在项目中包含上述xx.h配置头文件;
2.3 添加可执行程序
add_executable(可执行程序名称,可执行程序.cpp文件)
2.4 指定C++的标准:通过CMAKE_CXX_STANDARD 和 CMAKE_CXX_STANDARD_REQUIRED来指定;
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
2.5 在源代码的根目录下创建一个build文件夹,将编译的信息全部保存到bulid中,这样方便我们对源码的管理以及二次编译;
2.6 添加编译生成的动态链接库,将动态链接库源文件放在子目录Child下,Child下包含库的头文件childxx.h和childxx.cpp文件。
//添加子文件夹
add_subdirectory(Child)
//连接库文件
target_link_libraries(项目名称 PUBLIC Child)
//添加包含目录,以便找到库的头文件
target_include_directories(项目名称 PUBLIC "${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/Child")
2.7 设置某个库位可选库,在编译大型项目中很常见,在cmake-gui中可以选择性的编译某些库。
option(USE_CHILD "使用Child库" ON)
2.8 设置可选项后,添加库的构建和连接条件。
//USE_CHILD是一个用户定义的变量,使用EXTRA_LIBS变量收集任何可选库,以便链接,EXTRA_INCLUDES 变量用于可选的头文件
if(USE_CHILD)
add_subdirectory(Child)
list(APPEND EXTRA_LIBS Child)
list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/Child")
endif()
对源码的更改,在需要使用库的xx.cpp中,添加如下代码:
#ifdef USE_CHILD
# include "childxx.h"
#endif
对引用系统库函数还是自定义库中的的函数,在源码中可以采用如下方式指定。
//指定使用自定义的sqrt函数,还是库sqrt函数
#ifdef USE_CHILD
const double output = sqrt(input);
#else
const double output = sqrt(input);
#endif
由于源码中需要使用USE_CHILD,因此需要在配置头文件xx.h.in文件中添加。
#cmakedefine USE_CHILD
2.9 库的使用要求
主要命令
- target_compile_definitions()
- target_compile_options()
- target_include_directories()
- target_link_libraries()
在Child子目录下的CMakeList.txt中添加
target_include_directories(CHILD INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
2.10 安装和测试
在Child/CMakeList.txt中添加库和头文件;
install(TARGETS Child DESTINATION lib)
install(FILES Childxx.h DESTINATION include)
在根目录下的CMakeList.txt中添加可执行文件和配置头文件
install(TARGETS 项目名 DESTINATION bin)
install(FILES "${PROJECT_BINARY_DIR}/xxConfig.h" DESTINATION include)
CMake变量 CMAKE_INSTALL_PREFIX用于确定将安装文件的根目录;
在根目录CMakeList.txt文件中,添加一些测试来验证程序是否正常。
enable_testing()
//测试程序是否正常,是否有段错误或其他方式的崩溃,并且返回值为0
add_test(NAME Runs COMMAND 项目名 25)
//PASS_REGULAR_EXPRESSION属性验证测试的输出是否包含某些字符串。在这种情况下,验证在提供的参数数量不正确时打印使用消息。
add_test(NAME Usage COMMAND 项目名)
set_tests_properties(Usage PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number")
//定义一个函数来测试
function(do_test target arg result)
add_test(NAME Comp${arg} COMMAND ${target} ${arg})
set_tests_properties(Comp${arg} PROPERTIES PASS_REGULAR_EXPRESSION ${result})
endfunction(do_test)
//测试
do_test(项目名 参数)
2.11 在不同平台下链接不同的库。
假如Child在相应的模块下,需要使用系统的log,exp函数,如平台没有,则从m库中选择相应的函数。
include(模块名)
check_symbol_exists(log "math.h" HAVE_LOG)
check_symbol_exists(exp "math.h" HAVE_EXP)
if(NOT (HAVE_LOG AND HAVE_EXP))
unset(HAVE_LOG CACHE)
unset(HAVE_EXP CACHE)
set(CMAKE_REQUIRED_LIBRARIES "m")
check_symbol_exists(log "math.h" HAVE_LOG)
check_symbol_exists(exp "math.h" HAVE_EXP)
if(HAVE_LOG AND HAVE_EXP)
target_link_libraries(Child PRIVATE m)
endif()
endif()
如果可用,则使用下面的命令指定HAVE_LOG和HAVE_EXP作为PRIVATE编译定义。
if(HAVE_LOG AND HAVE_EXP)
target_compile_definitions(Child PRIVATE "HAVE_LOG" "HAVE_EXP")
endif()
在需要使用log和exp的源文件中添加如下代码。
#if defined(HAVE_LOG) && defined(HAVE_EXP)
//使用exp,log函数
#else
#enif
2.12 静态库和共享库
通过 BUILD_SHARED_LIBS变量可以用于控制add_library(),允许没有显示类型( STATIC、SHARED、MODULE、OBJECT)的库的构建方式。
在根目录下使用options() 命令添加 BUILD_SHARED_LIBS,可以通过ON或OFF控制。
//添加版cmake本
cmake_minimum_required(VERSION 3.10)
//设置项目版本
project(Tutorial VERSION 1.0)
//添加C++标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
//控制生成共享库
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
//设置变量BUILD_SHARED_LIBS
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
//配置头文件
configure_file(项目名Config.h.in 项目名Config.h)
//添加库目录
add_subdirectory(Child)
//生成可执行程序
add_executable(项目名 项目名.cxx)
target_link_libraries(项目名 PUBLIC Child)
上面已经启用这个库,下面需要在子目录下进行设置Child/CMakeList.txt。