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

Learning CMake Cookbook Chapter01 Part02

  • CMakeLists基本:条件语句编译控制
    • 在CMakeLists中使用条件语句进行不同编译方法的灵活切换
    • 不使用硬编码,将条件选择接口留给用户——option()命令

CMakeLists基本:条件语句编译控制

在CMakeLists中使用条件语句进行不同编译方法的灵活切换

之前的部分中,对于一个多文件的项目工程,我们已经可以掌握至少两种编译的思路使其生成对应的可执行文件:

  1. 直接生成可执行文件,在add_executable()中指定所有的源文件进行编译,并且使用include_directories()指令指定所需头文件的目录。
  2. 先为具有紧密依赖关系的文件组构建库文件——动态链接库(.so)或静态链接库(.a),之后为add_executable()命令仅添加main函数所在的源文件,最后使用target_link_libraries()命令将库文件链接到最终生成的可执行文件中。

总体来讲,分为输出库和不输出库两种模式,但是需要书写不同的代码段。那么在同一个CMakeLists文件中可否灵活的动态切换两种编译模式呢?以下使用条件编译语句进行简要介绍:


cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project(recipe-04 LANGUAGES CXX)

set(USE_LIBRARY OFF)
//定义一个变量,并将其设置为OFF,这里就是下文中逻辑语句的分支判据
//与OFF相同的逻辑值还有:数字0、false、NO、N、IGNORE、NOTFOUND、空字符串、以-NOTFOUND为后缀
//与OFF对应的逻辑变量是ON
//与ON相同的逻辑值还有:任何非零数字、true、YES、Y

message(STATUS "Compile sources into a library? ${USE_LIBRARY}")

set(BUILD_SHARED_LIBS OFF)
//注意这里容易造成混淆:!!!
//BUILD_SHARED_LIBS 是 CMakeLists 中的内置全局变量,而非我们定义的变量,
//在这里将其设置为OFF,则之后若程序允许库文件的生成,也只会生成STATIC类型的库,而非SHARED类型

list(APPEND _sources Message.hpp Message.cpp)


if(USE_LIBRARY)//条件编译:USE_LIBRARY如果为真则执行以下到else()分支,即生成库文件

  add_library(message ${_sources})

  add_executable(hello-world hello-world.cpp)

  target_link_libraries(hello-world message)

else()//条件编译:USE_LIBRARY如果为真则执行以下到endif(),即直接生成可执行文件

  add_executable(hello-world hello-world.cpp ${_sources})
  
endif()

不使用硬编码,将条件选择接口留给用户——option()命令

在刚刚的文件中,我们使用硬编码的形式,将条件编译的结果“写死”在了CMakeLists文件中,当用户想要修改时,必须进入CMakeLists中对文件内容进行修改,着造成了不便。故此,下面的方法将选项暴露给用户,允许用户在命令行对选项进行配置,从而不用修改文件也可对编译流程进行控制。


cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project(recipe-05 LANGUAGES CXX)

option(USE_LIBRARY "Compile sources into a library" OFF)
//通过引入option()命令将选择的权利暴露给用户,
//使用的方法为:在编译时使用-D选项,如:cmake -D USE_LIBRARY=OFF/ON,来决定之后的编译流程
//后面的OFF是默认选项,即:如果不加-D选项,则USE_LIBRARY默认为false

//如果你使用的是Windows下的CMake-gui,则这个选项会在configure阶段暴露给用户进行配置
//并且注意到中间的字符串,也同样是在gui中进行显示,对该选项进行描述
//当你按下CMake-gui中的generate选项时,
//系统会根据configure阶段你选择的配置将这些选项动态地添加到编译指令中

message(STATUS "Compile sources into a library? ${USE_LIBRARY}")

//相当与引入了一个包,用于提供下文中的cmake_dependent_option()命令
include(CMakeDependentOption)

//cmake_dependent_option()是一个“依赖其他选项的选项”,实质上它也是一个用户选项接口
//下面的语句理解为:“仅在USE_LIBRARY选项为ON的情况下,该option才会起作用”
//举例来说:即使我们运行cmake -D USE_LIBRARY=OFF -D MAKE_SHARED_LIBRARY=ON ..
//这仍然不会构建库,因为USE_LIBRARY被设置为OFF
cmake_dependent_option(
  MAKE_STATIC_LIBRARY "Compile sources into a static library" OFF
  "USE_LIBRARY" ON
  )
  
cmake_dependent_option(
  MAKE_SHARED_LIBRARY "Compile sources into a shared library" ON
  "USE_LIBRARY" ON
  )
  
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

list(APPEND _sources Message.hpp Message.cpp)

if(USE_LIBRARY)
  message(STATUS "Compile sources into a STATIC library? ${MAKE_STATIC_LIBRARY}")
  message(STATUS "Compile sources into a SHARED library? ${MAKE_SHARED_LIBRARY}")

  if(MAKE_SHARED_LIBRARY)
    add_library(message-shared SHARED ${_sources})
  endif()
  
  if(MAKE_STATIC_LIBRARY)
    add_library(message-static STATIC ${_sources})
  endif()

  if(MAKE_SHARED_LIBRARY)
    add_executable(hello-world hello-world.cpp)
    target_link_libraries(hello-world message-shared)

  elseif(MAKE_STATIC_LIBRARY)
    add_executable(hello-world hello-world.cpp)
    target_link_libraries(hello-world message-static)
    
  endif()
  
else()
  add_executable(hello-world hello-world.cpp ${_sources})
endif()

以下是编译过程的命令行代码示例:
在这里想要说明的是:以下有两个-D选项为option()命令提供参数指示,虽然二者存在依赖关系,但二者的前后顺序是无所谓的,无论被设置为ON还是OFF。

$: cd build
$: cmake -D USE_LIBRARY=OFF -D MAKE_SHARED_LIBRARY=ON ..
$: cmake --build .

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