CMAKE项目构建

53 阅读3分钟

3.2指令和命令

3.2.2定义语言和元数据

cmake project(<project-name> [<lang-name>...]) e.g. cmake project(demo CXX C)

cmake project(<project-name> [VERSION <maj>.<min>.<patch>.<tweak>] [DESCRIPTION <project-descrip-string>] [HOMEPAGE_URL <url-string>] [LANGUAGES <lang-name>...] ) e.g.

project(moderncmake
        VERSION 0.0.0.1
        DESCRIPTION "modern cmake for cpp"
        HOMEPAGE_URL "www.baidu.com"
        LANGUAGES CXX C CUDA
)

project()命令会自动创建内置变量,包括

PROJECT_NAME
CMAKE_PROJECT_NAME 顶层CMakeLists.txt可见
PROJECT_SOURCE_DIR, <PROJECT_NAME>_SOURCE_DIR
PROJECT_BINARY_DIR, <PROJECT_NAME>_BINARY_DIR

指定VERSION时,会创建以下变量

PROJECT_VERSION, <PROJECT_NAME>_VERSION
CMAKE_PROJECT_NAME (只有在顶层 CMakeLists.txt 中)
PROJECT_VERSION_MAJOR, <PROJECT_NAME>_VERSION_MAJOR
PROJECT_VERSION_MINOR, <PROJECT_NAME>_VERSION_MINOR
PROJECT_VERSION_PATCH, <PROJECT_NAME>_VERSION_PATCH
PROJECT_VERSION_TWEAK, <PROJECT_NAME>_VERSION_TWEAK

3.3划分项目

?????????????? cmake add_subdirectory(source_dir [binary_dir] [EXECLUDE_FROM_ALL]) e.g.

# 顶层CMakeLists.txt
cmake_minimum_required(VERSION 3.22)
project(moderncmake
        VERSION 0.0.0.1
        DESCRIPTION "modern cmake for cpp"
        HOMEPAGE_URL "www.baidu.com"
        LANGUAGES CXX C
)

set(CMAKE_CXX_STANDARD 17)

add_executable(moderncmake main.cpp)
add_executable(main1 main.cpp)
add_executable(main2 main.cpp)

add_subdirectory(car)
target_link_libraries(main1 PRIVATE cars)
# car目录下CMakeLists.txt

add_library(cars OBJECT
        car.cpp
)  # 生成cars目标,全局可见?怎么就全局可见了  虽然是add_library,但不是库因为用了OBJECT关键字

target_include_directories(cars PUBLIC .)  # 将cars目录添加到其公共包括目录中? 这样main.cpp就能包含cars.h文件不用提供相对路径了??? 这样操作之后并没有能这样#include"car.h"

3.4项目结构

推荐的项目结构

tmp6EC3.png

cmake:宏和函数,查找模块和一次性脚本 src:将存储的二进制文件和库的源代码 doc:用于构建文档 extern:从源代码构建的外部项目的配置 test:包含自动测试的代码

其中CMakeLists.txt文件应该存在于以下目录中:顶级项目目录、src、doc、extern和test

其中可执行文件和库的文件结构如下:

可执行文件的目录结构:

tmpDEC2.png

库的目录结构:

tmp4983.png

3.5 环境范围

3.5.1 识别操作系统

if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
if(CMAKE_SYSTEM_NAME STREQUAL "AIX")

内建变量 CMAKE_SYSTEM_NAME 在进行交叉编译的时候,CMAKE_HOST_SYSTEM_NAME CMAKE_HOST_SYSTEM_PROCESSOR CMAKE_HOST_SYSTEM_VERSION指代宿主机的信息,?不带有HOST的应该是指代目标系统

3.5.3 更多系统版本相关内建变量

ANDROID APPLE CYGWIN UNIX IOS WIN32 WINCE WINDOWS_PHONE CMAKE_HOST_APPLE CMAKE_HOST_SOLARIS CMAKE_HOST_UNIX CMAKE_HOST_WIN3

UNIX适用于Linux macOS 和 Cygwin,其中在32位或64位的Windows和MSYS中,WIN32和CMAKE_HOST_WIN32均为真。

使用cmake查询主机系统信息 cmake_host_system_information(RESULT <VARIABLE> QUERY <KEY>...)

3.6配置工具链

3.6.1设定C++标准

根据每个目标设置语言标准 set_property(TARGET <target> PROPERTY CXX_STANDARD <standard>) 也可以在整个项目中采用一个标准 set(CMAKE_CXX_STANDARD CXX13) 强制要求项目的语言标准,也就是基于项目设置的语言标准对编译器进行检查。 set(CMAKE_CXX_STANDARD_REQUIRED ON)

3.6.3特定于供应商的扩展

编译器实现的特性不尽相同,希望项目是扩展无关的可以关掉扩展 set(CMAKE_CXX_EXTENSIONS OFF)

3.6.4过程间优化

现代编译器能够在链接执行时进行优化,称为连接时优化。cmake支持查看是否支持连接时优化并开启优化。

include(CheckIPOSupported)
check_ipo_supported(RESULT ipo_supported)
if(ipo_supported)
    set(CMAKE_INTERPROCEDURAL_OPTIMIZATION True)
endif()

3.6.5检查支持的编译器特性

检查编译器是否支持某种特性

list(FIND CMAKE_CXX_COMPILER_FEATURES cxx_variable_teplates result)
if(result EQUAL -1)
    message(FATAL_ERROR "I really need variable templates.")
endif()

通常是建议直接查是否支持某个标准,例如:cxx_std_98、cxx_std_11、cxx_std_14、cxx_std_17、cxx_std_20 和 cxx_std_23。也可以在文档:cmake.org/cmake/help/… 中找到。

3.6.6编译测试文件

使用try_run或者try_compile测试。

3.7禁用项目内构建

建议使用:

if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
    message(FATAL_ERROR "In-source builds are not allowed")
endif()