$ cmake -Bbuild .
该命令是跨平台的,使用了-H
和-B
为CLI选项。-H
表示当前目录中搜索根CMakeLists.txt
文件。-Bbuild
告诉CMake在一个名为build
的目录中生成所有的文件。
➜ build cmake --build . --target help
The following are some of the valid targets for this Makefile:
… all (the default if no target is provided)
… clean
… depend
… rebuild_cache
… edit_cache
… helloworld
CMake生成的目标比构建可执行文件的目标要多。可以使用cmake --build . --target
语法,实现如下功能:
对于更复杂的项目,通过测试阶段和安装规则,CMake将生成额外的目标:
message :为用户显示一条消息
语法:
message( [STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR]
"message to display" ...)
可以用下述可选的关键字指定消息的类型:
➜ cmake --help
Generators
The following generators are available on this platform (* marks default):
* Unix Makefiles = Generates standard UNIX makefiles.
Ninja = Generates build.ninja files.
Watcom WMake = Generates Watcom WMake makefiles.
CodeBlocks - Ninja = Generates CodeBlocks project files.
CodeBlocks - Unix Makefiles = Generates CodeBlocks project files.
CodeLite - Ninja = Generates CodeLite project files.
CodeLite - Unix Makefiles = Generates CodeLite project files.
Sublime Text 2 - Ninja = Generates Sublime Text 2 project files.
Sublime Text 2 - Unix Makefiles
= Generates Sublime Text 2 project files.
Kate - Ninja = Generates Kate project files.
Kate - Unix Makefiles = Generates Kate project files.
Eclipse CDT4 - Ninja = Generates Eclipse CDT 4.0 project files.
Eclipse CDT4 - Unix Makefiles= Generates Eclipse CDT 4.0 project files.
➜ cmake_tutorial mkdir -p build
➜ cmake_tutorial cd build
➜ build ls
➜ build cmake -G Ninja …
– The C compiler identification is GNU 4.8.5
– The CXX compiler identification is GNU 4.8.5
– Check for working C compiler: /usr/bin/cc
– Check for working C compiler: /usr/bin/cc – works
– Detecting C compiler ABI info
– Detecting C compiler ABI info - done
– Detecting C compile features
– Detecting C compile features - done
– Check for working CXX compiler: /usr/bin/c++
– Check for working CXX compiler: /usr/bin/c++ – works
– Detecting CXX compiler ABI info
– Detecting CXX compiler ABI info - done
– Detecting CXX compile features
– Detecting CXX compile features - done
– Configuring done
– Generating done
– Build files have been written to: /root/workspace/cmake_tutorial/build
构建项目
➜ build cmake --build . -j8
[2/2] Linking CXX executable EP01_helloworld/helloworld
➜ build ls
build.ninja CMakeCache.txt CMakeFiles cmake_install.cmake EP01_helloworld rules.ninja
与前一个配置相比,每一步的输出没什么变化。每个生成器都有自己的文件集,所以编译步骤的输出和构建目录的内容是不同的:
build.ninja
和rules.ninja
:包含Ninja的所有的构建语句和构建规则。CMakeCache.txt
:CMake会在这个文件中进行缓存,与生成器无关。CMakeFiles
:包含由CMake在配置期间生成的临时文件。cmake_install.cmake
:CMake脚本处理安装规则,并在安装时使用。cmake --build .
将ninja
命令封装在一个跨平台的接口中。
在CMake中,add_library命令的基本语法如下:
add_library(
命令格式:
add_executable ( [ WIN32] [ MACOSX_BUNDLE] [ EXCLUDE_FROM_ALL] [source1] [source2 …])
add_executable ( IMPORTED [ GLOBAL ])
add_executable ( ALIAS )
使用指定的源文件来生成目标可执行文件。
示例:
add_library(message
#STATIC
SHARED
message.h
message.cpp
)
add_executable(helloworld_lib helloworld_lib.cpp)
target_link_libraries(helloworld_lib message)
CMake接受add_library
的第二个参数的有效值:
CMakeLists.txt
中使用add_library(message SHARED Message.hpp Message.cpp)
从静态库切换到动态共享对象(DSO)。add_library
的列表中的源码编译到目标文件,不将它们归档到静态库中,也不能将它们链接到共享对象中。如果需要一次性创建静态库和动态库,那么使用对象库尤其有用。我们将在本示例中演示。SHARED
库不同,它们不链接到项目中的任何目标,不过可以进行动态加载。该参数可以用于构建运行时插件。CMAKE_POSITION_INDEPENDENT_CODE
add_library(message-objs
OBJECT
message.h
message.cpp
)
# this is only needed for older compilers
# but doesn't hurt either to have it
set_target_properties(message-objs
PROPERTIES
POSITION_INDEPENDENT_CODE 1
)
add_library(message-shared
SHARED
$<TARGET_OBJECTS:message-objs>
)
add_library(message-static
STATIC
$<TARGET_OBJECTS:message-objs>
)
add_executable(hello-world helloworld_lib.cpp)
target_link_libraries(hello-world message-static)
在以下代码片段中,我们介绍了两个变量:USE_LIBRARY
和BUILD_SHARED_LIBS
。这两个变量都设置为OFF
。如CMake语言文档中描述,逻辑真或假可以用多种方式表示:
1
、ON
、YES
、true
、Y
或非零数,则逻辑变量为true
。0
、OFF
、NO
、false
、N
、IGNORE、NOTFOUND
、空字符串,或者以-NOTFOUND
为后缀,则逻辑变量为false
。USE_LIBRARY
变量将在第一个和第二个行为之间切换。BUILD_SHARED_LIBS
是CMake的一个全局标志。因为CMake内部要查询BUILD_SHARED_LIBS
全局变量,所以add_library
命令可以在不传递STATIC/SHARED/OBJECT
参数的情况下调用;如果为false
或未定义,将生成一个静态库。
# option(USE_LIBRARY "Compile sources into a library" OFF)
set(USE_LIBRARY OFF)
message(STATUS "Compile sources into a library? ${USE_LIBRARY}")
set(BUILD_SHARED_LIBS OFF)
list(APPEND _sources message.h message.cpp)
if(USE_LIBRARY)
add_library(message ${_sources})
add_executable(hello-world helloworld_lib.cpp)
target_link_libraries(hello-world message)
else()
add_executable(hello-world helloworld_lib.cpp ${_sources})
endif()
option
可接受三个参数:
option(
表示该选项的变量的名称。"help string"
记录选项的字符串,在CMake的终端或图形用户界面中可见。[initial value]
选项的默认值,可以是ON
或OFF
。有时选项之间会有依赖的情况。示例中,我们提供生成静态库或动态库的选项。但是,如果没有将USE_LIBRARY
逻辑设置为ON
,则此选项没有任何意义。CMake提供cmake_dependent_option()
命令用来定义依赖于其他选项的选项:
include(CMakeDependentOption)
# second option depends on the value of the first
cmake_dependent_option(
MAKE_STATIC_LIBRARY "Compile sources into a static library" OFF
"USE_LIBRARY" ON
)
# third option depends on the value of the first
cmake_dependent_option(
MAKE_SHARED_LIBRARY "Compile sources into a shared library" ON
"USE_LIBRARY" ON
)
如果USE_LIBRARY
为ON
,MAKE_STATIC_LIBRARY
默认值为OFF
,否则MAKE_SHARED_LIBRARY
默认值为ON
。可以通过cmake命令行指定变量的值:
$ cmake -D USE_LIBRARY=OFF -D MAKE_SHARED_LIBRARY=ON ..
这仍然不会构建库,因为USE_LIBRARY
仍然为OFF
。
CMake有适当的机制,通过包含模块来扩展其语法和功能,这些模块要么是CMake自带的,要么是定制的。本例中,包含了一个名为CMakeDependentOption
的模块。如果没有include
这个模块,cmake_dependent_option()
命令将不可用。参见 https://cmake.org/cmake/help/latest/module/CMakeDependentOption.html
TIPS:手册中的任何模块都可以以命令行的方式使用cmake --help-module
。例如,cmake --help-module CMakeDependentOption
将打印刚才讨论的模块的手册页(帮助页面)。
如何选择一个特定的编译器?例如,如果想使用Intel或Portland Group编译器怎么办?CMake将语言的编译器存储在 CMAKE_
变量中,其中
是受支持的任何一种语言,对于我们的目的是CXX
、C
或Fortran
。用户可以通过以下两种方式之一设置此变量:
使用CLI中的-D
选项,例如:
$ cmake -D CMAKE_CXX_COMPILER=clang++ ..
通过导出环境变量CXX
(C++编译器)、CC
(C编译器)和FC
(Fortran编译器)。例如,使用这个命令使用clang++
作为C++
编译器:
$ env CXX=clang++ cmake ..
Make提供--system-information
标志,它将把关于系统的所有信息转储到屏幕或文件中。要查看这个信息,请尝试以下操作:
$ cmake --system-information information.txt
CMake可以配置构建类型,例如:Debug、Release等。配置时,可以为Debug或Release构建设置相关的选项或属性,例如:编译器和链接器标志。控制生成构建系统使用的配置变量是CMAKE_BUILD_TYPE
。该变量默认为空,CMake识别的值为:
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
cmake -D CMAKE_BUILD_TYPE=Debug …
下面是对Visual Studio的CMake调用:
$ mkdir -p build
$ cd build
$ cmake .. -G"Visual Studio 12 2017 Win64" -D CMAKE_CONFIGURATION_TYPES="Release;Debug"
将为Release和Debug配置生成一个构建树。然后,您可以使--config
标志来决定构建这两个中的哪一个:
$ cmake --build . --config Release
NOTE:当使用单配置生成器开发代码时,为Release版和Debug创建单独的构建目录,两者使用相同的源代码。这样,就可以在两者之间切换,而不用重新配置和编译。
list(APPEND flags "-fPIC" "-Wall")
if(NOT WIN32)
list(APPEND flags "-Wextra" "-Wpedantic")
endif()
target_compile_options(geometry
PRIVATE
${flags}
)
— 分割线 —
add_executable(compute-areas compute-areas.cpp)
# 为可执行目标设置了编译选项:
target_compile_options(compute-areas
PRIVATE
"-fPIC"
)
target_link_libraries(compute-areas geometry)
本例中,警告标志有-Wall
、-Wextra
和-Wpedantic
,将这些标示添加到geometry
目标的编译选项中; compute-areas
和 geometry
目标都将使用-fPIC
标志。编译选项可以添加三个级别的可见性:INTERFACE
、PUBLIC
和PRIVATE
。
可见性的含义如下:
compute-areas
将链接到geometry
库,compute-areas
也不会继承geometry
目标上设置的编译器选项。目标属性的可见性CMake的核心,以这种方式添加编译选项,不会影响全局CMake变量CMAKE_
,并能更细粒度控制在哪些目标上使用哪些选项。
cmake --build . – VERBOSE=1
cmake --build . -j8 --verbose
cmake -DCMAKE_VERBOSE_MAKEFILE=ON …
if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
endif()
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
endif()
add_executable(animal-farm animal-farm.cpp)
set_target_properties(animal-farm
PROPERTIES
CXX_STANDARD 14
CXX_EXTENSIONS OFF
CXX_STANDARD_REQUIRED ON
)
ISO C++
标准的编译器标志,而不使用特定编译器的扩展。OFF
时,CMake将寻找下一个标准的最新版本,直到一个合适的标志。这意味着,首先查找C++11
,然后是C++98
。cmake的list命令即对列表的一系列操作,cmake中的列表变量是用分号;分隔的一组字符串,创建列表可以使用set命令(参考set命令),例如:set (var a b c d)创建了一个列表 “a;b;c;d”,而set (var “a b c d”)则是只创建了一个变量"a c c d"。list命令的具体格式根据子命令不同会有所区别
list(LENGTH <list><output variable>)
list(GET <list> <elementindex> [<element index> ...]<output variable>)
list(APPEND <list><element> [<element> ...])
list(FIND <list> <value><output variable>)
list(INSERT <list><element_index> <element> [<element> ...])
list(REMOVE_ITEM <list> <value>[<value> ...])
list(REMOVE_AT <list><index> [<index> ...])
list(REMOVE_DUPLICATES <list>)
list(REVERSE <list>)
list(SORT <list>)
我们可以看到,list命令的格式如下
list (subcommand [args...])
subcommand为具体的列表操作子命令,例如读取、查找、修改、排序等。为待操作的列表变量,[args…]为对列表变量操作需要使用的参数表,不同的子命令对应的参数也不一致。
ENGTH
返回list的长度GET
返回list中index的element到value中APPEND
添加新element到list中FIND
返回list中element的index,没有找到返回-1INSERT
将新element插入到list中index的位置REMOVE_ITEM
从list中删除某个elementREMOVE_AT
从list中删除指定index的elementREMOVE_DUPLICATES
从list中删除重复的elementREVERSE
将list的内容反转SORT
将list按字母顺序排序示例:
list(
APPEND sources_with_lower_optimization
geometry_circle.cpp
geometry_rhombus.cpp
)