;
目录结构如下:
可以通过定义宏来控制打印的信息,我们CMakeLists.txt内容如下:
cmake_minimum_required(VERSION 3.10)
project(cmake_study)
# 设置输出bin文件的地址
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
# 设置选项WWW1和WWW2,默认关闭
option(WWW1 "print one message" OFF)
option(WWW2 "print another message" OFF)
if (WWW1)
add_compile_options(-DWWW1)
endif ()
if (WWW2)
add_compile_options(-DWWW2)
endif ()
# 执行源文件
add_executable(main main.c)
cd到build目录下执行cmake .. && make,然后到bin目录下执行./main,可以看到打印为空,
接着分别按照下面指令去执行,然后查看打印效果,
cmake .. -DWWW1=ON -DWWW2=OFF && make
cmake .. -DWWW1=OFF -DWWW2=ON && make
cmake .. -DWWW1=ON -DWWW2=ON && make
这里有个小坑要注意下:假设使用cmake设置了一个option叫A,下次再设置别的option例如B,如果没有删除上次执行cmake时产生的缓存文件,那么这次虽然没设置A,也会默认使用A上次的option值。
所以如果option有变化,要么删除上次执行cmake时产生的缓存文件,要么把所有的option都显式的指定其值。
CMake常用指令
cmake会自动定义两个变量
${PROJECT_SOURCE_DIR} : 当前工程最上层的目录
${PROJECT_BINARY_DIR} :当前工程的构建目录
cmake_minimum_required(VERSION *.**) :定义 cmake 的最低兼容版本。
project(****) :工程名称
set(CMAKE_C_STANDARD 11) :指定C语言标准
set(CMAKE_CXX_STANDARD 11) :指定C++语言标准
include_directories
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
添加路径到头文件的搜索路径
add_subdirectory
add_subdirectory(NAME)
添加一个文件夹进行编译,该文件夹下的 CMakeLists.txt 负责编译该文件夹下的源码。NAME是想对于调用add_subdirectory的CMakeListst.txt的相对路径。
add_executable
add_executable(<name> [WIN32] [MACOSX_BUNDLE]
[EXCLUDE_FROM_ALL]
source1 [source2 ...])
利用源码文件生成目标可执行程序。
name:工程所要构建的目标名称
WIN32/..:目标app运行的平台(可忽略)
source1:构建目标App的源文件
添加Library
现在我们尝试添加一个library到我们的工程。这个lib提供一个自定义的计算平方根的函数,用来替换编译器提供的函数。
lib的源文件放到一个叫MathFunctions的子目录中,在目录下新建CMakeList.txt文件,添加如下的一行
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)
# 生成链接库
add_library (MathFunctions ${DIR_LIB_SRCS})
源文件mysqrt.cxx包含一个函数mysqrt用于计算平方根。代码如下
#include "MathFunctions.h"
#include <stdio.h>
// a hack square root calculation using simple operations
double mysqrt(double x)
if (x <= 0) {
return 0;
double result;
double delta;
result = x;
// do ten iterations
int i;
for (i = 0; i < 10; ++i) {
if (result <= 0) {
result = 0.1;
delta = x - (result * result);
result = result + 0.5 * delta / result;
fprintf(stdout, "Computing sqrt of %g to be %g\n", x, result);
return result;
mysqrt.cxx
还需要添加一个头文件MathFunctions.h以提供接口给main函数调用
double mysqrt(double x);
现在的目录结构
├── build
├── CMakeLists.txt
├── MathFunctions
│ ├── CMakeLists.txt
│ ├── MathFunctions.h
│ └── mysqrt.cxx
├── TutorialConfig.h.in
└── tutorial.cxx
CMakeLists.txt文件需要相应做如下改动
添加一行add_subdirectory来保证新加的library在工程构建过程中被编译。
添加新的头文件搜索路径MathFunction/MathFunctions.h。
添加新的library到executable。
include_directories("${PROJECT_SOURCE_DIR}/MathFunctions")
add_subdirectory(MathFunctions)
# 添加executable
add_executable(Demo main.cxx)
# 使用命令 target_link_libraries 指明可执行文件 main 需要连接一个名为 MathFunctions 的链接库
target_link_libraries(Demo MathFunctions)
add_definitions(-DENABLE_DEBUG -DABC)
向 C/C++编译器添加 -D 定义。如果你的代码中定义了#ifdef ENABLE_DEBUG #endif,这个代码块就会生效。
add_dependencies
add_dependencies(target-name depend-target1 depend-target2 ...)
定义 target 依赖的其他 target,确保在编译本 target 之前,其他的 target 已经被构建。
aux_source_directory
aux_source_directory(dir VARIABLE)
查找dir目录下所有的源码文件,存储在一个变量中。在add_executable的时候就不用一个一个的源码文件添加了,例如:
aux_source_directory(. SRC_LIST)
add_executable(main ${SRC_LIST})
find_package
find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE] [REQUIRED] [[COMPONENTS] [components...]] [OPTIONAL_COMPONENTS components...] [NO_POLICY_SCOPE])
查找并从外部项目加载设置。 <PackageName>_FOUND 将设置为指示是否找到该软件包。 找到软件包后,将通过软件包本身记录的变量和“导入的目标”提供特定于软件包的信息。 该QUIET选项禁用信息性消息,包括那些如果未找到则表示无法找到软件包的消息REQUIRED。REQUIRED如果找不到软件包,该选项将停止处理并显示一条错误消息。
COMPONENTS选件后(或REQUIRED选件后,如果有的话)可能会列出所需组件的特定于包装的列表 。后面可能会列出其他可选组件OPTIONAL_COMPONENTS。可用组件及其对是否认为找到包的影响由目标包定义。
link_libraries
link_libraries([item1 [item2 [...]]] [[debug|optimized|general] <item>] ...)
将库链接到以后添加的所有目标。
add_library
add_library(<name> [STATIC | SHARED | MODULE] [source1] [source2 ...])
根据源码文件生成目标库。
STATIC,SHARED 或者 MODULE 可以指定要创建的库的类型。 STATIC库是链接其他目标时使用的目标文件的存档。 SHARED库是动态链接的,并在运行时加载
enable_testing
enable_testing()
控制 Makefile 是否构建 test 目标,涉及工程所有目录。 一般情况这个指令放在工程的主CMakeLists.txt 中.
add_test
add_test(testname Exename arg1 arg2 ...)
testname 是自定义的 test 名称,Exename 可以是构建的目标文件也可以是外部脚本等等。 后面连接传递给可执行文件的参数。 如果没有在同一个 CMakeLists.txt 中打开ENABLE_TESTING()指令, 任何 ADD_TEST 都是无效的。
exec_program
在 CMakeLists.txt 处理过程中执行命令,并不会在生成的 Makefile 中执行。 具体语法为:
exec_program(Executable [directory in which to run]
[ARGS <arguments to executable>]
[OUTPUT_VARIABLE <var>]
[RETURN_VALUE <var>])
用于在指定的目录运行某个程序,通过 ARGS 添加参数,如果要获取输出和返回值,可通过OUTPUT_VARIABLE 和 RETURN_VALUE 分别定义两个变量.
这个指令可以帮助你在 CMakeLists.txt 处理过程中支持任何命令,比如根据系统情况去修改代码文件等等。
FILE 指令
文件操作指令
FILE(WRITE filename "message to write"... )
FILE(APPEND filename "message to write"... )
FILE(READ filename variable)
FILE(GLOB variable [RELATIVE path] [globbing expression_r_rs]...)
FILE(GLOB_RECURSE variable [RELATIVE path] [globbing expression_r_rs]...)
FILE(REMOVE [directory]...)
FILE(REMOVE_RECURSE [directory]...)
FILE(MAKE_DIRECTORY [directory]...)
FILE(RELATIVE_PATH variable directory file)
FILE(TO_CMAKE_PATH path result)
FILE(TO_NATIVE_PATH path result)
CMake 控制指令
IF 指令
if(<condition>)
<commands>
elseif(<condition>) # optional block, can be repeated
<commands>
else() # optional block
<commands>
endif()
#####
IF(var),如果变量不是:空,0,N, NO, OFF, FALSE, NOTFOUND 或<var>_NOTFOUND 时,表达式为真。
IF(NOT var ),与上述条件相反。
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 dirname),当 dirname 是目录时,为真。
IF(variable MATCHES regex)
IF(string MATCHES regex)
FOREACH 指令
foreach(<loop_var> <items>)
<commands>
endforeach()
其中<items>
是以分号或空格分隔的项目列表。记录foreach匹配和匹配之间的所有命令endforeach而不调用。 一旦endforeach评估,命令的记录列表中的每个项目调用一次<items>
。在每次迭代开始时,变量loop_var将设置为当前项的值。
WHILE 指令
while(<condition>)
<commands>
endwhile()
while和匹配之间的所有命令 endwhile()被记录而不被调用。 一旦endwhile()如果被评估,则只要为<condition>
真,就会调用记录的命令列表。
【CSDN】Linux下CMake简明教程
CMake设置编译选项的几种方法
https://www.jianshu.com/p/6df3857462cd