【Learning CMake Cookbook】第一章--第三部分

Learning CMake Cookbook Chapter01 Part03

  • 编译器选项在CMakeLists中的设置
  • 编译选项正确性的检测
  • 其他方法添加编译选项
  • 为不同厂商提供的编译器给出不同的编译选项设置

编译器选项在CMakeLists中的设置

本次将使用CMakeLists来设置编译器选项。一般来说,这些命令都是可以在编译过程中,使用命令行直接敲进去的,都是编译时加入的选项/参数。以下的这些-fPIC、-Wall等编译器选项,实质上与g++/gcc编译时的-o、-i、-g等参数并没有太大区别。(当前这么理解不知道是否有误2022-02-18)。

cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project(recipe-08 LANGUAGES CXX)

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}
  )//为库文件的编译添加选项:-Wextra -Wpedantic -fPIC -Wall
  

add_executable(compute-areas compute-areas.cpp)


target_compile_options(compute-areas
  PRIVATE
    "-fPIC"
  )//为可执行文件的编译添加选项:-fPIC
  
target_link_libraries(compute-areas geometry)

需要注意的是以上target_compile_options()的参数PRIVATE,这是一个可见性的标记,除了PRIVATE外还有PUBLIC和INTERFACE标记,具体的标记含义如下:

  • PRIVATE,编译选项会应用于给定的目标,不会传递给与目标相关的目标。
    • 我们的示例中, 即使 compute-areas 将链接到 geometry 库, compute-areas 也不会继承 geometry 目标上设置的编译器选项。(就是说 flags 列表中的标志不会被compute-area继承)
  • PUBLIC,编译选项将应用于指定目标和使用它的目标。
    • 具体来说:flags 列表中的标志将会被compute-area继承,因为compute-area链接了geometry库???
  • INTERFACE,给定的编译选项将只应用于指定目标,并传递给与目标相关的目标。
    • 具体来说:flags 列表中的标志将会被compute-area继承,因为compute-area链接了geometry库???

但是以上的 INTERFACE 和 PUBLIC 的差异还是没搞明白

编译选项正确性的检测

我们进行了如上的设置,但如何验证我们的设置是否起效了呢?于是可以使用如下的编译指令,在编译过程的输出中进行实时的查看:本例中,设置VERBOSE=1

$ mkdir -p build
$ cd build
$ cmake ..
$ cmake --build . -- VERBOSE=1

其他方法添加编译选项

除了以上的方式对编译选项添加一些设置/标志,还可以通过在命令行中使用类似配置option的方式来对其进行设置。同样是使用-D命令,在命令行中对CMAKE_CXX_FLAGS进行设置。这种方式将对所有的对象添加所设置的编译标志。

$ mkdir -p build
$ cd build
$ cmake -D CMAKE_CXX_FLAGS="-fno-exceptions -fno-rtti" ..
$ cmake --build . -- VERBOSE=1

使用如上方法,为所有对象添加-fno-exceptions 以及 -fno-rtti编译标志,在build命令执行完后,可以在命令行中看到对应的输出结果得以验证。

但是以上的方法是一种全局的设置,在实际工程中,我们还是推荐为每个目标设置编译器标志,使用target_compile_options()设置每一个对象,不仅允许对编译选项进行细粒度控制,而且还可以更好地与CMake的更高级特性进行集成(这部分我们放在之后的章节进行介绍)。

为不同厂商提供的编译器给出不同的编译选项设置

CMake的一大优点在于其可以跨平台为我们的工程提供构建、编译的方案。所以对不同厂商提供的编译器,不一定相互理解各自的标志,故这里我们提供如下方法解决项目跨平台编译、对于不同平台给出不同标志的方案。

以下这种方法对CMake内置变量CMAKE__FLAG_\作为列表进行编译标志的添加。

if(CMAKE_CXX_COMPILER_ID MATCHES GNU)//对于GCC/G++我们给出一套编译选项的标志设置方案
  list(APPEND CMAKE_CXX_FLAGS "-fno-rtti" "-fno-exceptions")
  list(APPEND CMAKE_CXX_FLAGS_DEBUG "-Wsuggest-final-types" "-Wsuggest-final-methods" "-Wsuggest-override")
  list(APPEND CMAKE_CXX_FLAGS_RELEASE "-O3" "-Wno-unused")
endif()//对于不同的版本:Debug/Release版本,我们为其添加不同的标志

if(CMAKE_CXX_COMPILER_ID MATCHES Clang)//对于Clang我们给出一套编译选项的标志设置方案
  list(APPEND CMAKE_CXX_FLAGS "-fno-rtti" "-fno-exceptions" "-Qunused-arguments" "-fcolor-diagnostics")
  list(APPEND CMAKE_CXX_FLAGS_DEBUG "-Wdocumentation")
  list(APPEND CMAKE_CXX_FLAGS_RELEASE "-O3" "-Wno-unused")
endif()//Clang编译器不一定支持GCC/G++中的一些标志,但是我们可以发现其中的确有些标志是重复/通用的

以下还提供了更细粒度的设置/书写方法,该方法中,不直接使用CMake的内置变量,而是直接自定义一个特定的标志列表:

set(COMPILER_FLAGS)
set(COMPILER_FLAGS_DEBUG)
set(COMPILER_FLAGS_RELEASE)

if(CMAKE_CXX_COMPILER_ID MATCHES GNU)
  list(APPEND CXX_FLAGS "-fno-rtti" "-fno-exceptions")
  list(APPEND CXX_FLAGS_DEBUG "-Wsuggest-final-types" "-Wsuggest-final-methods" "-Wsuggest-override")
  list(APPEND CXX_FLAGS_RELEASE "-O3" "-Wno-unused")
endif()

if(CMAKE_CXX_COMPILER_ID MATCHES Clang)
  list(APPEND CXX_FLAGS "-fno-rtti" "-fno-exceptions" "-Qunused-arguments" "-fcolor-diagnostics")
  list(APPEND CXX_FLAGS_DEBUG "-Wdocumentation")
  list(APPEND CXX_FLAGS_RELEASE "-O3" "-Wno-unused")
endif()

稍后,使用生成器表达式来设置编译器标志的基础上,为每个配置和每个目标生成构建系统:

target_compile_option(compute-areas
  PRIVATE
    ${CXX_FLAGS}
    "$<$:${CXX_FLAGS_DEBUG}>"
    "$<$:${CXX_FLAGS_RELEASE}>"
)

??勘误:以上set的三个列表好像都没有用到?!这里是不是有错误–待定2022-02-19

你可能感兴趣的:(CMakeCookBook,cmake,c++,编译器,linux)