CMake:条件语句、选项命令以及指定编译器

导言

上两篇,我们基本上对静态库和动态库的基本概念以及如何构建有了全面的认识。有了以上的实践,我们可以通过对自己在工作和科研学习中常用的一些工具进行总结和归纳,慢慢的形成自己的库。如我们不同领域的数学库,数据库操作工具库等等。

在目前的工作和学习以及兴趣来看,我也在慢慢的形成自己的小小的库,以满足我在入场科研和工作中的需求,加速研究和算法落地等。

今天我们想要探索的命令,其实在大部分在上一篇中已经用过了,但是没有进行详细的讲解。今天我们一起去探索一下关于条件语句、选项命令和指定编译器指令的的相关操作。

条件语句

首先,我们还是拿我们上一篇根目录下的CMakeLists.txt文件进行讲解。

cmake_minimum_required(VERSION 3.10 FATAL_ERROR)

project(hello-world LANGUAGES CXX)

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

option(BUILD_SHARED_LIBS "Specifies the type of libraries (SHARED or STATIC) to build" OFF)

# Set install direcotory
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
  set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/output/)
endif()

add_subdirectory(${CMAKE_SOURCE_DIR}/message-module)

include_directories(
    ${CMAKE_SOURCE_DIR}/message-module/include
)

add_executable(
    ${PROJECT_NAME}
    ${CMAKE_SOURCE_DIR}/hello_world.cpp
) 

target_link_libraries(
    ${PROJECT_NAME}
    test_message   
)

这里,我们使用了一个条件语句if()...endif()和一个选项命令option。这一节我们先对条件语句if()...endfi()进行讲解,关于选项option命令,将在下一节进行讲解。

if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
  set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/output/)
endif()

判断CMake自带的宏CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT有没有处于开启状态,如果是默认状态的话,则CMAKE_INSTALL_PREFIX将被设置为${CMAKE_SOURCE_DIR}/output/

这里,我们只写一个CMakeLists.txt对条件语句if()...else()和宏CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULTCMAKE_INSTALL_PREFIX进行探索。

cmake_minimum_required(VERSION 3.10 FATAL_ERROR)

project(condition)

if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
  set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/output/)
endif()

message("CMAKE_INSTALL_PREFIX is " ${CMAKE_INSTALL_PREFIX})

在这里插入图片描述
如果我们对CMAKE_INSTALL_PREFIX提前进行了定义

cmake_minimum_required(VERSION 3.10 FATAL_ERROR)

project(condition)

set(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT off)

if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
    set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/output/)
else()
    set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/output/test)
endif()

message("CMAKE_INSTALL_PREFIX is " ${CMAKE_INSTALL_PREFIX})

在这里插入图片描述
以上源码地址为:源码

选项命令

当然,上述内容我们也可以在编译时,使用如下命令,而不用显示地在CMakeLists.txt中对CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT进行设置,但我们需要在CMakeLists.txt中添加opetion命令。

cmake_minimum_required(VERSION 3.10 FATAL_ERROR)

project(condition)

option(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT "Set default install path" off)

if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
    set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/output/)
else()
    set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/output/test)
endif()

message("CMAKE_INSTALL_PREFIX is " ${CMAKE_INSTALL_PREFIX})
cmake .. -DCMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT=OFF

在这里插入图片描述
其中,-D开关用于为CMake设置任何类型的变量:逻辑变量、路径等等。
以上源码地址为:源码

指定编译器

到目前为止,我们还没有考虑过使用CMake如何选择编译器。CMake可以根据平台和生成器选择编译器,还能将编译器标志设置为默认值。

在实际工作中,指定编译器十分重要,比如我们要交叉编译嵌入式的项目,亦或是我们可以将QtOpenCV等三方库交叉编译到我们的嵌入式项目中。具体关于如何编译其他三方库生成指定的形式,我们将在之后讲到交叉编译时会详细讲解。

1. 通过命令行的形式指定

$ cmake -D CMAKE_CXX_COMPILER=clang++ ..

指定c++的编译器为clang++

CMAKE_CXX_COMPILER 指定C++编译器
CMAKE_C_COMPILER 指定C编译器
CMAKE_Fortran_COMPILER 指定Fortran编译器

2. 通过导出环境变量

$ env CXX=clang++ cmake ..

导出环境变量,指定C++的编译器为Clang++

CXX(C++编译器)、CC(C编译器)和FC(Fortran编译器)

注意:CMake了解运行环境,可以通过-D开关或者环境变量设置许多选项。第一种方法覆盖第二种方法,但是建议使用-D的显式设置选项。显式由于隐式,因为环境变量可能被设置为不合适的值(当前项目)。

注意:这里,我们假设,其他的编译器,如clang++在标准的路径中可以用,CMake可以在标准路径中执行查找编译器。如果在标准路径中不可以用使用,则用户需要将完整的编译器可执行文件或者包装器路径传递给CMake。如:

cmake -D CMAKE_CXX_COMPILER=/mnt/usr/bin/clang++ ..

注意:这里,建议使用-DCMAKE_<LANG>_COMPILER选项设置编译器,而不是导出CXXCCFC。这是确保跨平台并与非POSIX兼容的唯一方法。为了避免变量污染环境,这些变量能会影响与项目一起构建的外部库环境。

3. 在CMake中指定

set(CMAKE_CXX_COMPILER /mnt/usr/bin/clang++)

4. 工作原理

在使用CMake进行构建时,CMake会进行一系列的平台测试,以确定哪些编译器可以使用以及它们是否适合当前的项目。

一个合适的编译器不仅取决于我们使用的平台,还取决于我们想要的生成器。CMake执行的第一个测试基于项目语言的编译器名称。如,CC是一个工作i的C编译器,那么它将用作C项目的默认编译器。

GNU/Linux上,使用Unix MakefileNinja时,GCC家族中的编译器很可能时C++CFortran的默认选择。Windows上,将选择Visual StudioC++C编译器。如果选择MinGWMSYS Makefile作为生成器,则默认使用MinGW编译器。

5. 编译器的补充

我们平台上的CMake可以找到可用的编译器和编译器标志的方法是:CMake提供--system-information标志,他将把关于系统的所有信息转储到屏幕或者文件中。

$ cmake --system-information information.txt

文件中可以看到CMAKE_CXX_COMPILERCMAKE_C_COMPILERCMAKE_Fortran_COMPILER的默认值,以及默认标志。

CMake提供了额外的变量来与编译器交互:

  • CMAKE_<LANG>_COMPILER_LOADED:如果为项目启用了语言<LANG>,则将设置为TRUE
  • CMAKE_<LANG>_COMPILER_ID:编译器标识字符串,编译器供应商所特有。例如,GCC用于GNU编译器集合,AppleClang用于macOS上的Clang, MSVC用于Microsoft Visual Studio编译器。注意,不能保证为所有编译器或语言定义此变量。
  • CMAKE_COMPILER_IS_GNU<LANG>:如果语言<LANG>GNU编译器集合的一部分,则将此逻辑变量设置为TRUE。注意变量名的<LANG>部分遵循GNU约定:C语言为CC, C++语言为CXX, Fortran语言为G77
  • CMAKE_<LANG>_COMPILER_VERSION:此变量包含一个字符串,该字符串给定语言的编译器版本。版本信息在major[.minor[.patch[.tweak]]]中给出。但是,对于CMAKE_<LANG>_COMPILER_ID,不能保证所有编译器或语言都定义了此变量。

我们可以使用不同的编译器,构建下面的CMakeLists.txt

cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(recipe-06 LANGUAGES C CXX)
message(STATUS "Is the C++ compiler loaded? ${CMAKE_CXX_COMPILER_LOADED}")
if(CMAKE_CXX_COMPILER_LOADED)
    message(STATUS "The C++ compiler ID is: ${CMAKE_CXX_COMPILER_ID}")
    message(STATUS "Is the C++ from GNU? ${CMAKE_COMPILER_IS_GNUCXX}")
    message(STATUS "The C++ compiler version is: ${CMAKE_CXX_COMPILER_VERSION}")
endif()
message(STATUS "Is the C compiler loaded? ${CMAKE_C_COMPILER_LOADED}")
if(CMAKE_C_COMPILER_LOADED)
    message(STATUS "The C compiler ID is: ${CMAKE_C_COMPILER_ID}")
    message(STATUS "Is the C from GNU? ${CMAKE_COMPILER_IS_GNUCC}")
    message(STATUS "The C compiler version is: ${CMAKE_C_COMPILER_VERSION}")
endif()

更多请关注微信公众号【Hope Hut】:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值