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

【CMake】CMake构建项目入门

一、CMake介绍

CMake 是一个跨平台的自动化构建工具,用于管理软件项目的编译过程。它通过简单的配置文件(CMakeLists.txt)生成特定平台的构建文件(如 Makefile、Visual Studio 项目),让开发者可以专注于代码本身而非平台差异。

CMake官方网站:www.cmake.org

1.1 CMake 安装

这里介绍Ubuntu下安装Cmake,直接使用下述命令安装即可:

sudo apt install cmake

安装完成之后,直接在bash中查看CMake版本,我的版本是3.22.1

cmake -version

在这里插入图片描述

二、使用Cmake写一个Hello World

创建一个main.cpp,写上最简单的的程序——Hello World

#include<iostream>int main(){std::cout << "Hello World !" << std::endl;return 0;
}

在同级目录下创建一个CMakeLists.txt,用于配置CMake

touch CMakeLists.txt

CMakeLists中写入对应内容

cmake_minimum_required(VERSION 3.10)  # 添加最低版本要求PROJECT(hello)  # 创建项目,变量为hello_SOURCE_DIRSET(SRC_LIST main.cpp)  # 设置源文件列表# 打印构建目录信息
MESSAGE(STATUS "This is BINARY dir: ${hello_BINARY_DIR}")# 打印源文件目录信息
MESSAGE(STATUS "This is SOURCE dir: ${hello_SOURCE_DIR}")# 添加可执行文件
ADD_EXECUTABLE(hello ${SRC_LIST})

这个 CMakeLists.txt 的主要功能是:

  1. 设置项目名称为 “hello”
  2. 指定源文件为当前目录下的 main.cpp
  3. 打印构建目录和源文件目录的路径信息
  4. 创建名为 “hello” 的可执行文件

对于上述内容,在后续会讲解对应的语法,这里先看看CMake的整体流程


我们当前的项目结构是这样的,非常简单

在这里插入图片描述

我们在当前路径下,使用下述命令让cmake构建起来

cmake .

运行后,打印出来了我们的构建目录和源文件目录,并且在当前目录生成了Makefile

在这里插入图片描述

tree

在这里插入图片描述

使用make命令让Makefile跑起来

make

在这里插入图片描述

此时在当前路径下就生成了可执行文件hello

在这里插入图片描述

运行可执行文件,得到了Hello World!的打印

在这里插入图片描述

三、CMake语法介绍

在上述的工程中,我们用到了一些最基本的CMake语法,下面依次介绍

PROJECT 关键字

可以⽤来指定⼯程的名字和⽀持的语⾔,默认⽀持所有语⾔

  • PROJECT (HELLO) 指定了⼯程的名字,并且⽀持所有语⾔—建议
  • PROJECT (HELLO CXX) 指定了⼯程的名字,并且⽀持语⾔是C++
  • PROJECT (HELLO C CXX) 指定了⼯程的名字,并且⽀持语⾔是C和C++

该指定隐式定义了两个CMAKE的变量

  1. _BINARY_DIR,本例中是hello_BINARY_DIR
  2. _SOURCE_DIR,本例中是 hello_SOURCE_DIR

MESSAGE关键字就可以直接使⽤者两个变量,当前都指向当前的⼯作⽬录,后⾯会讲外部编译

如果改了⼯程名,这两个变量名也会改变,比如下面的例子,变量就是hello2了

cmake_minimum_required(VERSION 3.10)  # 添加最低版本要求PROJECT(hello2)  # 创建项目,变量为hello_SOURCE_DIRSET(SRC_LIST main.cpp)  # 设置源文件列表# 打印构建目录信息
MESSAGE(STATUS "This is BINARY dir: ${hello2_BINARY_DIR}")# 打印源文件目录信息
MESSAGE(STATUS "This is SOURCE dir: ${hello2_SOURCE_DIR}")# 添加可执行文件
ADD_EXECUTABLE(hello2 ${SRC_LIST})

编译生成的可执行文件的名称也改为了hello2

在这里插入图片描述

SET 关键字

  • SET关键字是用于设置变量名的,比如上述的SET(SRC_LIST main.cpp),其中SRC_LIST就代表了main.cpp

  • SET关键字后面也可以加入多个文件,可以使用空格隔开,比如

SET(SRC_LIST main.cpp a.cpp b.cpp)

MESSAGE 关键字

  • MESSAGE 是 CMake 的一个输出信息命令,用于在 CMake 配置(生成构建文件)阶段向控制台打印信息

主要包含三种信息

  1. SEND_ERROR,产生错误,生成过程中被跳过
  2. STATUS,普通状态信息,用于提示配置过程
  3. FATAL_ERROR,致命错误,立即终止所有的cmake过程

ADD_EXECUTABLE 关键字

  • 生成可执行文件,比如上述的ADD_EXECUTABLE(hello ${SRC_LIST}),就是将main.cpp源文件编译为hello这个可执行文件

  • 上述程序使用的是自定义的变量名,也可以直接写成ADD_EXECUTABLE(hello main.cpp)

  • 工程名称的PROJECT(hello)和我们这里的ADD_EXECUTABLE(hello ${SRC_LIST})没有关系,名字完全可以不同,没有影响

语法的基本原则

  • 变量使用${变量名}的方法取值,但是在IF控制语句中是直接使用变量名,这里需要注意

  • 指令(参数1 参数2 参数3 …),参数之间使用括弧,参数之间使用空格或者分号进行分开,例如我们的ADD_EXECUTABLE命令可以这样写:

ADD_EXECUTABLE(hello main.cpp a.cpp b.cpp)

或者

ADD_EXECUTABLE(hello main.cpp;a.cpp;b.cpp)
  • 指令是大小写不区分的,但是参数和变量是大小区分的,不过通常推荐使用全大写来书写指令

语法注意事项

  • SET(SRC_LIST main.cpp)可以改写为SET(SRC_LIST "main.cpp"),如果文件名中含有空格,则必须使用双引号,比如SET(SRC_LIST "m ain.cpp")

  • ADD_EXECUTABLE(hello main)后缀可以不写,此时cmake会自动查找.c.cpp后缀的文件,比如main.cmain.cpp,但是通常情况下我们推荐写上,防止存在main.cmain.cpp两个文件

四、内部构建和外部构建

我们上述使用cmake进行构建就是内部构建,内部构建的意思就是在当前文件夹下进行构建:

cmake .

内部构建产生的临时文件特别多,不方便清理,我们下面介绍外部构建,外部构建就是将生成的临时文件全部放到build文件夹内部,这样项目结构更加清晰,并且利于清理


同样的main.cpp,我们进行外部构建,先在当前目录下创建一个build文件夹,进入到build目录下

mkdir build
cd build

build的上级目录存在CMakeLists.txt,因此使用..表示上级目录

cmake ..

对于外部编译,这里的内置变量hello2_BINARY_DIRhello2_SOURCE_DIR就不同了,可以发现配置路径变成了当前路径下的build文件夹内

在这里插入图片描述

这样,配置文件和源文件就分开了

在这里插入图片描述

如果cmake指定路径不对,则会报错,比如cmake .,提示找不到CMakeLists.txt

在这里插入图片描述

后续步骤和内部构建是一样的,在build目录下使用Makefile编译,然后运行可执行文件

在这里插入图片描述

五、添加更多工程配置

为了让我们的Hello World更像一个工程,我们还需要添加下面的几个文件/文件夹

  1. src文件夹,用于存放工程的源代码
  2. doc文件夹,用于存放工程的文档
  3. READEMECOPYRIGHT,主要是一些项目说明和版权说明
  4. runhello的脚本,用于调用可执行可执行文件hello
  5. 将构建好的目标文件放入构建目录下的bin子目录
  6. doc目录的内容以及READMECOPYRIGHT安装到usr/share/doc/cmake路径下

5.1 将目标文件放入构建目录的bin子目录

每个目录下都要有一个CMakeLists.txt说明,整体的项目结构如下

在这里插入图片描述

  • 外层的CMakeLists.text如下,主要是定义项目的名称以及项目的子目录srcbin
  • ADD_SUBDIRECTORY 命令用于将子目录中的 CMake 项目纳入当前构建系统,子目录必须含有CMakeLists.txt文件
PROJECT(HELLO)ADD_SUBDIRECTORY(src bin)

内层的CMakeLists.txt如下,添加了可执行文件hello

ADD_EXECUTABLE(hello main.cpp)

ADD_SUBDIRECTORY 关键字

ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
  • 这个指令用于向当前工程添加存放源文件的子目录,并且可以指定中间二进制和目标二进制存放的位置

  • EXCLUDE_FROM_ALL函数是将写的目录从编译中排出,如程序的`example

  • 上述的ADD_SUBDIRECTORY(src bin)的意思是将src子目录加入工程并且指定编译输出(包含编译中间结果)路径为bin目录,如果不指定二进制文件存放位置,那么文件默认存放在build/src目录中


进入到build路径,执行cmake ..,查看到我们的二进制文件都存放在了自动生成的bin文件夹中

在这里插入图片描述

更改二进制的保存路径

  • SET 指令重新定义 EXECUTABLE_OUTPUT_PATHLIBRARY_OUTPUT_PATH 变量 来指定最终的⽬标⼆进制的位置

  • 比如,我们想让目标二进制的位置在build/bin路径下,我们可以这样写:

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR/bin})
  • 比如,我们想让生成的库文件放在build/lib里面,我们可以这样写:
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR/lib})

更改上述外层的CMakeLists.txt,可以不指定ADD_SUBDIRECTOR中二进制的生成路径了,如下

PROJECT(HELLO)SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)ADD_SUBDIRECTORY(src)

构建的项目结构如下,效果就是目标二进制文件在build/bin路径下,中间二进制文件在build/src下,因为这里没有选择生成库文件,因此就没有build/lib文件夹

在这里插入图片描述

5.2 安装

  • 一种是从代码编译后直接make install 安装
  • 另一种是打包时指定目录安装
    • 比如make install DESTDIR=/tmp/test
    • 比如./configure -prefix=/usr/local/test

如何安装上述hello项目

需要使用到一个新的关键字INSTALL

  • INSTALL关键字可以用于安装二进制文件、动态库、静态库、目录、文件、脚本等
  • 可以配合CMake的变量CMAKE_INSTALL_PREFIX来指定安装的路径,CMAKE_INSTALL_PREFIX 默认是在 /usr/local/
安装文件COPYRIGHTREADME

比如我们将上述的READMECOPYRIGHT安装到/usr/local/share/doc/cmake/下,新增READMECOPYRIGHT

touch README COPYRIGHT

在这里插入图片描述

修改外层CMakeLists.txt,安装文件使用的是FILES

PROJECT(HELLO)SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/)
ADD_SUBDIRECTORY(src)

进入到build路径下,启动cmake ..,编译make,然后执行,这里需要有权限

sudo make install

查看安装的路径下的文件,与预期配置相符

在这里插入图片描述

也可以在配置的时候重新指定CMAKE_INSTALL_PREFIX的路径,比如改为/usr,这样相对路径就是/usr开头的

cmake -D CMAKE_INSTALL_PREFIX=/usr

配置是输出信息,显示安装的文件在/usr/share/doc/cmake路径下,成功改变了相对路径

在这里插入图片描述

安装脚本runhello.sh

安装脚本使用的是PROGRAMS,安装到usr/bin路径下,这里我们使用绝对路径试试

INSTALL(PROGRAMS runhello.sh DESTINATION /usr/bin)

在这里插入图片描述

进入build路径,执行下述命令

cmake .. && make && sudo make install

可以查看到,安装到了/usr/bin路径下

ls /usr/bin | grep hello

在这里插入图片描述

安装doc目录下的所有文件
  • 使用DIRECTORY可以递归安装整个目录

在这里插入图片描述

  • 修改CMakeLists.txt,我们把目录安装到usr/local/share/doc/cmake中,与READMECOPYRIGHT放在一起
INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake/)

执行构建 & 编译 & 安装命令

cmake .. && make && sudo make install

查看文件都安装到了正确的位置
在这里插入图片描述

⽬录名以/结尾:将这个⽬录中的内容安装到⽬标路径

  1. ⽬录名不以/结尾:这个⽬录将被安装为⽬标路径下的
  2. ⽬录名以/结尾:将这个⽬录中的内容安装到⽬标路径

如果上述使用doc安装,我们测试一下:

INSTALL(DIRECTORY doc DESTINATION share/doc/cmake/)

实际上是doc这个文件夹安装到里面了

在这里插入图片描述

并且这个文件夹内部的所有文件都被一起安装过去了

在这里插入图片描述

更多资料:https://github.com/0voice

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

相关文章:

  • 【华为OD】MVP争夺战(C++、Java、Python)
  • 多表查询-4-外连接
  • 使用包管理工具CocoaPods、SPM、Carthage的利弊与趋势
  • 【机器学习入门巨详细】(研0版)二创OPEN MLSYS
  • CTFHub————Web{信息泄露[Git泄露(Stash、Index)]}
  • Linux进程管理的核心:task_struct中的双链表与网状数据结构
  • 数据结构之并查集和LRUCache
  • Waiting for server response 和 Content Download
  • Pandas 模块之数据的读取
  • 骁龙8 Gen4前瞻:台积3nm工艺如何平衡性能与发热
  • 【leetcode】709. 转换成小写字母
  • 赋能家庭、行业与工业场景,智微智能新一代Twin Lake 全栈智能终端发布
  • 用一张“冰裂纹”石墨烯薄膜,让被动散热也能做 AI 推理——基于亚波长裂纹等离激元的零功耗温度-逻辑门
  • 基于YOLO11的垃圾分类AI模型训练实战
  • MCP上的数据安全策略:IAM权限管理与数据加密实战
  • wedo智能车库-----第31节(免费分享图纸)
  • 独立开发第二周:构建、执行、规划
  • 【Lucene/Elasticsearch】 数据类型(ES 字段类型) | 底层索引结构
  • 记录Ruoyi-vue-pro芋道商城部署过程
  • C++类模版2
  • BERT:双向Transformer革命 | 重塑自然语言理解的预训练范式
  • 事件驱动设计:Spring监听器如何像咖啡师一样优雅处理高并发
  • Linux的NetworkManager的nmcli配置网桥(bridge) 笔记250712
  • Linux操作系统之进程间通信:共享内存
  • 同步、异步、阻塞、非阻塞之间联系与区别
  • SOEM build on ubuntu
  • 2025Stockapi股票数据接口,股票实时数据,技术指标macd,kdj,cci技术指标算法,集合竞价数据,龙虎榜数据接口
  • 【图像处理基石】如何入门大规模三维重建?
  • Gameplay - 独立游戏Celeste的Player源码
  • Unity开发中常用的洗牌算法