cmake之从可执行文件到库
从可执行文件到库
-
一些基础的注意事项
# set minimum cmake version 项目构建的开始需要设置最小的cmake版本,并定义不满足这一要求时的cmake行为 cmake_minimum_required(VERSION 3.5 FATAL_ERROR) # project name and language 项目名称和支持的编程语言 project(recipe-01 LANGUAGES CXX) # 编译和链接源文件hell0-world.cpp以生成可执行文件hello-world add_executable(hello-world hello-world.cpp)
-
上述文件命名为CMakeLists.txt,区分大小写,否则无法解析;
-
CMake语言不区分大小写,但是参数区分大小写;
-
CMake中,c++是默认编程语言,但最好使用LANGUAGES选项在project中显示声明项目的语言;
-
一些基础指令:
mkdir -p build # 创建生成构建器的位置 cd build cmake .. # 指定CMakeLists.txt所在位置
为了不和源代码混淆,一般在源外创建生成构建其目录;
-
CMake是一个构建系统生成器,描述构建系统(VS, Ninja、Makefile等)如何操作才能编译代码;然后CMake为所选的构建系统生成相应的指令;
-
如何切换生成器:
-
通过生成器列表确定是否存在所需要的生成器:
cmake -help
-
切换生成器:
... cd build cmake -G Ninja .. # 即添加-G参数切换所需要使用的生成器 cmake --build .
每个生成器都有自己的文件集,构建结果其生成的文件是不同的;
-
-
-
构建和链接静态库和动态库
-
构建所需要的CMakeLists.txt
# ---准备操作--- # set minimum cmake version cmake_minimum_required(VERSION 3.5 FATAL_ERROR) # project name and language project(recipe-03 LANGUAGES CXX) # 创建目标-静态库 # 生成必要的构建指令,将指定的源码编译到库中 # 第二个参数为其他值时: # STATIC - 用于创建静态库,即编译文件的打包存档,用于在链接其他目标时使用; # SHARED - 用于创建动态库链接,并在运行时加载; # OBJECT - 将列表中的源码编译到目标文件,不将其进行归档到静态库和共享对象中; # MODULE - DSO组,不链接到项目中的任何目标,不过可以进行动态加载,用于构建运行时插件; add_library(message STATIC Message.hpp Message.cpp) # 创建可执行文件 # 将库链接到可执行文件,确保hello-world可执行文件正确依赖于message库 add_executable(hello-world hello-world.cpp) # 目标库连接到可执行文件 target_link_libraries(hello-world message)
编译完成之后,会生成一个message.lib静态库文件;
-
要保证编译的目标文件与生成位置无关, 可以通过使用 set_target_properties 命令;
set_target_properties(message-objs PROPERTIES POSITION_INDEPENDENT_CODE 1 )
-
-
条件语句控制编译
-
条件结构为 if-else- else-endif ;
-
如果需要在不同的行为之间进行切换,如构建静态库或动态库再生成可执行文件和直接生成可执行文件两种选择,则CMake中的文件条件语部分可以编写为:
... set(USE_LIBRARY OFF) # 设置变量 message(STATUS "COMPILE SOURCE INTO A LIBRARY? ${USE_LIBRARY}") set(USE_SHARED_LIBS OFF) list(APPEND _source Message.hpp Message.cpp) # 将文件装入列表 if(USED_LIBRARY) add_library(message ${_sources}) #_source是局部变量,前面加下划线,不应该再当前范围之外使用 add_excutable(hello-world hello-world.cpp) target_link_libraries(hell-world message) else() add_excutable(hell-world hello-world.cpp ${_sources}) #添加方式有所不同 endif() ...
-
-
向用户显示选项,可以被用户选择性设置
-
在CMake中使用option(),用于外部设置,从而切换构建系统的生成行为
-
使用选项替换set(USE_LIBRARY OFF)命令,使得其在命令行可以被修改
option(USE_LIBRARY "Compile sources into a library" OFF) # 三个参数:option(<option_variable> "help string" [initial value]) # <option_variable> - 变量的名称 # "help string" - 描述选项的字符段; # [initial value] - 选项的默认值
# 编译时使用 ... cd build cmake -D USE_LIBRARY=ON .. # -D开关用于为CMake设置任何类型的变量,如逻辑变量、路径等 cmake --build .
-
-
指定编译器
-
CMake将语言的编译器存储在CMAKE__COMPILER 变量中,选择特定的编译器时,可以通过CMAKE__COMPILER进行选择,其中,可以是受支持的任意一种语言
# 指定编译器的方式有两种 # 第一种 cmake -D CMKAE_CXX_COMPILER=clang++ .. # 第二种 env CXX=clang++ cmake ..
-
建议使用第二种编译器指定方式,因为环境变量可能被设定为不适合当前项目的值;
-
可以通过命令cmake --system-information来查看可用的比那一起和对应的编译器的标志;
-
-
切换构建类型
-
构建类型如Debug、Release等;
-
控制生成构建系统使用的配置变量为CMAKE_BUILD_TYPE,该变量默认为空;
-
使用
# 准备 ... # 设置默认的构建类型,并打印一条消息 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 .. ..
-
-
设置编译器选项,即控制项目的编译标志
-
计算不同的形状面积的函数位于不同文件中
-
CMakeLists
# 控制编译器标志的第一种方法 ... # 主要代码 message("C++ compiler flags: ${CMAKE_CXX_FLAGS}") # 为目标准备标志列表 list(APPEND flags "-fPIC" "-Wall") if(NOT Win32) list(APPEND flags "-Wextra" "-Wpedantic") endif() # 添加新的目标库并附加依赖源 add_library(geometry STATIC geometry_circle.cpp geometry_circle.hpp geometry_polygon.cpp geometry_polygon.hpp geometry_rhombus.cpp geometry_rhombus.hpp geometry_square.cpp geometry_square.hpp ) # 设置编译选项 target_compile_options(geometry PRIVATE ${flags}) # 创建可执行目标 add_executable(compute-areas compute-areas.cpp) # 为可执行目标设置编译选项 target_compille_options(compute-areas PRIVATE "-fPIC") #链接可目标文件与库文件 target_link_libraries(compute-areas geometry) ...
-
控制编译器标志的第二种方法:不用对CMakeLists.txt进行修改,修改geometry和compute-areas目标的编译器选项可以使用CMAKE的参数进行配置:
... cmake -D CMAKE_CXX_FLAGS="-fno-exceptions -fno-rtti" .. # 这个命令将编译项目, 禁用异常和运行时类型标识(RTTI) ... # 也可以使用全局标志,即使用CMakeLists.txt运行下面的命令 cmake -D CMAKE_CXX_FLAGS="-fno-exceptions -fno-rtti" ..
-
-
使用控制流
-
CMake提供了创建循环的语言工具: foreach-endforeach 和 while-endwhile,实际使用样例可以参考如下的foreach:
# 准备 ... add_library(geometry STATIC 文件列表) target_compile_options(PRIVATE -03) list(APPEND sources_with_lower_optimization geometry_circle.cpp geometry_rhombus.cpp)# 生成源文件列表 # 循环以上文件列表中的文件,并将其优化级别调到-02 message(STATUS "Setting source properties using IN LISTS syntax:") foreach(_source IN LISTS sources_with_lower_optimization) set_source_files_properties(${_source} PROPERTIES COMPILE_FLAGS -02) message(STATUS "Appending -02 flag for ${_source}") endforeach() # 检查是否设置正确 message(STATUS "Querying source properties using IN plain syntax:") foreach(_source IN LISTS sources_with_lower_optimization) get_source_file_property(${_source} PROPERTIES COMPILE_FLAGS) message(STATUS "Source ${_source} has the following extra COMPILE_FLAGS:${_flags}") endforeach() ...
-
-
polo
[4]: http://adrai.github.io/flowchart.js/### 从可执行文件到库
-
一些基础的注意事项
# set minimum cmake version 项目构建的开始需要设置最小的cmake版本,并定义不满足这一要求时的cmake行为 cmake_minimum_required(VERSION 3.5 FATAL_ERROR) # project name and language 项目名称和支持的编程语言 project(recipe-01 LANGUAGES CXX) # 编译和链接源文件hell0-world.cpp以生成可执行文件hello-world add_executable(hello-world hello-world.cpp)
-
上述文件命名为CMakeLists.txt,区分大小写,否则无法解析;
-
CMake语言不区分大小写,但是参数区分大小写;
-
CMake中,c++是默认编程语言,但最好使用LANGUAGES选项在project中显示声明项目的语言;
-
一些基础指令:
mkdir -p build # 创建生成构建器的位置 cd build cmake .. # 指定CMakeLists.txt所在位置
为了不和源代码混淆,一般在源外创建生成构建其目录;
-
CMake是一个构建系统生成器,描述构建系统(VS, Ninja、Makefile等)如何操作才能编译代码;然后CMake为所选的构建系统生成相应的指令;
-
如何切换生成器:
-
通过生成器列表确定是否存在所需要的生成器:
cmake -help
-
切换生成器:
... cd build cmake -G Ninja .. # 即添加-G参数切换所需要使用的生成器 cmake --build .
每个生成器都有自己的文件集,构建结果其生成的文件是不同的;
-
-
-
构建和链接静态库和动态库
-
构建所需要的CMakeLists.txt
# ---准备操作--- # set minimum cmake version cmake_minimum_required(VERSION 3.5 FATAL_ERROR) # project name and language project(recipe-03 LANGUAGES CXX) # 创建目标-静态库 # 生成必要的构建指令,将指定的源码编译到库中 # 第二个参数为其他值时: # STATIC - 用于创建静态库,即编译文件的打包存档,用于在链接其他目标时使用; # SHARED - 用于创建动态库链接,并在运行时加载; # OBJECT - 将列表中的源码编译到目标文件,不将其进行归档到静态库和共享对象中; # MODULE - DSO组,不链接到项目中的任何目标,不过可以进行动态加载,用于构建运行时插件; add_library(message STATIC Message.hpp Message.cpp) # 创建可执行文件 # 将库链接到可执行文件,确保hello-world可执行文件正确依赖于message库 add_executable(hello-world hello-world.cpp) # 目标库连接到可执行文件 target_link_libraries(hello-world message)
编译完成之后,会生成一个message.lib静态库文件;
-
要保证编译的目标文件与生成位置无关, 可以通过使用 set_target_properties 命令;
set_target_properties(message-objs PROPERTIES POSITION_INDEPENDENT_CODE 1 )
-
-
条件语句控制编译
-
条件结构为 if-else- else-endif ;
-
如果需要在不同的行为之间进行切换,如构建静态库或动态库再生成可执行文件和直接生成可执行文件两种选择,则CMake中的文件条件语部分可以编写为:
... set(USE_LIBRARY OFF) # 设置变量 message(STATUS "COMPILE SOURCE INTO A LIBRARY? ${USE_LIBRARY}") set(USE_SHARED_LIBS OFF) list(APPEND _source Message.hpp Message.cpp) # 将文件装入列表 if(USED_LIBRARY) add_library(message ${_sources}) #_source是局部变量,前面加下划线,不应该再当前范围之外使用 add_excutable(hello-world hello-world.cpp) target_link_libraries(hell-world message) else() add_excutable(hell-world hello-world.cpp ${_sources}) #添加方式有所不同 endif() ...
-
-
向用户显示选项,可以被用户选择性设置
-
在CMake中使用option(),用于外部设置,从而切换构建系统的生成行为
-
使用选项替换set(USE_LIBRARY OFF)命令,使得其在命令行可以被修改
option(USE_LIBRARY "Compile sources into a library" OFF) # 三个参数:option(<option_variable> "help string" [initial value]) # <option_variable> - 变量的名称 # "help string" - 描述选项的字符段; # [initial value] - 选项的默认值
# 编译时使用 ... cd build cmake -D USE_LIBRARY=ON .. # -D开关用于为CMake设置任何类型的变量,如逻辑变量、路径等 cmake --build .
-
-
指定编译器
-
CMake将语言的编译器存储在CMAKE__COMPILER 变量中,选择特定的编译器时,可以通过CMAKE__COMPILER进行选择,其中,可以是受支持的任意一种语言
# 指定编译器的方式有两种 # 第一种 cmake -D CMKAE_CXX_COMPILER=clang++ .. # 第二种 env CXX=clang++ cmake ..
-
建议使用第二种编译器指定方式,因为环境变量可能被设定为不适合当前项目的值;
-
可以通过命令cmake --system-information来查看可用的比那一起和对应的编译器的标志;
-
-
切换构建类型
-
构建类型如Debug、Release等;
-
控制生成构建系统使用的配置变量为CMAKE_BUILD_TYPE,该变量默认为空;
-
使用
# 准备 ... # 设置默认的构建类型,并打印一条消息 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 .. ..
-
-
设置编译器选项,即控制项目的编译标志
-
计算不同的形状面积的函数位于不同文件中
-
CMakeLists
# 控制编译器标志的第一种方法 ... # 主要代码 message("C++ compiler flags: ${CMAKE_CXX_FLAGS}") # 为目标准备标志列表 list(APPEND flags "-fPIC" "-Wall") if(NOT Win32) list(APPEND flags "-Wextra" "-Wpedantic") endif() # 添加新的目标库并附加依赖源 add_library(geometry STATIC geometry_circle.cpp geometry_circle.hpp geometry_polygon.cpp geometry_polygon.hpp geometry_rhombus.cpp geometry_rhombus.hpp geometry_square.cpp geometry_square.hpp ) # 设置编译选项 target_compile_options(geometry PRIVATE ${flags}) # 创建可执行目标 add_executable(compute-areas compute-areas.cpp) # 为可执行目标设置编译选项 target_compille_options(compute-areas PRIVATE "-fPIC") #链接可目标文件与库文件 target_link_libraries(compute-areas geometry) ...
-
控制编译器标志的第二种方法:不用对CMakeLists.txt进行修改,修改geometry和compute-areas目标的编译器选项可以使用CMAKE的参数进行配置:
... cmake -D CMAKE_CXX_FLAGS="-fno-exceptions -fno-rtti" .. # 这个命令将编译项目, 禁用异常和运行时类型标识(RTTI) ... # 也可以使用全局标志,即使用CMakeLists.txt运行下面的命令 cmake -D CMAKE_CXX_FLAGS="-fno-exceptions -fno-rtti" ..
-
-
使用控制流
-
CMake提供了创建循环的语言工具: foreach-endforeach 和 while-endwhile,实际使用样例可以参考如下的foreach:
# 准备 ... add_library(geometry STATIC 文件列表) target_compile_options(PRIVATE -03) list(APPEND sources_with_lower_optimization geometry_circle.cpp geometry_rhombus.cpp)# 生成源文件列表 # 循环以上文件列表中的文件,并将其优化级别调到-02 message(STATUS "Setting source properties using IN LISTS syntax:") foreach(_source IN LISTS sources_with_lower_optimization) set_source_files_properties(${_source} PROPERTIES COMPILE_FLAGS -02) message(STATUS "Appending -02 flag for ${_source}") endforeach() # 检查是否设置正确 message(STATUS "Querying source properties using IN plain syntax:") foreach(_source IN LISTS sources_with_lower_optimization) get_source_file_property(${_source} PROPERTIES COMPILE_FLAGS) message(STATUS "Source ${_source} has the following extra COMPILE_FLAGS:${_flags}") endforeach() ...
-
1 [参考CMake Cookbook](CMake Cookbook )