一、文件数
├── CMakeLists.txt
├── main.cpp
1.1 main.cpp
#include <iostream>
int main(int argc, char *argv[])
{
std::cout << "Hello Build Type!" << std::endl;
return 0;
}
1.2 CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(build_type)
# 如果没有指定则设置默认编译方式
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message("Setting build type to 'RelWithDebInfo' as none was specified.") # 命令行输出message里的信息
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE # 不管CACHE是否设置过CMAKE_BUILD_TYPE这个
STRING "Choose the type of build." FORCE) # 变量,强制赋值为RelWithDebInfo
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" # 当使用cmake-gui的时候,设置构建级别的四个选项
"Release" "MinSizeRel" "RelWithDebInfo")
endif()
add_executable(cmake_examples_build_type main.cpp)
二、CMake具体解析
2.1 构建级别
CMake具有许多内置的构建配置,可用于编译工程。 这些配置指定了代码优化的级别,以及调试信息是否包含在二进制文件中。
这些优化级别,主要有:
- Release —— 不可以打断点调试,程序开发完成后发行使用的版本,占的体积小。 它对代码做了优化,因此速度会非常快,
在编译器中使用命令:-O3 -DNDEBUG
可选择此版本。 - Debug ——调试的版本,体积大。
在编译器中使用命令:-g
可选择此版本。 - MinSizeRel—— 最小体积版本
在编译器中使用命令:-Os -DNDEBUG
可选择此版本。 - RelWithDebInfo—— 既优化又能调试。
在编译器中使用命令:-O2 -g -DNDEBUG
可选择此版本。
2.2 设置级别的方式
2.2.1 CMake图形界面
2.2.2 CMake命令行中
在命令行运行 CMake 的时候, 使用 cmake 命令行的 -D 选项配置编译类型
cmake .. -DCMAKE_BUILD_TYPE=Release
2.2.3 CMake中设置默认的构建级别
CMake 提供的默认构建类型是不进行优化的构建级别。 对于某些项目,需要自己设置默认的构建类型,以便不必记住进行设置。
具体语法接下来介绍
2.2.4 set()命令
该命令可以为普通变量、缓存变量、环境变量赋值。
处可以设置零个或多个参数。多个参数将以分号分隔的列表形式加入,以形成要设置的实际变量值。零参数将导致未设置普通变量。见 [unset()](https://cmake.org/cmake/help/latest/command/unset.html#command:unset)
命令显式取消设置变量。
所以此处学习 SET
命令需要分为设置普通变量,缓存变量以及环境变量三种类别来学习。
正常变量
set(<variable <value>... [PARENT_SCOPE])
设置的变量值作用域属于整个 CMakeLists.txt 文件(一个工程可能有多个 CMakeLists.txt)。
当这个语句加入 PARENT_SCOPE
后,表示要设置的变量是父目录中的 CMakeLists.txt 已经设置的变量。
比如,有如下目录树
├── CMakeLists.txt
└── src
└── CMakeLists.txt
并且在顶层的 CMakeLists.txt 中包含了 src 目录:add_subdirectory(src)
,那么顶层的 CMakeLists.txt 就是父目录。
如果父目录中有变量 Bang
,在子目录中就可以直接使用(比如,用 message()
输出 Bang
,值就是父目录中设置的值)。并且利用 set()
修改该变量 Bang()
的值,但是如果希望在子目录中的 CMakeLists.txt 中对变量的修改能够得以保留的话,就需要在 set()
命令中加入 Parent scoope
这个变量。
当然,如果父目录中本身中没有这个变量,子目录中仍然使用了 parent scope
,那么出了这个作用域后,该变量仍然不会存在。
CACHE
变量
完整语句如下:
set(<variable><value>... CACHE<type><docstring>[FORCE])
- 首先,什么是
CACHE
变量,就是在运行 CMake 的时候,变量的值可能会被缓存到一份文件里,即 build 文件夹下的 CMakeCache.txt 文件,当你重新运行 CMake 的时候,那些变量会默认使用这个缓存里面的值。这个值是全局变量,整个 CMake 工程都可以使用该变量。 - 在 build 这个文件夹里,只要运行
cmake ..
命令就会自动出现一些值,比如CMAKE_INSATLL_PREFIX
。如果设置set(CMAKE_INSTALL_PREFIX"/usr“)
,虽然CACHE
缓存文件里还有这个CMAKE_INSTALL_PREFIX
变量,但是因为我们显示地设置了一个名为CMAKE_INSTALL_PREFIX
的正常变量,所以之后使用CMAKE_INSTALL_PREFIX
,值就是我们设置的正常变量的值。 - 如果加上
CACHE
关键字,则设置的这个变量会被写入缓存文件中(但是如果本身缓存文件中有这个变量,则不会覆盖缓存中的变量)。只有加上FORCE
关键字,这个被写入文件的值会覆盖之前文件中存在的同名变量。 - 加上
CACHE
关键字,和是必须的。
CMake GUI 中通过 Add Entry 让用户设置值。可以有 5 种选项(我这里是 4 种),弹出提示消息
- BOOL:则为布尔
ON/OFF
值。 cmake-gui 提供一个复选框。 - FILEPATH:则为磁盘上文件的路径。 cmake-gui 提供一个文件对话框。
- PATH:则为磁盘上目录的路径。 cmake-gui 提供一个文件对话框。
- STRING:则为一行文字。 cmake-gui 提供文本字段或下拉选择(如果
STRINGS
设置了缓存条目属性。) - INTERNAL:则为一行文字。 cmake-gui 不显示内部条目。它们可用于在运行之间持久存储变量。使用此类型暗含
FORCE
。
比如
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
这句话,就是强制在缓存文件中覆盖 CMAKE_BUILD_TYPE 这个变量,将这个变量设置为 RelWithDebInfo。而STRING "Choose the type of build."
参数在使用 cmake-gui 的时候起作用,在界面上会出现一个下拉框供给用户选择来设置 CMAKE_BUILD_TYPE 变量。里的一行文字作为提示。
但是这个下拉框里的内容,需要使用随后的set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
这个命令来设置。也就是所谓的设置 string 缓存条目属性。
添加后的界面如下图所示:
环境变量
set(ENV{<variable>} [<value>])
设置一个 Environment Variable
到给定值,随后的调用 $ENV{<variable>}
将返回此新值。此命令仅仅影响当前的 CMake 进程,不影响调用 CMake 的进程,也不影响整个系统环境,也不影响后续构建或测试过程的环境。
如果在空字符串之后 ENV{}
或如果没有参数,则此命令将清除环境变量的任何现有值。之后``的参数将被忽略。如果发现其他参数,则会发出作者警告。
三、CMake构建
$ cmake ..
Setting build type to 'RelWithDebInfo' as none was specified.
-- The C compiler identification is GNU 8.4.1
-- The CXX compiler identification is GNU 8.4.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - 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: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /root/CmakeTest/build
$ make VERBOSE=1
/usr/bin/cmake -S/root/CmakeTest -B/root/CmakeTest/build --check-build-system CMakeFiles/Makefile.cmake 0
/usr/bin/cmake -E cmake_progress_start /root/CmakeTest/build/CMakeFiles /root/CmakeTest/build//CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/root/CmakeTest/build'
make -f CMakeFiles/cmake_examples_build_type.dir/build.make CMakeFiles/cmake_examples_build_type.dir/depend
make[2]: Entering directory '/root/CmakeTest/build'
cd /root/CmakeTest/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /root/CmakeTest /root/CmakeTest /root/CmakeTest/build /root/CmakeTest/build /root/CmakeTest/build/CMakeFiles/cmake_examples_build_type.dir/DependInfo.cmake --color=
make[2]: Leaving directory '/root/CmakeTest/build'
make -f CMakeFiles/cmake_examples_build_type.dir/build.make CMakeFiles/cmake_examples_build_type.dir/build
make[2]: Entering directory '/root/CmakeTest/build'
[ 50%] Building CXX object CMakeFiles/cmake_examples_build_type.dir/main.cpp.o
/usr/bin/c++ -O2 -g -DNDEBUG -MD -MT CMakeFiles/cmake_examples_build_type.dir/main.cpp.o -MF CMakeFiles/cmake_examples_build_type.dir/main.cpp.o.d -o CMakeFiles/cmake_examples_build_type.dir/main.cpp.o -c /root/CmakeTest/main.cpp
[100%] Linking CXX executable cmake_examples_build_type
/usr/bin/cmake -E cmake_link_script CMakeFiles/cmake_examples_build_type.dir/link.txt --verbose=1
/usr/bin/c++ -O2 -g -DNDEBUG CMakeFiles/cmake_examples_build_type.dir/main.cpp.o -o cmake_examples_build_type
make[2]: Leaving directory '/root/CmakeTest/build'
[100%] Built target cmake_examples_build_type
make[1]: Leaving directory '/root/CmakeTest/build'
/usr/bin/cmake -E cmake_progress_start /root/CmakeTest/build/CMakeFiles 0
$ ls
Consolidate compiler generated dependencies of target cmake_examples_build_type
$ ./cmake_examples_build_type
Hello Build Type!