当前位置: 首页 > news >正文

CMake笔记(简易教程)

CMake笔记

概述(需要提前了解的知识)

一个c/c++程序从代码到生成二进制文件,需要经历的几个关键步骤:预编译(预处理)、编译、汇编、连接 【编译链接的几个步骤】

  • 编译器:目前市面常见的编译器有msvc(微软)、gcc(gnu compiler collection)、clang。
    其中,msvc被集成在微软的visual studio当中,用于windows平台下的c++开发;gcc则是gnu/linux的编译工具集合,除了使用在gnu/linux下,也会平移到了windows系统中的MinGW中。而clang则是被主要用于macOS的开发。

  • Visual Studio(集成开发环境IDE:编辑器、编译器msvc、nmake、调试器wingdb),比较傻瓜的进行完整的编译流程,不需要开发者干预。但是,mvsc对c++的标准做了一定的自适配,有一些c++的特性、语法、api做了适当性的调整,可能会导致代码的跨平台兼容性差。

  • windows平台的Visal Studio替代方案:vscode(编辑器)、 MinGW(编译器、调试器)、cmake(编译工具)

  • vcode优点:开源、免费、插件丰富、可定制化极强、小巧;缺点:配置略复杂,部分插件需要科学上网

  • MinGW优点:对c++ 标准特性的支持比msvc高(msvc在某些C++特性上有一定的改动);缺点:编译流程基本靠命令行进行,对开发人员有一定门槛

  • cmake优点:跨平台、支持多种编译器:vc++、gcc、clang等,利于开发者掌握代码模块间的关联性;缺点:官方文档比较杂,没有优秀的官方范例,很多配置项有多种配置方式,一些配置项互相影响导致结果与官方文档说明的功能有差异


CMake

CMake是一个跨平台的c/c++ 构建系统,同时支持主流的c++编译器:gcc/g++、msvc、clang等。
通过一个CMakeLists.txt文件管控整个c++ 项目的代码结构、三方依赖、编译生成方式等,抹平了不同操作系统和编译器的差异。是目前主流的c++ 构建系统工具。


CMakeLists.txt文件

  • CMakeLists.txt文件是CMake进行编译链接的配置文件,保存了项目信息、代码模块关联性、链接库生成配置、可执行文件生成配置、头文件引用配置等,一般由开发者根据项目内容手动编写,保存在项目的根目录下

  • CMakeLists.txt主要结构:

    1. [项目信息] 一般包括CMake最低版本要求、项名称、版本信息等(可省略)
    2. [系统变量定义] 主要包括编译器编译参数,和CMake系统变量的定义(非必须)
    3. [自定义变量选项] 复杂项目中,可能需要手动设置一些宏或者模块选择,可通过自定义变量选项来进行配置(可省略)
    4. [子项目配置] 多模块开发涉及(非必须)
    5. [头文件、库文件引用配置] 应用第三方库或多模块开发涉及,非必须
    6. [编译] 一般add_executable或者add_library即可
    7. [链接] 链接库(动态库、静态库)连接至上一步生成的产物上


常用语法总览

语法解释其他注意事项
project工程名非必须
cmake_minimum_requiredcmake最低版本需求非必须
${}引用变量等
add_executable编译可执行文件参数1:目标名称
参数2:源文件列表
add_library编译库文件参数1:目标名称
参数2:STATIC SHARED动态静态
参数3:源文件列表
include_directories设置头文件目录一般引用第三方库时使用
link_directories设置库文件目录一般引用第三方库时使用
message输出文本信息调试输出信息
add_compile_options设置编译选项gcc、g++选项(有些选项可能无效)。
需要使用set(CMAKE_CXX_FLAGS …)来指定
set设置选项设置CMake系统变量值
aux_source_directory批量引用源文件搜寻目录下的全部源文件
options自定义选项
if(),elseif(),else(),endif()条件分支
target_link_options目标链接选项指定链接器的选项,有时候一些编译器的链接器需要专用的链接参数


SET常用选项

选项解释参数
CMAKE_BUILD_TYPE编译模式“Release”,“Debug” 。PS:微软msvc编译器下,该选项无效,需要有单独的参数进行指定,参见后文
EXECUTABLE_OUTPUT_PATH设置可执行文件输出目录
CMAKE_ARCHIVE_OUTPUT_DIRECTORY设置静态库模块导入文件dll.a(lib)输出目录
CMAKE_RUNTIME_OUTPUT_DIRECTORY设置链接库输出目录
CMAKE_LIBRARY_OUTPUT_DIRECTORY设置链接库输出目录
LIBRARY_OUTPUT_PATH设置静态库、动态库生成路径
CMAKE_INSTALL_PREFIX设置make install的安装目录绝对路径
BUILD_SHARED_LIBS动态库生成开关ON/OFF
CMAKE_CXX_FLAGS设置编译选项编译选项

PS:链接库输出选项

  1. CMAKE_ARCHIVE_OUTPUT_DIRECTORYCMAKE_RUNTIME_OUTPUT_DIRECTORYCMAKE_LIBRARY_OUTPUT_DIRECTORYLIBRARY_OUTPUT_PATH 在Linux和Windows下以及不同的编译器的产生的效果不同,可能与CMake版本或者系统差异有关,需要酌情调用,或者全部调用**
  2. 调用add_compile_options来设置编译选项可能会不生效(因编译器而定)这时候可以使用CMAKE_CXX_FLAGS变量来设置


命令行常用选项

选项说明其他注意事项
-version显示cmake版本信息
-help显示cmake命令行帮助信息
-G选择编译器MinGW编译器一般是"MinGW Makefiles"
-D[选项]命令行临时修改选项,[选项]参见SET常用选项如果命令行和CMakeLists.txt里有同样的选项,那么命令行选项设置会失效
–build在当前目录下执行编译
–target install与–build同时使用,执行安装需要提前设置CMAKE_INSTALL_PREFIX
–parallel并行编译开关与–build参数同时调用



范例:

1. 范例1(windows msvc)
# 使用VisualStudio 2017版本进行编译
# CMakeLists.txt与build目录同级
mkdir build
cd build
cmake .. -G "Visual Studio 2017 15 Win64" -DCMAKE_INSTALL_PREFIX=d:\package
cmake --build . --parallel --target install --config Release

说明:

cmake … -G “Visual Studio 2017 15 Win64” -DCMAKE_INSTALL_PREFIX=d:\package

  • cmake … 从上层目录寻找MakeLists.txt
  • -G “Visual Studio 2017 15 Win64” 指明使用vs2017(msvc15) x64 编译器进行编译
  • -DCMAKE_INSTALL_PREFIX=d:\package 项目最终安装在d:\package目录下

cmake --build . --parallel --target install --config Release

  • –build . 从当前目录开始编译
  • –parallel 并行编译(多线程编译)
  • –target install 编译完以后进行安装,安装至CMAKE_INSTALL_PREFIX指定的目录
  • –config Release 微软msvc编译器需要在编译时指定Debug或Release

2. 范例2(Windows gnu/c++)
#!/bin/bash
# CMakeLists.txt与build目录同级
mkdir build
cd build
cmake .. -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=d:\package -DCMAKE_BUILD_TYPE=Release
cmake --build . --parallel --target install

说明:

cmake … -G “MinGW Makefiles” -DCMAKE_INSTALL_PREFIX=d:\package

  • cmake … 从上层目录寻找MakeLists.txt
  • -G “MinGW Makefiles” 指明使用MinGW的g++进行编译
  • -DCMAKE_INSTALL_PREFIX=d:\package 项目最终安装在d:\package目录下
  • -DCMAKE_BUILD_TYPE=Release 使用Release模式进行编译

cmake --build . --parallel --target install

  • –build . 从当前目录开始编译
  • –parallel 并行编译(多线程编译)
  • –target install 编译完以后进行安装,安装至CMAKE_INSTALL_PREFIX指定的目录
  • –config Release 微软msvc编译器需要在编译时指定Debug或Release



详细解析

[项目信息]

project([NAME])项目名称

插入字符串即可\

cmake_minimum_required(VERSION 3.0)cmake需求版本

最低版本号,根据所使用的cmake版本可支持的特性来决定,本篇所涉及的特性使用3.0以上即可


[变量定义]

set([NAME] [VALUE])设定变量

一般复杂项目时,部分字符串、文件名会反复调用,定义变量保存,方便编写,使用${NAME}可得到变量值


message(${NAME})输出内容

在cmake准备阶段,message会输出指定变量或者宏的值,方便开发者确认详细配置内容\

[自定义配置选项]

option([NAME] [DESCRIPTION] [DEFAULT_VALUE])设置自定义选项

自定义执行选项,可在cmake执行阶段,通过命令行改变选项,一般配合if()else()进行编译分支

NAME-选项名称
DESCRIPTION-描述字符串
DEFAULT_VALUE-默认值ON/OFF或者字符串\

if([表达式])…elseif([表达式])…else()…endif() 条件分支

关系运算符解释
AND
NOT
OR
EXIST目录、文件是否存在
EQUAL变量等于
LESS变量小于
GREATER变量大于
STREQUAL字符串等于
STRELESS字符串小于
STREGREATER字符串大于

[子项目配置]

add_subdirectory([DIR])添加子项目

运用在多模块项目中,主模块CMakeLists.txt中应用其他模块,DIR目录为绝对路径,该目录下必须要有对应的源文件和CMakeLists.txt\

[头文件、库文件引用配置]

include_directories([DIR])添加头文件目录

一般用在引用第三方模块\

link_directories([DIR])添加链接库目录

一般用在引用第三方模块\

[编译]

add_executable([OUT] [SOURCE FILE LIST])编译可执行文件

  • OUT-可执行文件名
  • SOURCE FILE LIST-编译OUT需要的源文件列表

add_library([OUT] [TYPE] [SOURCE FILE LIST])编译链接库

  • OUT-编译输出的链接库名称,PS:cmake采用Linux命名规则,链接库会自动添加"lib"前缀
  • TYPE-链接库类型:STATIC-静态库,SHARED-动态库;如果不指定,则默认静态库
  • SOURCE FILE LIST-编译OUT需要的源文件列表

aux_source_directory([DIR] [NAME])查找目录中所有源文件

在调用add_executable或add_library时,需要列出全部的源文件。大项目中,源文件如果很多,一个一个添加很复杂,可以使用aux_source_directory自动扫描[DIR]下的全部源文件,赋值给[NAME]变量,再通过NAME引用

aux_source_directory(${CMAKE_SOURCE_DIR}/src CPPS)//扫描CMakeLists.txt所在目录下src目录下的全部源文件,定义为CPPSadd_executable(out ${CPPS})  //使用CPPS来编译可执行文件out

[链接]

target_link_libraries([OUT] [LIBS])链接库文件

将LIBS的全部库文件链接到[OUT]可执行文件、库文件中

  1. target_link_libraries必须写在add_executable和add_library之后
  2. cmake采用的是Linux命名规则,所以指定LIBS时,如果只写库名,会在库名前加lib,默认优先查找静态库,再查找动态库
  3. LIBS可以指定完整的库文件名
  4. 不建议在一条target_link_libraries中混合使用2,3中的静态、动态、自动查找方式,否则可能会导致未知错误

-Wl,-rpath选项的用法

设置二进制文件bin的动态库加载路径

## 指定bin的链接器参数
set_target_properties(bin PROPERTIES LINK_FLAGS "-Wl,-rpath=./")  
target_link_options(bin PRIVATE -Wl,-rpath=$ORIGIN)## 在使用"./"时,又是不一定生效,所以需要使用ld链接器的参数$ORIGIN来指定当前路径


-------------------- --------------------

Cmake 命令

以下以编译第三方开源库为例

构建编译系统 win/msvc

#一般来说,需要开发者在CMakeLists.txt所在同级目录创建一个构建系统目录
mkdir build 
cd build# cmake .. 指定CMakeLists.txt所在路径
# -G选项可以指定编译器与32位或64位,可以使用"make -G"命令列举当前cmake版本支持的全部编译器版本
# -DCMAKE_INSTALL_PREFIX 指定编译的二进制文件、头文件路径安装目录
# -DBUILD_SHARED_LIBS=OFF 禁制编译动态库,只生成静态库
cmake .. -G "Visual Studio 15 2017 Win64" -DCMAKE_INSTALL_PREFIX=/d/library -DBUILD_SHARED_LIBS=OFF# --build . 对当前目录下的构建系统,进行编译(根据所选的编译器)
# --target install 编译完成后,进行安装,安装路径为上一步DCMAKE_INSTALL_PREFIX所指定的路径
# --config=release 指定编译类型为release模式(或debug)
cmake --build . --target install --config=release

构建编译系统 win/mingw

#一般来说,需要开发者在CMakeLists.txt所在同级目录创建一个构建系统目录
mkdir build 
cd build# cmake .. 指定CMakeLists.txt所在路径
# -G选项可以指定编译器与32位或64位,可以使用"make -G"命令列举当前cmake版本支持的全部编译器版本
# -DCMAKE_INSTALL_PREFIX 指定编译的二进制文件、头文件路径安装目录
# -DBUILD_SHARED_LIBS=OFF 禁制编译动态库,只生成静态库
cmake .. -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=/d/library -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release# --build . 对当前目录下的构建系统,进行编译(根据所选的编译器)
# --target install 编译完成后,进行安装,安装路径为上一步DCMAKE_INSTALL_PREFIX所指定的路径
cmake --build . --target install

构建编译系统 linux/默认配置

#一般来说,需要开发者在CMakeLists.txt所在同级目录创建一个构建系统目录
mkdir build 
cd build# cmake .. 指定CMakeLists.txt所在路径
# -DCMAKE_INSTALL_PREFIX 指定编译的二进制文件、头文件路径安装目录
# -DBUILD_SHARED_LIBS=OFF 禁制编译动态库,只生成静态库
cmake .. -DCMAKE_INSTALL_PREFIX=/d/library -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release# --build . 对当前目录下的构建系统,进行编译(根据所选的编译器)
# --target install 编译完成后,进行安装,安装路径为上一步DCMAKE_INSTALL_PREFIX所指定的路径
cmake --build . --target install

PS:
msvc(visual studio)与其他编译器不同。设置debug/release模式时,msvc是在编译步骤(cmake --build .)使用–config参数来指定debug/release。
而其他编译器,则是在生成构建系统时(cmake …),使用-DCMAKE_BUILD_TYPE来指定debug/release



CMake与交叉编译

由于每个交叉编译链的差异,以及个人部署的环境不同,所以CMake的交叉编译环境,需要根据系统差异进行反复测试才能调试通过
以下为官方文档,且较为通用的配置
ps:在较高版本的cmak下,建议将设置交叉编译工具的命令放置在project()之前,否则cmake可能仍旧会使用系统默认的编译器

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)set(ARMROOT "/home/ubuntu/arm-linux-gnueabi/")//设置编译链的主目录(非必须,如果编译出错时,可以尝试加上)
set(CMAKE_SYSROOT ${ARMROOT})//设置C编译器绝对路径
set(CMAKE_C_COMPILER ${ARMROOT}/bin/arm-linux-gnueabi-gcc)
//设置C++编译器绝对路径
set(CMAKE_CXX_COMPILER ${ARMROOT}/bin/arm-linux-gnueabi-g++)set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)//project(xxxx)
....
....
....



http://www.xdnf.cn/news/337177.html

相关文章:

  • 【探寻C++之旅】第十三章:红黑树
  • 第8章-3 查询性能优化1
  • kotlin @JvmStatic注解的作用和使用场景
  • 《信息论与编码课程笔记》——信源编码(1)
  • 动态SQL与静态SQL
  • threejs 添加css3d标签 vue3
  • [数据处理] 6. 数据可视化
  • 商业中的人工智能 (AI) 是什么?
  • 从0到1:用Lask/Django框架搭建个人博客系统(4/10)
  • 每日学习:DAY24
  • 第三节第一部分:Static修饰类变量、成员变量
  • pip下载tmp不够
  • ASP.NET Core 中实现 Markdown 渲染中间件
  • 信创生态核心技术栈:数据库与中间件
  • 《智能网联汽车 自动驾驶功能场地试验方法及要求》 GB/T 41798-2022——解读
  • Mac 平台 字体Unicode范围分析器
  • 使用迁移学习的自动驾驶汽车信息物理系统安全策略
  • MySQL数据库创建、删除、修改
  • Android NDK版本迭代与FFmpeg交叉编译完全指南
  • ubuntu24.04安装anaconda
  • SwiftData 数据持久化解决方案
  • 如何使用极狐GitLab 软件包仓库功能托管 python?
  • git设置tabsize
  • Kubernetes client-go 客户端类型与初始化指南
  • 驱动开发硬核特训 · Day 30(上篇):深入理解 I2C 总线驱动模型(以 at24 EEPROM 为例)
  • Dynamic Causal Modeling在医疗AI领域的编程案例与应用研究
  • 〖 Linux 〗解决 VS Code 远程连接服务器的常见问题
  • iPhone手机连接WiFi异常解决方法
  • 【hadoop】案例:Sqoop迁移仓库数据
  • 5、开放式PLC梯形图编程组件 - /自动化与控制组件/open-plc-programming