Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >CMAKE入门实战

CMAKE入门实战

作者头像
公众号guangcity
发布于 2019-09-20 09:39:09
发布于 2019-09-20 09:39:09
1.6K00
代码可运行
举报
文章被收录于专栏:光城(guangcity)光城(guangcity)
运行总次数:0
代码可运行

0.导语

最近做的项目使用CLION构建,而这个采用CMakeLists.txt管理,因此为了更好的学习,故找到了一篇大牛级别的入门文章,有文章有代码,本文是花了一点时间把这篇文章学习后的重要点记录吧,原作者github地址:https://github.com/wzpan/cmake-demo。

1.单个源文件

CMakeLists.txt 的语法比较简单,由命令、注释和空格组成,其中命令是不区分大小写的。符号 # 后面的内容被认为是注释。命令由命令名称、小括号和参数组成,参数之间使用空格进行间隔。

首先创建一个main.cpp

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <iostream>

int main() {
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

编写第一个CMakeLists.txt:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cmake_minimum_required(VERSION 3.10)
project(cmakeLearn)
add_executable(main main.cpp)
  1. cmake_minimum_required:指定运行此配置文件所需的 CMake 的最低版本;
  2. project:参数值是 cmakeLearn,该命令表示项目的名称是 cmakeLearn
  3. add_executable:将名为main.cpp的源文件编译成一个名称为 cmakeLearn 的可执行文件。

现在查看一下路径:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
light@city:~/CLionProjects/cmakeLearn$ ls
CMakeLists.txt  main.cpp

输入下列命令进行cmake

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cmake .

cmake过程

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
light@city:~/CLionProjects/cmakeLearn$ cmake .
-- The C compiler identification is GNU 5.5.0
-- The CXX compiler identification is GNU 5.5.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/light/CLionProjects/cmakeLearn

cmake 后 生成了Makefile

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
light@city:~/CLionProjects/cmakeLearn$ ls
CMakeCache.txt  cmake_install.cmake  main.cpp
CMakeFiles      CMakeLists.txt       Makefile

然后执行make

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
light@city:~/CLionProjects/cmakeLearn$ make
Scanning dependencies of target main
[ 50%] Building CXX object CMakeFiles/main.dir/main.cpp.o
[100%] Linking CXX executable main
[100%] Built target main

执行

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
light@city:~/CLionProjects/cmakeLearn$ ./main
Hello, World!

2.多个源文件

2.1 同一目录,多个源文件

在1中的cmake添加下面这行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)

当本地源文件很多,如果将源文件都加到里面就很烦,所以这里采用aux_source_directory。CMake 会将当前目录所有源文件的文件名赋值给变量 DIR_SRCS ,再指示变量 DIR_SRCS 中的源文件需要编译成一个名称为 Demo 的可执行文件。

这样就避免出现下面这种情况:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 指定生成目标
add_executable(Demo main.cc MathFunctions.cc xx.cc ....cc)

小结:

  • aux_source_directory(. DIR_SRCS)

查找当前目录下的所有源文件,并将名称保存到 DIR_SRCS 变量。

2.2 多个目录,多个源文件

此时目录架构:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
./Demo3
    |
    +--- main.cc
    |
    +--- math/
          |
          +--- MathFunctions.cc
          |
          +--- MathFunctions.h

对于这种情况,需要分别在项目根目录 Demo3 和 math 目录里各编写一个 CMakeLists.txt 文件。

为了方便,我们可以先将 math 目录里的文件编译成静态库再由 main 函数调用

这里与上述2.1CMakeLists不同之处是在上面基础上加上了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 添加 math 子目录
add_subdirectory(math)
# 添加链接库
target_link_libraries(Demo MathFunctions)

以此完成:

  • 子目录添加
  • 链接库添加

最后,在子目录下指定链接库名字:

子目录中的 CMakeLists.txt:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)
# 生成链接库
add_library (MathFunctions ${DIR_LIB_SRCS})

小结:

  • add_library(MathFunctions ${DIR_LIB_SRCS})

将 src 目录中的源文件编译为静态链接库。

3.自定义编译选项

CMake 允许为项目增加编译选项,从而可以根据用户的环境和需求选择最合适的编译方案。

例如,可以将 MathFunctions 库设为一个可选的库,如果该选项为 ON ,就使用该库定义的数学函数来进行运算。否则就调用标准库中的数学函数库。

本节CMake与2不同如下三块:

(1)加入一个配置头文件,用于处理 CMake 对源码的设置

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 加入一个配置头文件,用于处理 CMake 对源码的设置
configure_file (
  "${PROJECT_SOURCE_DIR}/config.h.in"
  "${PROJECT_BINARY_DIR}/config.h"
  )

configure_file 命令用于加入一个配置头文件 config.h ,这个文件由 CMake 从 config.h.in生成,通过这样的机制,将可以通过预定义一些参数和变量来控制代码的生成。

例如:修改main.cc:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include "config.h"
...
...
...
#ifdef USE_MYMATH
  #include "math/MathFunctions.h"
#else
  #include
#endif

根据 USE_MYMATH 的预定义值来决定是否调用标准库还是 MathFunctions 库。

上修改main.cc中引用了一个 config.h 文件,这个文件预定义了 USE_MYMATH 的值。但我们并不直接编写这个文件,为了方便从 CMakeLists.txt 中导入配置,我们编写一个 config.h.in 文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#cmakedefine USE_MYMATH

这样 CMake 会自动根据 CMakeLists 配置文件中的设置自动生成 config.h 文件。

这里使用了ccmake进行可视化编译选择,Ubuntu上安装:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
sudo apt-get install cmake-curses-gui

运行ccmake .后:

hjkl控制方向移动,enter 键可以修改该选项。修改完成后可以按下 c 选项完成配置,之后再按 g 键确认生成 Makefile 。ccmake 的其他操作可以参考窗口下方给出的指令提示。

下面来看一下config.h文件内容:

USE_MYMATH 为 ON
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define USE_MYMATH
USE_MYMATH 为 OFF
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/* #undef USE_MYMATH */

(2)是否加入 MathFunctions 库

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 是否加入 MathFunctions 库
if (USE_MYMATH)
  include_directories ("${PROJECT_SOURCE_DIR}/math")
  add_subdirectory (math)  
  set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)

option 命令添加了一个 USE_MYMATH 选项,并且默认值为 ON

(3)是否使用自己的 MathFunctions 库

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 是否使用自己的 MathFunctions 库
option (USE_MYMATH
       "Use provided math implementation" ON)

根据 USE_MYMATH 变量的值来决定是否使用我们自己编写的 MathFunctions 库。

4.安装和测试

4.1 安装

之前在编译一些源代码程序的时候,先make后make install,这样会把一些头文件与静态/动态库安装到指定的目录下。

那在CMAKE中同样可以这么做,如下:

首先先在 math/CMakeLists.txt 文件里添加下面两行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 指定 MathFunctions 库的安装路径
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)

指明 MathFunctions 库的安装路径。之后同样修改根目录的 CMakeLists 文件,在末尾添加下面几行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 指定安装路径
install (TARGETS Demo DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/config.h"
         DESTINATION include)

通过上面定制,后安装如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
light@city:~/cmake-demo/Demo5$ sudo make install
[ 50%] Built target MathFunctions
[100%] Built target Demo
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/bin/Demo
-- Installing: /usr/local/include/config.h
-- Installing: /usr/local/lib/libMathFunctions.a
-- Installing: /usr/local/include/MathFunctions.h

据此完成了安装工作。

4.2 测试

CMake 提供了一个称为 CTest 的测试工具。我们要做的只是在项目根目录的 CMakeLists 文件中调用一系列的 add_test 命令。

启动测试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 启用测试
enable_testing()

(1)无帮助信息测试

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 测试程序是否成功运行
add_test (test_run Demo 5 2)

(2)有帮助信息测试

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 测试 210 次方
add_test (test_2_10 Demo 2 10)
set_tests_properties (test_2_10)
 PROPERTIES PASS_REGULAR_EXPRESSION "is 1024")

其中 PASS_REGULAR_EXPRESSION 用来测试输出是否包含后面跟着的字符串。

5.支持gdb

让 CMake 支持 gdb 的设置也很容易,只需要指定 Debug 模式下开启 -g 选项:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")

6.添加版本号

在编写项目中给项目添加版本号:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
set (Demo_VERSION_MAJOR 1)
set (Demo_VERSION_MINOR 0)

分别指定当前的项目的主版本号和副版本号。

如果想在代码中获取信息,可以修改config.h.in文件,添加两个预定义变量:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// the configured options and settings for Tutorial
#define Demo_VERSION_MAJOR @Demo_VERSION_MAJOR@
#define Demo_VERSION_MINOR @Demo_VERSION_MINOR@

主程序调用,打印:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
printf("%s Version %d.%d\n",
        argv[0],
        Demo_VERSION_MAJOR,
        Demo_VERSION_MINOR);

7.生成安装包

如何配置生成各种平台上的安装包,包括二进制安装包和源码安装包。为了完成这个任务,我们需要用到 CPack ,它同样也是由 CMake 提供的一个工具,专门用于打包。

我们做如下三个工作:

  1. 导入 InstallRequiredSystemLibraries 模块,以便之后导入 CPack 模块;
  2. 设置一些 CPack 相关变量,包括版权信息和版本信息,其中版本信息用了上一节定义的版本号;
  3. 导入 CPack 模块。

对应CMakeLists.txt如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 构建一个 CPack 安装包
include (InstallRequiredSystemLibraries)
set (CPACK_RESOURCE_FILE_LICENSE
  "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
set (CPACK_PACKAGE_VERSION_MAJOR "${Demo_VERSION_MAJOR}")
set (CPACK_PACKAGE_VERSION_MINOR "${Demo_VERSION_MINOR}")
include (CPack)

下面就是如何使用:

输入cpack .,也可以指定二进制与源码安装包:

  • 生成二进制安装包:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cpack -C CPackConfig.cmake
  • 生成源码安装包
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cpack -C CPackSourceConfig.cmake

cpack安装:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
light@city:~/cmake-demo/Demo8$ cpack -CPackConfig.cmake
CPack: Create package using STGZ
CPack: Install projects
CPack: - Run preinstall target for: Demo8
CPack: - Install project: Demo8
CPack: Create package
CPack: - package: /home/light/cmake-demo/Demo8/Demo8-1.0.1-Linux.sh generated.
CPack: Create package using TGZ
CPack: Install projects
CPack: - Run preinstall target for: Demo8
CPack: - Install project: Demo8
CPack: Create package
CPack: - package: /home/light/cmake-demo/Demo8/Demo8-1.0.1-Linux.tar.gz generated.
CPack: Create package using TZ
CPack: Install projects
CPack: - Run preinstall target for: Demo8
CPack: - Install project: Demo8
CPack: Create package
CPack: - package: /home/light/cmake-demo/Demo8/Demo8-1.0.1-Linux.tar.Z generated.

此时会在本地目录下创建3个不同格式的二进制包文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
light@city:~/cmake-demo/Demo8$ ls Demo8*
Demo8-1.0.1-Linux.sh  Demo8-1.0.1-Linux.tar.gz  Demo8-1.0.1-Linux.tar.Z

随便选择一个安装,例如sh:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
sh Demo8-1.0.1-Linux.sh

使用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
light@city:~/cmake-demo/Demo8$ ./Demo8-1.0.1-Linux/bin/Demo 5 2
Now we use our own Math library.
5 ^ 2 is 25
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 光城 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
万字总结编译利器CMake,从入门到项目实战演练
你或许听过好几种 Make 工具,例如 GNU Make ,QT 的 qmake ,微软的 MS nmake,BSD Make(pmake),Makepp,等等。这些 Make 工具遵循着不同的规范和标准,所执行的 Makefile 格式也千差万别。这样就带来了一个严峻的问题:如果软件想跨平台,必须要保证能够在不同平台编译。而如果使用上面的 Make 工具,就得为每一种标准写一次 Makefile ,这将是一件让人抓狂的工作。
嵌入式Linux内核
2023/06/28
1.4K0
万字总结编译利器CMake,从入门到项目实战演练
cmake用法
示例源码 在 linux 平台下使用 CMake 生成 Makefile 并编译的流程如下:
用户2929716
2018/08/23
1.3K0
cmake用法
算法部署 | 万字长文带你从C++案例一步一步实操cmake(起飞系列)
你或许听过好几种Make工具,例如GNU Make ,QT的qmake ,微软的MS nmake,BSD Make(pmake),Makepp,等等。这些Make工具遵循着不同的规范和标准,所执行的Makefile格式也千差万别。这样就带来了一个严峻的问题:如果软件想跨平台,必须要保证能够在不同平台编译。而如果使用上面的 Make 工具,就得为每一种标准写一次Makefile,这将是一件让人抓狂的工作。
集智书童公众号
2021/07/30
1.5K0
CMake入门实战——自定义编译选项
CMake 允许为项目增加编译选项,从而可以根据用户的环境和需求选择最合适的编译方案。
AI异构
2020/07/29
2.4K0
CMake入门实战——自定义编译选项
CMake入门实战——多个源文件
上面的例子只有单个源文件。现在假如把 power 函数单独写进一个名为 MathFunctions.c 的源文件里,使得这个工程变成如下的形式:
AI异构
2020/07/29
2.1K0
CMake入门实战——生成安装包
本节将学习如何配置生成各种平台上的安装包,包括二进制安装包和源码安装包。为了完成这个任务,我们需要用到 CPack ,它同样也是由 CMake 提供的一个工具,专门用于打包。 首先在顶层的 CMakeLists.txt 文件尾部添加下面几行:
AI异构
2020/07/29
1.6K0
cmake终极奥义
上期makefile终极奥义反响不错,有粉丝提出有没有cmake终极奥义,那么她来了。已构建项目,地址为:
DeROy
2021/03/12
1.3K0
cmake终极奥义
CMake
理论上来说,任意一个c++程序都可以使用g++来编译,但当程序规模越来越大时,一个工程可能有许多的文件夹和源文件,这时输入的编译命令将会越来越长。因此,对于C++使用一些工程管理工具会更加高效。这里我们使用CMake。 在一个CMake工程中,我们会使用cmake命令生成一个Makefile文件,然后,用make命令根据这个 makefile文件的内容来编译整个工程。
小飞侠xp
2019/01/03
1.8K0
CMakeLists.txt 语法介绍与实例演练
cmake 是一个跨平台、开源的构建系统。它是一个集软件构建、测试、打包于一身的软件。它使用与平台和编译器独立的配置文件来对软件编译过程进行控制。
全栈程序员站长
2022/06/24
2.4K0
CMakeLists.txt 语法介绍与实例演练
CMake学习笔记(一)——CMake官网教程
剑影啸清寒
2018/01/02
4.4K0
cmake-tutorial cmake入门指引
Below is a step-by-step tutorial covering common build system use cases that CMake helps to address. Many of these topics have been introduced in Mastering CMakeas separate issues but seeing how they all work together in an example project can be very helpful. This tutorial can be found in the Tests/Tutorial directory of the CMake source code tree. Each step has its own subdirectory containing a complete copy of the tutorial for that step.
望天
2019/08/29
1.2K0
CMake入门实战——其他
让 CMake 支持 gdb 的设置也很容易,只需要指定 Debug 模式下开启 -g 选项:
AI异构
2020/07/29
5280
cmake快速入门「建议收藏」
cmake是kitware公司以及一些开源开发者在开发几个工具套件(VTK)的过程中所产生的衍生品。后来经过发展,最终形成体系,在2001年成为一个独立的开放源代码项目。其官方网站是www.cmake.org,可以通过访问官方网站来获得更多关于cmake的信息,而且目前官方的英文文档比以前有了很大的改进,可以作为实践中的参考手册。
全栈程序员站长
2022/09/13
1.3K0
cmake快速入门「建议收藏」
cmake 简介2021-10-03
CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的makefile或者project文件,能测试编译器所支持的C++特性,类似UNIX下的automake。
用户3519280
2023/07/08
4360
CMake 基础学习
使用 {}进行变量的引用。例如:message({Hello_VERSION}), Hello为工程名。CMake提供了很多有用的变量。以下仅列举常用的变量:
艳龙
2021/12/16
1.8K0
【CMake教程】(五)CMake 配置install打包
我们编译生成的可执行文件一般,会生成在当前的编译路径下,也就是build或者release路径下。那么如何将编译生成的可执行文件和库文件打包到一起进行发布那?本片教程我们将讲述如何在cmake中配置install的打包路径。下面我们将以mathlib库和头文件为例子进行配置。
CNNer
2020/07/21
9.3K0
【CMake教程】(四)CMake 配置生成lib或者so的库文件
上面几个教程我们的程序都是生成可执行文件。但是我们在合作开发算法的时候经常需要交付的是一个模块,该模块提供特定的算法功能,用于给整体的项目进行调用。但我们又不能直接提供源码,所以我们可以提供一个库文件(静态库或者动态库),配置接口文件可以在不提供源代码的情况下给他人提供算法模块功能。本文主要讲述如何使用CMakeLists.txt,配置生成动态和静态库文件。
CNNer
2020/07/21
13.1K0
cmake基本使用
CMAKE_C_FLAGS:编译C文件时的选项,如-g;也可以通过add_definitions添加编译选项
aruba
2020/07/02
1.7K0
CMake入门实战——单个源文件
你或许听过好几种 Make 工具,例如 GNU Make ,QT 的 qmake ,微软的 MS nmake,BSD Make(pmake),Makepp,等等。这些 Make 工具遵循着不同的规范和标准,所执行的 Makefile 格式也千差万别。这样就带来了一个严峻的问题:如果软件想跨平台,必须要保证能够在不同平台编译。而如果使用上面的 Make 工具,就得为每一种标准写一次 Makefile ,这将是一件让人抓狂的工作。 CMake就是针对上面问题所设计的工具:它首先允许开发者编写一种平台无关的 CMakeList.txt 文件来定制整个编译流程,然后再根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件,如 Unix 的 Makefile 或 Windows 的 Visual Studio 工程。从而做到“Write once, run everywhere”。显然,CMake 是一个比上述几种 make 更高级的编译配置工具。一些使用 CMake 作为项目架构系统的知名开源项目有 VTK、ITK、KDE、OpenCV、OSG 等。 在 linux 平台下使用 CMake 生成 Makefile 并编译的流程如下:
AI异构
2020/07/29
5740
CMake简介及使用实例
CMake是一个跨平台的建构系统的工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的构建文档makefile或者project文件,描述系统建构的过程。还能测试编译器所支持的C++特性,类似UNIX下的automake。只是 CMake 的组态档取名为 CmakeLists.txt。CMake并不直接建构出最终的软件,而是产生标准的建构档(如 Unix的 Makefile或 Windows Visual C++的 projects/workspaces),然后再依一般的构建方式使用。
恋喵大鲤鱼
2018/08/03
2.7K0
推荐阅读
相关推荐
万字总结编译利器CMake,从入门到项目实战演练
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验