Sirius' blog Sirius' blog
首页
  • 学习笔记

    • 《C++》
    • 《MATLAB》
    • 《Python》
  • 学习笔记

    • 《Git》
    • 《CMake》
  • 技术文档
  • 博客搭建
  • 学习
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Sirius0v0

怕什么真理无穷,进一寸有一寸的欢喜
首页
  • 学习笔记

    • 《C++》
    • 《MATLAB》
    • 《Python》
  • 学习笔记

    • 《Git》
    • 《CMake》
  • 技术文档
  • 博客搭建
  • 学习
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 初识CMake:学习笔记与速查
    • 从可执行文件到库
      • 编译单个文件
      • 构建和链接静态库
      • 构建和链接动态库
      • 条件句控制编译
      • 显示选项
      • 设置编译器选项
      • 语言设定标准
      • 关于目标的一些选项汇总
  • CMake中常见的内置变量
  • 现代CMake命令行及CMakeLists.txt写法
  • CMake设置对象属性
  • CMake链接第三方库的方法
  • 使用CMake模块化项目
  • 《CMake》学习笔记
Sirius0v0
2023-02-21
目录

初识CMake:学习笔记与速查

# CMake学习

主要参考CMake菜谱 (opens new window)教程总结的学习笔记,仅供笔者参考,完整教程请移步CMake菜谱 (opens new window) 😃

# 从可执行文件到库

# 编译单个文件

# 设置CMake所需的最低版本
cmake_minimum_required (VERSION 3.8)

# 声明项目的名称和支持的编程语言(CXX代表C++)
project(hello_cmake_world LANGUAGES CXX)

# 将源代码添加到此项目的可执行文件。
add_executable (hello-cmake "hello_cmake_world.cpp")

该文件与源文件hello_cmake_world.cpp放在一起,执行

mkdir -p build
cd build
cmake ..
cmake --build .

注意:

  1. CMake语言不区分大小写,但是参数是区分大小写的

  2. CMake中,C++是默认的编程语言。不过,建议使用LANGUAGES选项在project命令中显式地声明项目的语言

  3. 使用cmake -help查看完整的帮助信息

  4. # mkdir -p sirius_build
    # cd sirius_build
    # cmake ..
    # 以上构建步骤可用跨平台命令代替
    # -H表示当前目录中搜索根CMakeLists.txt文件
    # -Bsirius_build告诉CMake在一个名为sirius_build的目录中生成所有的文件
    cmake -H. -Bsirius_build
    

# 构建和链接静态库

cmake_minimum_required (VERSION 3.8)
project(hello_cmake_world LANGUAGES CXX)

# 创建目标——静态库。库的名称和源码文件名相同
add_library(message
  STATIC
    "Message.hpp"
    "Message.cpp"
  )

add_executable (hello-cmake "hello_cmake_world.cpp")
# 最后需要将目标库链接到可执行目标
target_link_libraries(hello-cmake message)

# 构建和链接动态库

# 与构建静态库一样,只需将STATIC改为SHARED
add_library(message
  SHARED
    "Message.hpp"
    "Message.cpp"
  )

如果考虑跨平台,有两种方法:

  1. 可为动态库的头文件添加:

    #pragma once
    
    /* 添加一下内容以实现跨平台 */
    #ifdef _WIN32
        #ifdef MessageDLL
            #define MessageDLL __declspec(dllexport)
        #else
            #define MessageDLL __declspec(dllimport)
        #endif
    #else
        #define MessageDLL
    #endif
    //////////END////////////
    
    class MessageDLL Message {
    public:
        // ... DO SOMETING ...
    };
    
  2. 在CMakeLists.txt里添加set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

在 Windows 平台中,导出动态库时除了会生成 .dll 动态库之外还会生成一个.lib文件。这个.lib文件和静态库的.lib文件不同,它里面不保存代码生成的二进制文件,而是所有需要导出符号的符号表。

如果希望将一个符号(symbol)导出(这里的符号可以指类、函数等各种类型):

​ 方法一:需要在其前面加上 __declspec(dllexport) 标志。这样这个符号的相关信息就会存在于.lib中的符号表中; ​ 方法二:在CMakeLists.txt里添加set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

# 条件句控制编译

先看一个例子:

cmake_minimum_required(VERSION 3.8)
project(hello_cmake_world LANGUAGES CXX)

# 引入变量USE_LIBRARY,message打印相关信息
set(USE_LIBRARY OFF)
message(STATUS "Compile sources into a library? ${USE_LIBRARY}")
# BUILD_SHARED_LIBS在下面第二点有具体解释
set(BUILD_SHARED_LIBS OFF)

# 引入变量包括*.hpp\*.cpp文件
list(APPEND _sources "Message.hpp" "Message.cpp")

# 逻辑控制编译
if (USE_LIBRARY)
	add_library(message ${_sources})
	add_executable(hello-cmake "hello_cmake_world.cpp")
	target_link_libraries(hello-cmake message)
else()
	add_executable(hello-cmake "hello_cmake_world.cpp" ${_sources})
endif()
  1. 使用set为变量设置值,其中逻辑变量可以是以下几种之一:
    • 逻辑true:1、ON、YES、true、Y或非零数;
    • 逻辑false:0、OFF、NO、false、N、IGNORE、NOTFOUND、空字符串或以-NOTFOUND为后缀。
  2. BUILD_SHARED_LIBS是CMake的一个全局标志,可以决定为生成动态库还是静态库。如果为false或未定义,将生成一个静态库;
  3. _sources变量是一个局部变量,不应该在当前范围之外使用,可以在名称前加下划线。

# 显示选项

上一节中(条件句控制编译)用硬编码控制逻辑,只能从内部修改。

本节使用option()命令,以选项的形式在外部设置编译逻辑

语法:

option可接受三个参数:

option(<option_variable> "help string" [initial value])
  • <option_variable>变量名
  • "help string"在终端可见的帮助性文字
  • [initial value]选项的默认值,可以是ON或OFF。

因而对于上一节中的CMakeLists.txt,只需将set(USE_LIBRARY OFF)使用option()代替,并设置默认值即可:

option(USE_LIBRARY "Compile sources into a library" OFF)

现在,可以通过CMake的-DCLI选项,将信息传递给CMake来切换库的行为

cmake -D USE_LIBRARY=ON ..

-D开关用于为CMake设置任何类型的变量:逻辑变量、路径等等。


如果有依赖关系,如:用户设置不构建库,但设置了构建动态库,此时应该不构建库。CMake提供cmake_dependent_option()命令用来定义依赖于其他选项的选项:

需要引入CMakeDependentOption模块

语法:

cmake_dependent_option可接受五个参数:

cmake_dependent_option(<OPTION_NAME> "help string" <default_value> <depends> <force_value>)
  • <OPTION_NAME>变量名

  • "help string"帮助性文字

  • <default_value>默认值

  • <depends>该值为true时 开启此选项并设置为默认值,否则强制该选项默认值为 <force_value>

    <depends>可以用分号代表与的关系,例如:

    "ENABLE_BUILD;NOT DISABLE_TESTING"表示(ENABLE_BUILD && (!DISABLE_TESTING) )

因而添加是否编译为库和是否编译为动态库两个选项时,可修改为:

option(USE_LIBRARY "Compile sources into a library" OFF)

include(CMakeDependentOption)
# 当USE_LIBRARY为ON时,MAKE_STATIC_LIBRARY是;MAKE_STATIC_LIBRARY是
# 当USE_LIBRARY为ON时,MAKE_STATIC_LIBRARY是;MAKE_STATIC_LIBRARY是
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
)

# 设置编译器选项

参考如下一个例子:

cmake_minimum_required(VERSION 3.8)
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}
  )
  
add_executable(compute-areas compute-areas.cpp)

target_compile_options(compute-areas
  PRIVATE
    "-fPIC"
  )
  
target_link_libraries(compute-areas geometry)
  1. 编译选项target_compile_options()可以添加三个级别的可见性:INTERFACE、PUBLIC和PRIVATE;
    • PRIVATE,编译选项应用于指定的目标,不会传递给与目标相关的目标。
    • INTERFACE,给定的编译选项将只应用于指定目标,并传递给与目标相关的目标。
    • PUBLIC,编译选项将应用于指定目标和使用它的目标。

# 语言设定标准

set_target_properties(animals
  PROPERTIES
    CXX_STANDARD 14
    CXX_EXTENSIONS OFF
    CXX_STANDARD_REQUIRED ON
    POSITION_INDEPENDENT_CODE 1
)

这里为目标设置了一些属性:

  • CXX_STANDARD,会设置我们想要的C++标准。
  • CXX_EXTENSIONS,告诉CMake,只启用ISO C++标准的编译器标志,而不使用特定编译器的扩展。
  • CXX_STANDARD_REQUIRED,指定所选标准的版本。如果这个版本不可用,CMake将停止配置并出现错误。当这个属性被设置为OFF时,CMake将寻找下一个标准的最新版本,直到一个合适的标志。这意味着,首先查找C++20,然后是C++17,然后是C++14。

如果语言标准是所有目标共享的全局属性,那么可以将CMAKE_<LANG>_STANDARD、CMAKE_<LANG>_EXTENSIONS和CMAKE_<LANG>_STANDARD_REQUIRED变量设置为相应的值。所有目标上的对应属性都将使用这些设置。

# 关于目标的一些选项汇总

target_include_directories(myapp PUBLIC /path)	# 添加头文件搜索目录
target_link_libraries(myapp PUBLIC hellolib)			# 添加要链接的库
target_add_definitions(myapp PUBLIC MY_MACRO=1)			# 添加一个宏定义
target_add_definitions(myapp PUBLIC -DMY_MACRO=1)		# 与MY_MACRO=1等价
target_compile_options(myapp PUBLIC -fopenmp)			# 添加编译器命令行选项
target_sources(myapp PUBLIC hello.cpp other.cpp)		# 添加要编译的源文件

## 以下指令不推荐使用
include_directories(/path/to/include)
link_directories(/opt/cuda)			# 添加库的搜索路径
add_definitions(MY_MACRO=1)
add_compile_options(-fopenmp)
编辑 (opens new window)
#CMake
上次更新: 2023/08/14, 19:51:00
CMake中常见的内置变量

CMake中常见的内置变量→

最近更新
01
ipopt优化库配置及使用
07-21
02
ubuntu离线安装包的方法
07-21
03
其它控件的使用
03-05
更多文章>
Theme by Vdoing | Copyright © 2020-2024 Sirius0v0 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式