CMake Tutorial Notes
本文是记录学习CMake官方教程时的笔记与注意事项
注意:与本文对应的repository
| GitHub/Gitee | Link |
|---|---|
| GitHub | CMakeOfficialTutorial |
| Gitee | CMakeOfficialTutorial |
前期准备
为了能够在windows平台下使用CMake,以避免可能出现的问题,需要准备以下两项
对于CMake,下载最新版的(当前最新为3.23.2)即可,记得添加cmake的路径到PATH中去。
对于MinGW,需要进入下载页面,不要下载MinGW-W64 Online Installer(太慢),而是选择最新的下载选项(如下)中的x86_64-win32-seh,它是对应windows平台的压缩包。
MinGW-W64 GCC-8.1.0
下载完毕之后,将其中的目录mingw64解压出来,然后把对应的路径加入到环境变量PATH中去,以便在terminal中使用时可以被搜索到。
对于MinGW需要特别注意的是,在其bin目录下面有mingw32-make.exe,但没有make.exe,需要自己单独把mingw32-make.exe复制出来一份并重新命名为make.exe,否则会出现如下的错误
$ cmake ../Step1 -G "Unix Makefiles"
CMake Error: CMake was unable to find a build program corresponding to "Unix Makefiles". CMAKE_MAKE_PROGRAM is not set. You probably need to select a different build tool.
CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage
CMake Error: CMAKE_CXX_COMPILER not set, after EnableLanguage
-- Configuring incomplete, errors occurred!
See also "F:/Pyrad/CMakeLearning/CMakeTutorialLearning/Step1_build/CMakeFiles/CMakeOutput.log".
(可能的原因是CMake查找的是make而不是mingw32-make.exe,哪怕mingw32-make.exe已经在PATH中了)
此外,需要在CMakeLists.txt中指明需要使用mingw64对应的toolchain来编译,
SET(MY_MINGW64_HOME "D:/procs/mingw64")
SET(CMAKE_MAKE_PROGRAM "${MY_MINGW64_HOME}/bin/mingw32-make.exe")
SET(CMAKE_C_COMPILER "${MY_MINGW64_HOME}/bin/gcc.exe")
SET(CMAKE_CXX_COMPILER "${MY_MINGW64_HOME}/bin/g++.exe")
并且,在cmake编译时使用如下option
cmake <SRC_DIR> -G "Unix Makefiles"
否则在windows平台下,系统可能会按照VS的toolchain生成project文件,而不是像Linux下一样生成Makefile文件。
Step 1 基本
教程第一节
简述
本节介绍了一个简单的例子,只有一个cpp文件(以及稍后引入的通过cmake创建的一个头文件),通过引入一个简单的CMakeLists.txt来说明了如何编译这个简单的cpp源文件。
新的语法和命令
| functions | functions |
|---|---|
CMAKE_MINIMUM_REQUIRED() |
PROJECT() |
ADD_EXECUTABLE() |
CONFIGURE_FILE() |
SET() |
MESSAGE() |
TARGET_INCLUDE_DIRECTORIES() |
| variables | variables |
|---|---|
CMAKE_CXX_STANDARD |
CMAKE_CXX_STANDARD_REQUIRED |
CMAKE_MAKE_PROGRAM |
CMAKE_C_COMPILER |
CMAKE_CXX_COMPILER |
PROJECT_BINARY_DIR |
PROJECT_SOURCE_DIR |
关于CMakeLists.txt中基本语法(synopsis)的几点说明
关键字大小写不敏感(但最好统一用大写或小写)
变量是大小写敏感的
这里的CMakeLists.txt文件的内容:
CMAKE_MINIMUM_REQUIRED(VERSION 3.10)
# Set the project name
PROJECT(Tutorial VERSION 1.0)
# specify the C++ standard
SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_CXX_STANDARD_REQUIRED True)
MESSAGE(STATUS "[PYRAD] This is the BINARY directory: " ${Tutorial_BINARY_DIR})
MESSAGE(STATUS "[PYRAD] This is the SOURCE directory: " ${Tutorial_SOURCE_DIR})
# Add the executable
ADD_EXECUTABLE(Tutorial tutorial.cxx)
# If you'd like to build in a Unix way in windows platform,
# add the following
SET(MY_MINGW64_HOME "D:/procs/mingw64")
SET(CMAKE_MAKE_PROGRAM "${MY_MINGW64_HOME}/bin/mingw32-make.exe")
SET(CMAKE_C_COMPILER "${MY_MINGW64_HOME}/bin/gcc.exe")
SET(CMAKE_CXX_COMPILER "${MY_MINGW64_HOME}/bin/g++.exe")
CONFIGURE_FILE(TutorialConfig.h.in TutorialConfig.h)
TARGET_INCLUDE_DIRECTORIES(Tutorial PUBLIC "${PROJECT_BINARY_DIR}" )
使用cmake进行编译
命令为
$ mkdir Step1_build
$ cd ./Step1_build
$ cmake ../Step1 -G "Unix Makefiles"
$ cmake --build .
在windows平台下显示了信息如下:
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step1_build (master)
$ cmake ../Step1 -G "Unix Makefiles"
-- The C compiler identification is GNU 8.1.0
-- The CXX compiler identification is GNU 8.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/procs/mingw64/bin/gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/procs/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- [PYRAD] This is the BINARY directory: D:/Gitee/CMakeOfficialTutorial/Step1_build
-- [PYRAD] This is the SOURCE directory: D:/Gitee/CMakeOfficialTutorial/Step1
-- Configuring done
-- Generating done
-- Build files have been written to: D:/Gitee/CMakeOfficialTutorial/Step1_build
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step1_build (master)
$ cmake --build .
[ 50%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.obj
[100%] Linking CXX executable Tutorial.exe
[100%] Built target Tutorial
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step1_build (master)
$ ls
cmake_install.cmake CMakeCache.txt CMakeFiles/ Makefile Tutorial.exe* TutorialConfig.h
编译完毕之后,可以在编译目录(当前是Step1_build)里面执行如下命令,得到如下结果
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step1_build (master)
$ ./Tutorial.exe 4294967296
The square root of 4.29497e+09 is 65536
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step1_build (master)
$ ./Tutorial.exe 10
The square root of 10 is 3.16228
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step1_build (master)
$ ./Tutorial.exe
D:\Gitee\CMakeOfficialTutorial\Step1_build\Tutorial.exe Version 1.0
Usage: D:\Gitee\CMakeOfficialTutorial\Step1_build\Tutorial.exe number
PROJECT 关键字
其中PROJECT关键字指明工程名字,后面可以跟上所支持的语言(默认支持所有语言)。
PROJECT(Tutorial) # 指定工程名为Tutorial
PROJECT(Tutorial CXX) # 指定工程名为Tutorial,支持语言为C++
PROJECT(Tutorial C CXX) # 指定工程名为Tutorial,支持语言为C和C++
PROJECT(Tutorial VERSION 1.0) # 指定工程名为Tutorial,并且设定版本号为1.0
其中,这个声明同时也隐式定义了两个CMake变量,分别是
${PROJECT_NAME}_BINARY_DIR这个变量指明了存放一些binary等可执行文件的目录。比如在该项目里这个变量就会在cmake执行时被替换为
Tutorial_BINARY_DIR。${PROJECT_NAME}_SOURCE_DIR这个变量指明了存放源文件的目录。比如在该项目里这个变量就会在cmake执行时被替换为
Tutorial_SOURCE_DIR。
这两个隐式生成的CMake变量,会由于工程名的变化而产生变化,为了防止其发生变化,CMake还提供了两个预定义的变量,可以单独对其进行命名,防止因为工程名称发生变化而变化。
SET 关键字
SET关键字用来指定变量,如果后面跟一个列表,需要用空格隔开(如果文件名中有空格,那么该文件名就需要用双引号括起来)
SET(SRC_LIST main.cpp) # 声明了变量SRC_LIST
SET(SRC_LIST main.cpp t.cpp t2.cpp) # 声明了变量SRC_LIST
其中文件名可以带上后缀,也可以不带后缀,但是最好带上后缀,防止有歧义的情况发生(比如同时存在两个文件main.cpp和main)。
MESSAGE 关键字
这个关键字向终端输出用户的自定义的信息,包括三种
SEND_ERROR产生错误,跳过生成过程
STATUS输出信息,前缀是
--FATAL_ERROR立即终止所有的
cmake过程
在本例中,输出了两条信息,
# 变量${Tutorial_BINARY_DIR}是由cmake通过PROJECT所设定的名字自动赋值得到的
MESSAGE(STATUS "[PYRAD] This is the BINARY directory: " ${Tutorial_BINARY_DIR})
# 变量${Tutorial_SOURCE_DIR}也是由cmake通过PROJECT所设定的名字自动赋值得到的
MESSAGE(STATUS "[PYRAD] This is the SOURCE directory: " ${Tutorial_SOURCE_DIR})
Step2 添加库
教程第二节
Adding A Library 添加一个库
新的命令和语法
| functions | functions | functions |
|---|---|---|
add_library() |
add_subdirectory() |
target_link_libraries() |
option() |
configure_file() |
list() |
add_executable() |
target_include_directories() |
指令
| instructions | instructions |
|---|---|
if/endif |
|
初始目录结构
Step2/
│───CMakeLists.txt
│───tutorial.cxx
│───TutorialConfig.h.in
│
└───MathFunctions/
│───MathFunctions.h
└───mysqrt.cxx
修改的部分
首先需要在Step2/CMakeLists.txt这个顶层的文件里面,添加如下的修改(这里不包含原有的部分)
# PART 1
# If you'd like to build in a Unix way in windows platform,
# add the following
SET(MY_MINGW64_HOME "D:/procs/mingw64")
SET(CMAKE_MAKE_PROGRAM "${MY_MINGW64_HOME}/bin/mingw32-make.exe")
SET(CMAKE_C_COMPILER "${MY_MINGW64_HOME}/bin/gcc.exe")
SET(CMAKE_CXX_COMPILER "${MY_MINGW64_HOME}/bin/g++.exe")
# PART 2
option(USE_MYMATH "Use tutorial provided math implementation" ON)
if(USE_MYMATH)
# Add the MathFunctions library
add_subdirectory(MathFunctions)
list(APPEND EXTRA_LIBS MathFunctions)
list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
endif()
# PART 3
# add the executable
add_executable(Tutorial tutorial.cxx MathFunctions/mysqrt.cxx)
# PART 4
target_link_directories(Tutorial PUBLIC ${EXTRA_LIBS})
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
"${EXTRA_INCLUDES}"
)
上面修改中:
第一部分:仍然是指定在windows平台下的gcc/g++编译
第二部分:设定了一个CMake的宏
USE_MYMATH,以便可以在cmake编译期间打开或关闭。然后根据这个宏,通过命令
add_subdirectory添加一个lib的目录(MathFunctions),以便cmake可以得知我们的lib源文件的目录同时,还定义了两个cmake中的list变量:
EXTRA_LIBS和EXTRA_INCLUDES,第三部分:通过
add_executable告诉cmake最终编译得到的二进制文件Tutorial需要从源文件tutorial.cxx和lib库的源文件MathFunctions/mysqrt.cxx。(注意,这里在网页上忘记写了后者,会导致最后链接错误)第四部分:首先通过
target_link_directories告诉了linker需要去搜索lib文件(比如这里的MathFunctions.a)的路径,它所指定的二进制名Tutorial,必须是在之前已经通过add_executable活着add_library已经定义。其次通过
target_include_directories定义了在编译期间compiler需要去搜索的目录,以便找到所需的头文件。
在TutorialConfig.h.in文件中,添加如下指令
#cmakedefine USE_MYMATH
这个指令的目的,主要是定义一个可以在cmake期间灵活修改(打开/关闭)的宏,以方便使用。
实际上,USE_MYMATH这个宏在两个地方被定了,
第一个地方:top-level的
CMakeLists.txt中,使用CMake的option()这个函数定义了USE_MYMATH这个宏,并赋予其初始值,这个地方是USE_MYMATH这个宏真正被定义的地方,而且是通过CMake来定义的第二个地方:文件
TutorialConfig.h.in这个文件中。这个地方里面使用了CMake的指令#cmakedefine来定义USE_MYMATH这个宏,但它在cmake编译期间会被cmake做自动替换,替换为真正的C/C++的预编译指令:#define USE_MYMATH 0或#define USE_MYMATH 1而由于
USE_MYMATH这个宏是cmake定义的,所以在cmake期间,可以通过command line option来改变这个宏的值(ON/OFF),而随着改变的,是TutorialConfig.h.in这个文件根据cmake的编译指令而生成的文件中真正的C/C++的预编译指令所定义的USE_MYMATH这个宏值。比如,打开这个编译选项,使用
cmake ../Step2 -G Unix Makefiles" -DUSE_MYMATH=ON(或者直接用cmake ../Step2 -G Unix Makefiles",因为USE_MYMATH的默认值是ON),那么通过TutorialConfig.h.in这个文件生成的头文件TutorialConfig.h中,预编译指令就是:#define USE_MYMATH 1。如果关闭这个编译选项,使用
cmake ../Step2 -G Unix Makefiles" -DUSE_MYMATH=OFF,那么通过TutorialConfig.h.in这个文件生成的头文件TutorialConfig.h中,预编译指令就是:#define USE_MYMATH 0,总之,就是cmake会根据option中定义的宏,在根据编译时的command liine option是否打开,自动替换#cmakedefine USE_MYMATH成正确的真正的C/C++的预编译指令。
在tutorial.cxx源文件的中,修改的部分如下,
// PART 1
#ifdef USE_MYMATH
#include "MathFunctions.h"
#endif // USE_MYMATH
int main(int argc, char* argv[])
{
// ... ...
// PART 2
// calculate square root
#ifdef USE_MYMATH
const double outputValue = mysqrt(inputValue);
#else
const double outputValue = sqrt(inputValue);
#endif // USE_MYMATH
// ... ...
return 0;
}
上面修改的,
第一部分:是根据宏USE_MYMATH来决定是否添加头文件MathFunctions.h
第二部分:是根据宏USE_MYMATH来决定是否使用标准库中的函数sqrt还是我们这里自定义的库中的函数mysqrt
修改之后
添加并修改文件完毕之后,目录结构如下
STEP2/
│───CMakeLists.txt*
│───tutorial.cxx*
│───TutorialConfig.h.in*
│
└───MathFunctions/
│───CMakeLists.txt* (Newly added)
│───MathFunctions.h
└───mysqrt.cxx
打开USE_MYMATH编译
编译(打开USE_MYMATH宏)
cmake ../Step2 -G "Unix Makefiles"
cmake --build .
输出结果
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step2_build (master)
$ cmake ../Step2 -G "Unix Makefiles"
-- The C compiler identification is GNU 8.1.0
-- The CXX compiler identification is GNU 8.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/procs/mingw64/bin/gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/procs/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: D:/Gitee/CMakeOfficialTutorial/Step2_build
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step2_build (master)
$ cmake --build .
[ 20%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.obj
[ 40%] Building CXX object CMakeFiles/Tutorial.dir/MathFunctions/mysqrt.cxx.obj
[ 60%] Linking CXX executable Tutorial.exe
[ 60%] Built target Tutorial
[ 80%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.cxx.obj
[100%] Linking CXX static library libMathFunctions.a
[100%] Built target MathFunctions
执行编译后的二进制文件,得到如下输出,可以看到,使用的是我们自定义库中的mysqrt函数。
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step2_build (master)
$ ./Tutorial.exe 4294967296
Computing sqrt of 4.29497e+09 to be 2.14748e+09
Computing sqrt of 4.29497e+09 to be 1.07374e+09
Computing sqrt of 4.29497e+09 to be 5.36871e+08
Computing sqrt of 4.29497e+09 to be 2.68435e+08
Computing sqrt of 4.29497e+09 to be 1.34218e+08
Computing sqrt of 4.29497e+09 to be 6.71089e+07
Computing sqrt of 4.29497e+09 to be 3.35545e+07
Computing sqrt of 4.29497e+09 to be 1.67773e+07
Computing sqrt of 4.29497e+09 to be 8.38878e+06
Computing sqrt of 4.29497e+09 to be 4.19465e+06
The square root of 4.29497e+09 is 4.19465e+06
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step2_build (master)
$ ./Tutorial.exe 10
Computing sqrt of 10 to be 5.5
Computing sqrt of 10 to be 3.65909
Computing sqrt of 10 to be 3.19601
Computing sqrt of 10 to be 3.16246
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
The square root of 10 is 3.16228
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step2_build (master)
$ ./Tutorial.exe
D:\Gitee\CMakeOfficialTutorial\Step2_build\Tutorial.exe Version 1.0
Usage: D:\Gitee\CMakeOfficialTutorial\Step2_build\Tutorial.exe number
关闭USE_MYMATH编译
使用如下命令,在关闭自定义的宏USE_MYMATH之后编译
cmake ../Step2 -G "Unix Makefiles" -DUSE_MYMATH=OFF
cmake --build .
编译输出(这里偷懒了,没有rm -rf ./*,就让cmake增量编译吧)
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step2_build (master)
$ cmake ../Step2 -G "Unix Makefiles" -DUSE_MYMATH=OFF
-- Configuring done
-- Generating done
-- Build files have been written to: D:/Gitee/CMakeOfficialTutorial/Step2_build
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step2_build (master)
$ cmake --build .
Consolidate compiler generated dependencies of target Tutorial
[ 33%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.obj
[ 66%] Building CXX object CMakeFiles/Tutorial.dir/MathFunctions/mysqrt.cxx.obj
[100%] Linking CXX executable Tutorial.exe
[100%] Built target Tutorial
执行编译后的二进制文件,得到如下输出,可以看到,使用的是标准库中的sqrt函数。
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step2_build (master)
$ ./Tutorial.exe 4294967296
The square root of 4.29497e+09 is 65536
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step2_build (master)
$ ./Tutorial.exe 10
The square root of 10 is 3.16228
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step2_build (master)
$ ./Tutorial.exe
D:\Gitee\CMakeOfficialTutorial\Step2_build\Tutorial.exe Version 1.0
Usage: D:\Gitee\CMakeOfficialTutorial\Step2_build\Tutorial.exe number
Step3 添加库优化
教程第三节
新的语法和命令
| commands | commands |
|---|---|
target_compile_definitions() |
target_compile_options() |
target_include_directories() |
target_link_libraries() |
| variables | variables |
|---|---|
INTERFACE |
CMAKE_CURRENT_SOURCE_DIR |
本节主要讲述了,如何在一个库(lib)目录里面的CMakeLists.txt里面通过添加如下语句,使得当该库(lib)目录在被使用时(即被link时),由cmake自动include当前库的源文件目录。这样,在主目录下面的CMakeLists.txt里面就不用再显式地include这个库(lib)的目录以便查找其头文件。(但还是要在top-level的CMakeLists.txt里面显示地通过target_link_libraries来指明需要链接的目录)
target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)
改动一
在MathFunctions/CMakeLists.txt中,添加如下指令
# Remember INTERFACE means things that consumers
# require but the producer doesn't.
# State that anybody linking to us needs to include the current source dir
# to find MathFunctions.h, while we don't.
target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)
改动二
在主目录的CMakeLists.txt中,把如下指令
# add the MathFunctions library
if(USE_MYMATH)
add_subdirectory(MathFunctions)
list(APPEND EXTRA_LIBS MathFunctions)
list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
endif()
修改为
# add the MathFunctions library
if(USE_MYMATH)
add_subdirectory(MathFunctions)
list(APPEND EXTRA_LIBS MathFunctions)
endif()
即,删除list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")。
对应的,还是在主目录的CMakeLists.txt中,把如下指令
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
${EXTRA_INCLUDES}
)
修改为
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
)
也就是说,cmake会自动查找需要的库的源文件目录,而不用再在主目录的CMakeLists.txt中显式指明。
编译结果
同样地,使用如下两条命令进行编译
cmake ../Step3 -G "Unix Makefiles"
cmake --build .
结果
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step3_build (master)
$ cmake ../Step3 -G "Unix Makefiles"
-- The C compiler identification is GNU 8.1.0
-- The CXX compiler identification is GNU 8.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/procs/mingw64/bin/gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/procs/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: D:/Gitee/CMakeOfficialTutorial/Step3_build
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step3_build (master)
$ cmake --build .
[ 25%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.cxx.obj
[ 50%] Linking CXX static library libMathFunctions.a
[ 50%] Built target MathFunctions
[ 75%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.obj
[100%] Linking CXX executable Tutorial.exe
[100%] Built target Tutorial
Step4 安装和测试
教程第四节
本节主要讲述了如何设置install目录,以便编译完成之后,把对应的二进制文件、头文件以及库文件拷贝到设定好的目录中去。(The install rules are fairly simple: for MathFunctions we want to install the library and header file and for the application we want to install the executable and configured header.)
新的语法和命令
| commands | variables |
|---|---|
install() |
CMAKE_INSTALL_PREFIX |
改动一
在主目录的CMakeLists.txt中,添加如下的指令
install(TARGETS Tutorial DESTINATION bin)
install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
DESTINATION include
)
这样是说明
把二进制文件
Tutorial拷贝到install目录下的bin目录中去把头文件
TutorialConfig.h拷贝到install目录下的include目录中去
需要说明的是,如果在CMakeLists.txt中没有指明变量CMAKE_INSTALL_PREFIX,那么这个变量的默认值在windows平台是C:/Program Files(x86)/${PROJECT_NAME},在linux平台是/usr/local。
所以这两条指令实际上是说
把二进制文件
Tutorial拷贝到C:/Program Files(x86)/Tutorial/bin目录里去把头文件
TutorialConfig.h拷贝到C:/Program Files(x86)/Tutorial/include目录里去去
那么在这里就会有权限的问题,如果后面使用make --install .就会出现没有权限拷贝的问题,所以为了避免该问题,需要在CMakeLists.txt中设定合适的CMAKE_INSTALL_PREFIX
# Set install path
set(MY_INSTALL_DIR "MyInstallPath")
set(CMAKE_INSTALL_PREFIX "${PROJECT_BINARY_DIR}/${MY_INSTALL_DIR}")
install(TARGETS Tutorial DESTINATION bin)
install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
DESTINATION include
)
或者,另一种办法是在cmake --install .时,添加--prefix <prefix_to_path>来覆盖CMAKE_INSTALL_PREFIX变量的值。
改动二
在MathFunctions/CMakeLists.txt中,添加如下指令
install(TARGETS MathFunctions DESTINATION lib)
install(FILES MathFunctions.h DESTINATION include)
同样地,根据前面改动一中的说明,这两条指令实际上是说
把库文件
libMathFunctions.a拷贝到install目录下的lib目录中去把头文件
MathFunctions.h拷贝到install目录下的include目录中去
编译和安装
使用如下的三条命令来编译和安装
同样地,使用如下两条命令进行编译
cmake ../Step4 -G "Unix Makefiles"
cmake --build .
cmake --install .
结果
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step4_build (master)
$ cmake ../Step4 -G "Unix Makefiles"
-- The C compiler identification is GNU 8.1.0
-- The CXX compiler identification is GNU 8.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/procs/mingw64/bin/gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/procs/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: D:/Gitee/CMakeOfficialTutorial/Step4_build
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step4_build (master)
$ cmake --build .
[ 25%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.cxx.obj
[ 50%] Linking CXX static library libMathFunctions.a
[ 50%] Built target MathFunctions
[ 75%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.obj
[100%] Linking CXX executable Tutorial.exe
[100%] Built target Tutorial
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step4_build (master)
$ cmake --install .
-- Install configuration: ""
-- Installing: D:/Gitee/CMakeOfficialTutorial/Step4_build/MyInstallPath/bin/Tutorial.exe
-- Installing: D:/Gitee/CMakeOfficialTutorial/Step4_build/MyInstallPath/include/TutorialConfig.h
-- Installing: D:/Gitee/CMakeOfficialTutorial/Step4_build/MyInstallPath/lib/libMathFunctions.a
-- Installing: D:/Gitee/CMakeOfficialTutorial/Step4_build/MyInstallPath/include/MathFunctions.h
注意,如果需要在cmake的时候手动指明install path,就用如下指令
cmake ../Step4 -G "Unix Makefiles"
cmake --build .
cmake --install . --prefix /my/install/prefix
编译安装结果
在编译和安装结束之后,这里CMakeLists.txt中指明的目录MyInstallPath目录的tree结构如下
MyInstallPath/
├───bin/
│ Tutorial.exe
│
├───include/
│ MathFunctions.h
│ TutorialConfig.h
│
└───lib/
libMathFunctions.a
添加测试支持
在top-level的CMakeLists.txt中添加如下的testing support
enable_testing()
# PART 1
# does the application run
add_test(NAME Runs COMMAND Tutorial 25)
# does the usage message work?
add_test(NAME Usage COMMAND Tutorial)
set_tests_properties(Usage
PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
)
# PART 2
# define a function to simplify adding tests
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 a bunch of result based tests
do_test(Tutorial 4 "4 is 2")
do_test(Tutorial 9 "9 is 3")
do_test(Tutorial 5 "5 is 2.236")
do_test(Tutorial 7 "7 is 2.645")
do_test(Tutorial 25 "25 is 5")
do_test(Tutorial -25 "-25 is (-nan|nan|0)")
do_test(Tutorial 0.0001 "0.0001 is 0.01")
第一部分使用了
cmake的add_test和set_tests_properties来做简单测试第二部分定义了一个定制化的函数,并用来测试
如何运行测试
不要切换到install目录下面去,而是要到编译目录下面去(因为有文件CTestTestfile.cmake才行,否则ctest找不到test)。
使用如下命令测试
ctest -N
ctest -VV
结果
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step4_build (master)
$ ls
cmake_install.cmake CMakeFiles/
install_manifest.txt MathFunctions/ Tutorial.exe*
CMakeCache.txt CTestTestfile.cmake Makefile
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step4_build (master)
$ ctest.exe -N
Test project D:/Gitee/CMakeOfficialTutorial/Step4_build
Test #1: Runs
Test #2: Usage
Test #3: Comp4
Test #4: Comp9
Test #5: Comp5
Test #6: Comp7
Test #7: Comp25
Test #8: Comp-25
Test #9: Comp0.0001
Total Tests: 9
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step4_build (master)
$ ctest.exe -VV
UpdateCTestConfiguration from :D:/Gitee/CMakeOfficialTutorial/Step4_build/DartConfiguration.tcl
UpdateCTestConfiguration from :D:/Gitee/CMakeOfficialTutorial/Step4_build/DartConfiguration.tcl
Test project D:/Gitee/CMakeOfficialTutorial/Step4_build
Constructing a list of tests
Done constructing a list of tests
Updating test list for fixtures
Added 0 tests to meet fixture requirements
Checking test dependency graph...
Checking test dependency graph end
test 1
Start 1: Runs
1: Test command: D:\Gitee\CMakeOfficialTutorial\Step4_build\Tutorial.exe "25"
1: Test timeout computed to be: 10000000
1: Computing sqrt of 25 to be 13
... ...
... ...
9: Computing sqrt of 0.0001 to be 0.01
9: The square root of 0.0001 is 0.01
9/9 Test #9: Comp0.0001 ....................... Passed 0.07 sec
100% tests passed, 0 tests failed out of 9
Total Test time (real) = 1.15 sec
Step5 系统自省(System Introspection)
教程第五节
本节主要讲述了如何通过cmake指令来查找系统平台是否提供了所预期的函数,并根据检查结果进行(条件选择)编译。
新的语法和命令
| commands | commands |
|---|---|
include() |
check_symbol_exists() |
unset() |
target_compile_definitions() |
改动一
在MathFunctions/CMakeLists.txt中,添加如下指令
# PART 1
# does this system provide the log and exp functions?
include(CheckSymbolExists)
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(MathFunctions PRIVATE m)
endif()
endif()
# PART 2
if(HAVE_LOG AND HAVE_EXP)
target_compile_definitions(MathFunctions
PRIVATE "HAVE_LOG" "HAVE_EXP")
endif()
有两部分
第一部分(PART 1)
通过
include(CheckSymbolExists)引入宏CheckSymbolExists,用来检查一个Symbol是否存在检查系统中(platform头文件)是否存在
log和exp这两个函数,把检查结果分别存入两个变量HAVE_LOG以及HAVE_EXP如果没有,就说明有可能现在是其他的一些platform,再次做检查
第二部分(PART 2)
如果前面设置的两个变量
HAVE_LOG以及HAVE_EXP都是True,那么就设定两个在源代码中可以使用的宏,名字叫HAVE_LOG以及HAVE_EXP
改动二
在MathFunctions/mysqrt.cxxt中,修改代码如下
把如下这行代码
double result = x;
修改为
#if defined(HAVE_LOG) && defined(HAVE_EXP)
double result = exp(log(x) * 0.5);
std::cout << "Computing sqrt of " << x << " to be " << result
<< " using log and exp" << std::endl;
#else
double result = x;
#endif
可以看到,这里在源代码中检查了宏HAVE_LOG以及HAVE_EXP,这两个宏是在CMake期间定义的。
同时也要加上#include <cmath>这一行。
编译和安装
同样地,使用如下的三条命令来编译和安装
cmake ../Step5 -G "Unix Makefiles"
cmake --build .
cmake --install . --prefix /my/install/prefix
结果
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step5_build (master)
$ cmake ../Step5 -G "Unix Makefiles"
-- The C compiler identification is GNU 8.1.0
-- The CXX compiler identification is GNU 8.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/procs/mingw64/bin/gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/procs/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Looking for log
-- Looking for log - found
-- Looking for exp
-- Looking for exp - found
-- Configuring done
-- Generating done
-- Build files have been written to: D:/Gitee/CMakeOfficialTutorial/Step5_build
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step5_build (master)
$ cmake --build .
[ 25%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.cxx.obj
[ 50%] Linking CXX static library libMathFunctions.a
[ 50%] Built target MathFunctions
[ 75%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.obj
[100%] Linking CXX executable Tutorial.exe
[100%] Built target Tutorial
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step5_build (master)
$ cmake --install .
-- Install configuration: ""
-- Installing: D:/Gitee/CMakeOfficialTutorial/Step5_build/MyInstallPath/bin/Tutorial.exe
-- Installing: D:/Gitee/CMakeOfficialTutorial/Step5_build/MyInstallPath/include/TutorialConfig.h
-- Installing: D:/Gitee/CMakeOfficialTutorial/Step5_build/MyInstallPath/lib/libMathFunctions.a
-- Installing: D:/Gitee/CMakeOfficialTutorial/Step5_build/MyInstallPath/include/MathFunctions.h
需要注意的是,cmake ../Step4 -G "Unix Makefiles"时有打印如下信息,
-- Looking for log
-- Looking for log - found
-- Looking for exp
-- Looking for exp - found
这表示,按照我们在CMakeLists.txt中的定义,在查找当前平台对应的log和exp函数(并且找到了)。
Step6 添加自定义命令和生成文件
教程第六节
简述
本节主要讲述了
通过cmake的语法,如何生成一个头文件,使得其他源文件可以引用该头文件
该头文件不是手动写的,而是在cmake编译期间生成的,不在源代码的目录内(当然源代码的目录里有如何生成这个头文件的源代码)
具体地,本节是通过一个源代码文件(C++),生成一个头文件,该头文件里面是一个数组,表示的是10以内的数的平方根的结果,然后由MathFunctions/mysqrt.cxx引用它,以便在计算0以内的数的平方根的时候,直接查询该数组得出结果。
新的语法和命令
| commands | variables |
|---|---|
add_custom_command() |
CMAKE_CURRENT_BINARY_DIR |
CMAKE_CURRENT_BINARY_DIR是当前cmake编译的目录(full path)
add_custom_command()这个command相当于在Makefile中的一条生成-依赖指令,目的是通过定义的一条command来生成一个output,比如教程中的
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
DEPENDS MakeTable
)
它相当于是Makefile中的
OUTPUT: DEPENDS
COMMAND
具体地是
${CMAKE_CURRENT_BINARY_DIR}/Table.h: MakeTable
MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
也就是说,根据MakeTable这个依赖,会生成一个对应的Table.h头文件(target)。
改动一
首先删除了上一节中关于HAVE_LOG和HAVE_EXP的宏的创建、检查和引用的代码部分。
改动二
其次,在MathFunctions/CMakeLists.txt中,添加如下两条指令
add_executable(MakeTable MakeTable.cxx)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
DEPENDS MakeTable
)
第一条是说,要通过MakeTable.cxx生成一个二进制文件(用来运行产生Table.h这个文件)
第二条相当于定义了一条规则,要生成一个Table.h这个target,它的依赖是MakeTable这个二进制文件。
改动三
再次,在MathFunctions/CMakeLists.txt中,修改如下两条指令
add_library(MathFunctions
mysqrt.cxx
${CMAKE_CURRENT_BINARY_DIR}/Table.h
)
target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
)
第一条指令是指mysqrt.cxx文件在生成MathFunctions这个lib是时候,实际上依赖于我们的生成文件Table.h的。
第二条指令是把cmake当前编译的目录加入到头文件的包含的目录列表中去,以便mysqrt.cxx中include这个生成的头文件时,可以找到它。
改动四
最后,需要修改MathFunctions/mysqrt.cxx中源代码,见下,需要注意的是,官网上的代码似乎有错,这里做了修复。
#include <iostream>
#include "MathFunctions.h"
// A generated header file by cmake
#include "Table.h"
// a hack square root calculation using simple operations
double mysqrt(double x) {
if (x <= 0) { return 0; }
// Use the table to help find an initial value
// Note that varialbe sqrtTable is defined in a generated
// header file "Table.h"
double result = x;
if (x >= 1 && x < 10) {
std::cout << "Use the table to help find an initial value " << std::endl;
result = sqrtTable[static_cast<int>(x)];
std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
return result;
}
// do ten iterations
for (int i = 0; i < 10; ++i) {
if (result <= 0) { result = 0.1; }
double delta = x - (result * result);
result = result + 0.5 * delta / result;
std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
}
return result;
}
实际上,生成文件Table.h的内容如下,
double sqrtTable[] = {
0,
1,
1.41421,
1.73205,
2,
2.23607,
2.44949,
2.64575,
2.82843,
3,
0};
它就是是一个数组,表示的是10以内的数的平方根的结果,然后由MathFunctions/mysqrt.cxx引用它,
编译和安装
同样地,使用如下的三条命令来编译和安装
cmake ../Step6 -G "Unix Makefiles"
cmake --build .
cmake --install . --prefix /my/install/prefix
结果
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step6_build (master)
$ cmake ../Step6 -G "Unix Makefiles"
-- The C compiler identification is GNU 8.1.0
-- The CXX compiler identification is GNU 8.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/procs/mingw64/bin/gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/procs/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: D:/Gitee/CMakeOfficialTutorial/Step6_build
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step6_build (master)
$ cmake --build .
[ 14%] Building CXX object MathFunctions/CMakeFiles/MakeTable.dir/MakeTable.cxx.obj
[ 28%] Linking CXX executable MakeTable.exe
[ 28%] Built target MakeTable
[ 42%] Generating Table.h
[ 57%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.cxx.obj
[ 71%] Linking CXX static library libMathFunctions.a
[ 71%] Built target MathFunctions
[ 85%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.obj
[100%] Linking CXX executable Tutorial.exe
[100%] Built target Tutorial
注意,在cmake --build .时,有明显的信息说明生成了生成文件Table.h,如下
[ 28%] Built target MakeTable
[ 42%] Generating Table.h
最后,测试生成的二进制文件,发现在计算10以内的平方根时,确实使用了查表的方法,故结果正确。
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step6_build (master)
$ ./Tutorial.exe 2
Use the table to help find an initial value
Computing sqrt of 2 to be 1.41421
The square root of 2 is 1.41421
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step6_build (master)
$ ./Tutorial.exe 10
Computing sqrt of 10 to be 5.5
Computing sqrt of 10 to be 3.65909
Computing sqrt of 10 to be 3.19601
Computing sqrt of 10 to be 3.16246
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
The square root of 10 is 3.16228
Step7 生成安装包
教程第七节
简述
本节主要讲述了,通过cpack,如何生成一个安装包文件
关于generator的帮助页面:cpack-generators(7)
或者可以直接查询:cpack --help
新的语法和命令
工具:cpack(它是和cmake在一个bin目录下)
module:InstallRequiredSystemLibraries
| variables | variables |
|---|---|
CPACK_RESOURCE_FILE_LICENSE |
CPACK_PACKAGE_VERSION_MAJOR |
CPACK_PACKAGE_VERSION_MINOR |
CPACK_SOURCE_GENERATOR |
其中,在top-level的CMakeLists.txt中include(InstallRequiredSystemLibraries)这个module,使得它能够找到对应的runtime lib以便生成安装包。
后面的几个变量,是cpack在打包过程当中用到的,其中CPACK_SOURCE_GENERATOR指定了安装包的文件格式(.tar.gz等)
改动
在top-level的CMakeLists.txt中,添加如下指令
# For packing use (by cpack)
include(InstallRequiredSystemLibraries)
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
set(CPACK_SOURCE_GENERATOR "TGZ")
include(CPack)
打包
首先仍然需要编译生成二进制文件,然后调用cpack打包
cmake ../Step7 -G "Unix Makefiles"
cmake --build .
cpack -G ZIP
这里需要注意的是,虽然在top-level的CMakeLists.txt中指明了generator是TGZ,但它需要用到NSIS,否则就无法完成打包(这里本地没有安装NSIS)
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step7_build (master)
$ cpack
CPack Error: Cannot find NSIS compiler makensis: likely it is not installed, or not in your PATH
CPack Error: Could not read NSIS registry value. This is usually caused by NSIS not being installed. Please install NSIS from http://nsis.sourceforge.net
CPack Error: Cannot initialize the generator NSIS
所以,这里在cpack的command line中重新指明generator为ZIP,以便生成.zip包
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step7_build (master)
$ cpack -G ZIP
CPack: Create package using ZIP
CPack: Install projects
CPack: - Run preinstall target for: Tutorial
CPack: - Install project: Tutorial []
CPack: Create package
CPack: - package: D:/Gitee/CMakeOfficialTutorial/Step7_build/Tutorial-1.0-win64.zip generated.
打包完成后,在目录下就生成了安装包Tutorial-1.0-win64.zip,正如上述log中所说。
Step8 添加Testing Dashboard支持
教程第八节
简述
本节主要讲述了如何添加Testing Dashboard的支持。
实际上,ctest这里就是QA系统的一部分,它帮助完成编译,运行testcases,并且将结果上传到定义好的网站上去(这里利用了Kitware提供的一个公共网站)。
工具:ctest
module:CTest
| variables | variables |
|---|---|
CTEST_PROJECT_NAME |
CTEST_NIGHTLY_START_TIME |
CTEST_DROP_METHOD |
CTEST_DROP_SITE |
CTEST_DROP_LOCATION |
CTEST_DROP_SITE_CDASH |
改动一
因为CTest这个module在被include进来的时候,会自动调用enable_testing(),所以在top-level的CMakeLists.txt里面,把
# enable testing
enable_testing()
替换为
# enable dashboard scripting
# CTest module will automatically call enable_testing()
include(CTest)
改动二
在top-level目录下面,需要创建一个CTestConfig.cmake文件,用来给CTest这个module指明以下信息
The project name
The project “Nightly” start time
The time when a 24 hour “day” starts for this project.
The URL of the CDash instance where the submission’s generated documents will be sent
set(CTEST_PROJECT_NAME "CMakeTutorial")
set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
set(CTEST_DROP_METHOD "http")
set(CTEST_DROP_SITE "my.cdash.org")
set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial")
set(CTEST_DROP_SITE_CDASH TRUE)
运行结果
首先像以往一样,利用cmake生成Makefile
cmake ../Step8 -G "Unix Makefiles"
但之后不用编译,而是直接运行ctest
ctest -VV -D Experimental
运行之后的log如下:
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step8_build (master)
$ ctest -VV -D Experimental
UpdateCTestConfiguration from :D:/Gitee/CMakeOfficialTutorial/Step8_build/DartConfiguration.tcl
Parse Config file:D:/Gitee/CMakeOfficialTutorial/Step8_build/DartConfiguration.tcl
Site: SSEA
Build name: Win32-make
Create new tag: 20220610-1344 - Experimental
Configure project
Configure with command: "D:/procs/CMake/bin/cmake.exe" "D:/Gitee/CMakeOfficialTutorial/Step8"
Run command: "D:/procs/CMake/bin/cmake.exe" "D:/Gitee/CMakeOfficialTutorial/Step8"
-- Configuring done
-- Generating done
-- Build files have been written to: D:/Gitee/CMakeOfficialTutorial/Step8_build
Command exited with the value: 0
UpdateCTestConfiguration from :D:/Gitee/CMakeOfficialTutorial/Step8_build/DartConfiguration.tcl
Parse Config file:D:/Gitee/CMakeOfficialTutorial/Step8_build/DartConfiguration.tcl
Build project
MakeCommand:D:/procs/CMake/bin/cmake.exe --build . --config "${CTEST_CONFIGURATION_TYPE}"
Run command: "D:/procs/CMake/bin/cmake.exe" "--build" "." "--config" "Release"
[ 14%] Building CXX object MathFunctions/CMakeFiles/MakeTable.dir/MakeTable.cxx.obj
[ 28%] Linking CXX executable MakeTable.exe
[ 28%] Built target MakeTable
[ 42%] Generating Table.h
[ 57%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.cxx.obj
[ 71%] Linking CXX static library libMathFunctions.a
[ 71%] Built target MathFunctions
[ 85%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.obj
[100%] Linking CXX executable Tutorial.exe
[100%] Built target Tutorial
Command exited with the value: 0
MakeCommand:D:/procs/CMake/bin/cmake.exe --build . --config "${CTEST_CONFIGURATION_TYPE}"
0 Compiler errors
0 Compiler warnings
UpdateCTestConfiguration from :D:/Gitee/CMakeOfficialTutorial/Step8_build/DartConfiguration.tcl
Parse Config file:D:/Gitee/CMakeOfficialTutorial/Step8_build/DartConfiguration.tcl
Test project D:/Gitee/CMakeOfficialTutorial/Step8_build
Constructing a list of tests
Done constructing a list of tests
Updating test list for fixtures
Added 0 tests to meet fixture requirements
Checking test dependency graph...
Checking test dependency graph end
test 1
Start 1: Runs
1: Test command: D:\Gitee\CMakeOfficialTutorial\Step8_build\Tutorial.exe "25"
1: Test timeout computed to be: 1500
1: Computing sqrt of 25 to be 13
1: Computing sqrt of 25 to be 7.46154
1: Computing sqrt of 25 to be 5.40603
1: Computing sqrt of 25 to be 5.01525
1: Computing sqrt of 25 to be 5.00002
1: Computing sqrt of 25 to be 5
1: Computing sqrt of 25 to be 5
1: Computing sqrt of 25 to be 5
1: Computing sqrt of 25 to be 5
1: Computing sqrt of 25 to be 5
1: The square root of 25 is 5
1/9 Test #1: Runs ............................. Passed 0.20 sec
#### 省略了一些log
UpdateCTestConfiguration from :D:/Gitee/CMakeOfficialTutorial/Step8_build/DartConfiguration.tcl
Parse Config file:D:/Gitee/CMakeOfficialTutorial/Step8_build/DartConfiguration.tcl
target directory list [D:/Gitee/CMakeOfficialTutorial/Step8_build/CMakeFiles/TargetDirectories.txt]
Performing coverage
COVFILE environment variable not found, not running bullseye
globbing for coverage in: D:/Gitee/CMakeOfficialTutorial/Step8_build/CMakeFiles/Continuous.dir
globbing for coverage in: D:/Gitee/CMakeOfficialTutorial/Step8_build/CMakeFiles/ContinuousBuild.dir
globbing for coverage in:
### 省略了一些log
D:/Gitee/CMakeOfficialTutorial/Step8_build/MathFunctions/CMakeFiles/test.dir
Cannot find any GCov coverage files.
Not a valid Intel Coverage command.
Cannot find any Python Trace.py coverage files.
Cannot find Cobertura XML file: D:/Gitee/CMakeOfficialTutorial/Step8_build/coverage.xml
Cannot find GTM coverage file: D:/Gitee/CMakeOfficialTutorial/Step8_build/gtm_coverage.mcov
Cannot find Cache coverage file: D:/Gitee/CMakeOfficialTutorial/Step8_build/cache_coverage.cmcov
Cannot find Jacoco coverage files: D:/Gitee/CMakeOfficialTutorial/Step8/*jacoco.xml
Cannot find BlanketJS coverage files: D:/Gitee/CMakeOfficialTutorial/Step8/*.json
Cannot find Delphi coverage files: D:/Gitee/CMakeOfficialTutorial/Step8_build/*(*.pas).html
Cannot find any coverage files. Ignoring Coverage request.
UpdateCTestConfiguration from :D:/Gitee/CMakeOfficialTutorial/Step8_build/DartConfiguration.tcl
Parse Config file:D:/Gitee/CMakeOfficialTutorial/Step8_build/DartConfiguration.tcl
Submit files
SubmitURL: http://my.cdash.org/submit.php?project=CMakeTutorial
Upload file: D:/Gitee/CMakeOfficialTutorial/Step8_build/Testing/20220610-1344/Configure.xml to http://my.cdash.org/submit.php?project=CMakeTutorial&FileName=SSEA___Win32-make___20220610-1344-Experimental___XML___Configure.xml&build=Win32-make&site=SSEA&stamp=20220610-1344-Experimental&MD5=68697147e46c795bd021649a4a8fbb06 Size: 1731
Uploaded: D:/Gitee/CMakeOfficialTutorial/Step8_build/Testing/20220610-1344/Configure.xml
Upload file: D:/Gitee/CMakeOfficialTutorial/Step8_build/Testing/20220610-1344/Build.xml to http://my.cdash.org/submit.php?project=CMakeTutorial&FileName=SSEA___Win32-make___20220610-1344-Experimental___XML___Build.xml&build=Win32-make&site=SSEA&stamp=20220610-1344-Experimental&MD5=5eebae65efe28a7be70508f63cea7428 Size: 1561
Uploaded: D:/Gitee/CMakeOfficialTutorial/Step8_build/Testing/20220610-1344/Build.xml
Upload file: D:/Gitee/CMakeOfficialTutorial/Step8_build/Testing/20220610-1344/Test.xml to http://my.cdash.org/submit.php?project=CMakeTutorial&FileName=SSEA___Win32-make___20220610-1344-Experimental___XML___Test.xml&build=Win32-make&site=SSEA&stamp=20220610-1344-Experimental&MD5=a2c6321fc5ad2113c587ca5e404c65ba Size: 13335
Uploaded: D:/Gitee/CMakeOfficialTutorial/Step8_build/Testing/20220610-1344/Test.xml
Upload file: D:/Gitee/CMakeOfficialTutorial/Step8_build/Testing/20220610-1344/Done.xml to http://my.cdash.org/submit.php?project=CMakeTutorial&FileName=SSEA___Win32-make___20220610-1344-Experimental___XML___Done.xml&build=Win32-make&site=SSEA&stamp=20220610-1344-Experimental&MD5=c37457026038fb68e75bd8fb1e50d2ef Size: 112
Uploaded: D:/Gitee/CMakeOfficialTutorial/Step8_build/Testing/20220610-1344/Done.xml
Submission successful
可以看到,ctest自动进行了编译,并且之后运行了CMakeLists.txt中的unittest,然后,把结果上传到了Kitware的公共网页:https://my.cdash.org/index.php?project=CMakeTutorial.
Step9
教程第八节
简述
本节主要讲述了如何通过option函数来设置变量BUILD_SHARED_LIBS,然后编译出动态链接库。
新的语法和命令
| command | variables |
|---|---|
target_compile_definitions |
|
其中,在top-level的CMakeLists.txt中include(InstallRequiredSystemLibraries)这个module,使得它能够找到对应
改动一
在top-level的CMakeLists.txt中,添加如下指令
# control where the static and shared libraries are built so that on windows
# we don't need to tinker with the path to run the executable
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
其中option(BUILD_SHARED_LIBS "Build using shared libraries" ON)就是用来控制编译出来动态链接库(除法显示指定生成静态库)。
改动二
其次,在MathFunctions/CMakeLists.txt中,改动完成之后如下
# add the library that runs
add_library(MathFunctions MathFunctions.cxx)
# state that anybody linking to us needs to include the current source dir
# to find MathFunctions.h, while we don't.
target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)
# should we use our own math functions
option(USE_MYMATH "Use tutorial provided math implementation" ON)
if(USE_MYMATH)
target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
# first we add the executable that generates the table
add_executable(MakeTable MakeTable.cxx)
# add the command to generate the source code
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
DEPENDS MakeTable
)
# library that just does sqrt
add_library(SqrtLibrary STATIC
mysqrt.cxx
${CMAKE_CURRENT_BINARY_DIR}/Table.h
)
# state that we depend on our binary dir to find Table.h
target_include_directories(SqrtLibrary PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
)
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
# define the symbol stating we are using the declspec(dllexport) when
# building on windows
target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH")
# install rules
set(installable_libs MathFunctions)
if(TARGET SqrtLibrary)
list(APPEND installable_libs SqrtLibrary)
endif()
install(TARGETS ${installable_libs} DESTINATION lib)
install(FILES MathFunctions.h DESTINATION include)
注意,
这里定义要编译出来的库名虽然是
MathFunctions,但和上节不同的是,它依赖于文件MathFunctions.cxx,而不再是mysqrt.cxx文件
mysqrt.cxx是用来生成另外一个库(SqrtLibrary),但这个库是根据宏USE_MYMATH来决定是否要生成。
改动三
在MathFunctions/mysqrt.cxx中,将函数double mysqrt(double x)置于mathfunctions::detail这个namespace下面。
改动四
We also need to make some changes in tutorial.cxx, so that it no longer uses USE_MYMATH:
Always include
MathFunctions.hAlways use
mathfunctions::sqrtDon’t include
cmath
改动五
在文件MathFunctions/MathFunctions.h中,export一个在namespace mathfunction下面的函数
#if defined(_WIN32)
# if defined(EXPORTING_MYMATH)
# define DECLSPEC __declspec(dllexport)
# else
# define DECLSPEC __declspec(dllimport)
# endif
#else // non windows
# define DECLSPEC
#endif
namespace mathfunctions {
double DECLSPEC sqrt(double x);
}
改动六
在MathFunctions/CMakeLists.txt中,添加如下指令
# state that SqrtLibrary need PIC when the default is shared libraries
set_target_properties(SqrtLibrary PROPERTIES
POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
)
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
根据教程提示,如果不加这一部分会导致链接失败,不过,local测试,不加这一部也能编译通过???不值为何??
At this point, if you build everything, you may notice that linking fails as we are combining a static library without position independent code with a library that has position independent code. The solution to this is to explicitly set the
POSITION_INDEPENDENT_CODEtarget property of SqrtLibrary to beTrueno matter the build type.
打开USE_MYMATH编译
编译(打开USE_MYMATH宏)
cmake ../Step9 -G "Unix Makefiles" -DUSE_MYMATH=ON
cmake --build .
然后测试
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step9_build (master)
$ ./Tutorial.exe 1
Use the table to help find an initial value
Computing sqrt of 1 to be 1
Computing sqrt of 1 to be 1
Computing sqrt of 1 to be 1
Computing sqrt of 1 to be 1
Computing sqrt of 1 to be 1
Computing sqrt of 1 to be 1
Computing sqrt of 1 to be 1
Computing sqrt of 1 to be 1
Computing sqrt of 1 to be 1
Computing sqrt of 1 to be 1
The square root of 1 is 1
显然,生成了SqrtLibrary.a这个库,并且利用了其中的mysqrt来计算平方根。
关闭USE_MYMATH编译
使用如下命令,在关闭自定义的宏USE_MYMATH之后编译
cmake ../Step9 -G "Unix Makefiles" -DUSE_MYMATH=OFF
cmake --build .
然后测试
Pyrad@SSEA MINGW64 /d/Gitee/CMakeOfficialTutorial/Step9_build (master)
$ ./Tutorial.exe 2
The square root of 2 is 1.41421
显然,没有生成SqrtLibrary.a这个库,用的是标准库中的sqrt函数来计算平方根。