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_DEFAULT
、CMAKE_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
可以根据平台和生成器选择编译器,还能将编译器标志设置为默认值。
在实际工作中,指定编译器十分重要,比如我们要交叉编译嵌入式的项目,亦或是我们可以将Qt
、OpenCV
等三方库交叉编译到我们的嵌入式项目中。具体关于如何编译其他三方库生成指定的形式,我们将在之后讲到交叉编译时会详细讲解。
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
选项设置编译器,而不是导出CXX
、CC
和FC
。这是确保跨平台并与非POSIX
兼容的唯一方法。为了避免变量污染环境,这些变量能会影响与项目一起构建的外部库环境。
3. 在CMake中指定
set(CMAKE_CXX_COMPILER /mnt/usr/bin/clang++)
4. 工作原理
在使用CMake
进行构建时,CMake
会进行一系列的平台测试,以确定哪些编译器可以使用以及它们是否适合当前的项目。
一个合适的编译器不仅取决于我们使用的平台,还取决于我们想要的生成器。CMake
执行的第一个测试基于项目语言的编译器名称。如,CC
是一个工作i的C
编译器,那么它将用作C
项目的默认编译器。
GNU/Linux
上,使用Unix Makefile
或Ninja
时,GCC
家族中的编译器很可能时C++
、C
和Fortran
的默认选择。Windows
上,将选择Visual Studio
中C++
和C
编译器。如果选择MinGW
或MSYS Makefile
作为生成器,则默认使用MinGW编译器。
5. 编译器的补充
我们平台上的CMake
可以找到可用的编译器和编译器标志的方法是:CMake
提供--system-information
标志,他将把关于系统的所有信息转储到屏幕或者文件中。
$ cmake --system-information information.txt
文件中可以看到CMAKE_CXX_COMPILER
、CMAKE_C_COMPILER
和CMAKE_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】: