CMake 是一个开源的、跨平台的工具系列,用于构建、测试和打包软件。CMake 用于使用简单的平台和编译器独立的配置文件(CMakeLists.txt)来控制软件编译过程,并生成可以在您选择的编译环境中使用的本地生成文件和工作空间。CMake 工具套件是由 Kitware 创建的,以响应对 ITK 和 VTK 等开源项目强大的跨平台构建环境的需求。

CMake 是一个元构建系统。它可以从抽象的文本配置生成真正的本地构建工具文件。通常这样的代码存在于 CMakeLists.txt 文件中。

一、Cmake 安装

以 Ubuntu 18.04 Server 安装为例进行介绍。

到 https://cmake.org/files/ 下载指定版本的 Cmake,这里下载当前最新版 https://cmake.org/files/v3.22/cmake-3.22.0-linux-x86_64.tar.gz

  1. 下载 cmake-3.22.0
wget https://cmake.org/files/v3.22/cmake-3.22.0-linux-x86_64.tar.gz
--2021-12-06 01:05:45--  https://cmake.org/files/v3.22/cmake-3.22.0-linux-x86_64.tar.gz
Resolving cmake.org (cmake.org)... 66.194.253.25
Connecting to cmake.org (cmake.org)|66.194.253.25|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 45044059 (43M) [application/x-gzip]
Saving to: ‘cmake-3.22.0-linux-x86_64.tar.gz’cmake-3.22.0-linux- 100%[===================>]  42.96M  24.0KB/s    in 18m 51s2021-12-06 01:24:37 (38.9 KB/s) - ‘cmake-3.22.0-linux-x86_64.tar.gz’ saved [45044059/45044059]
  1. 解压压缩包
tar zxvf cmake-3.22.0-linux-x86_64.tar.gz

列出 cmake-3.22.0-linux-x86_64 文件夹目录树,如果未安装 tree 命令支持,先安装。

tree 安装:

sudo apt  install tree
tree -L 2 cmake-3.22.0-linux-x86_64

cmake-3.22.0-linux-x86_64 目录树如下:

cmake-3.22.0-linux-x86_64
├── bin
│   ├── ccmake
│   ├── cmake
│   ├── cmake-gui
│   ├── cpack
│   └── ctest
├── doc
│   └── cmake
├── man
│   ├── man1
│   └── man7
└── share├── aclocal├── applications├── bash-completion├── cmake-3.22├── emacs├── icons├── mime└── vim
  1. 创建软链接

移动 cmake-3.22.0-linux-x86_64 到 /opt/cmake-3.22.0-linux-x86_64 文件夹下(文件路径是可以指定的, 一般选择在/opt 或 /usr 路径下)。

sudo mv cmake-3.22.0-linux-x86_64 /opt/cmake-3.22.0-linux-x86_64

将 cmake bin 下的文件创建软链接。

sudo ln -sf /opt/cmake-3.22.0-linux-x86_64/bin/* /usr/bin/
  1. 确认安装结果
cmake --version

输出如下,cmake 安装版本是 3.22.0。

cmake version 3.22.0

CMake suite maintained and supported by Kitware (kitware.com/cmake).

二、CMake Hello world

使用 CMake 前的准备工作。

mkdir test
cd test
touch main.cpp
touch CMakeLists.txt

main.cpp

#include<iostream>
using namespace std;
int main(){cout<<"hello world!"<<endl;return 0;
}

CMakeLists.txt

#cmake最小需要版本
cmake_minimum_required(VERSION 2.8)#项目名字
project(HELLOWORLD)#包含原程序,即把给定目录下的源程序复制给变量DIR_SRC
aux_source_directory(. DIR_SRC)#生成程序
add_executable(helloworld ${DIR_SRC})

创建 build 目录生成 Cmake 编译后的输出文件。

mkdir build
cd build
cmake ../

很明显报错了。

CMake Deprecation Warning at CMakeLists.txt:2 (cmake_minimum_required):Compatibility with CMake < 2.8.12 will be removed from a future version ofCMake.Update the VERSION argument <min> value or use a ...<max> suffix to tellCMake that the project does not need compatibility with older versions.CMake Error: CMake was unable to find a build program corresponding to "Unix Makefiles".  CMAKE_MAKE_PROGRAM is not set.  You probably need to select a different build tool.
CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage
CMake Error: CMAKE_CXX_COMPILER not set, after EnableLanguage
-- Configuring incomplete, errors occurred!
See also "/home/snake/test/build/CMakeFiles/CMakeOutput.log".

兼容 CMake < 2.8.12 将从未来的版本中移除,需要更改 CMakeLists.txt:

cmake_minimum_required(VERSION 3.0)

CMake无法找到对应于“Unix Makefiles”的构建程序。没有设置 CMAKE_MAKE_PROGRAM。您可能需要选择不同的构建工具。需要安装构建工具,这里选择安装 make。

sudo apt-get -y install make
make -v

make -v 输出如下:

GNU Make 4.1
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

CMAKE_C_COMPILER 和 CMAKE_CXX_COMPILER 未设置,安装 g++ 解决。

sudo apt install g++

从这里不难看出 Cmake 还是需要搭配 make 和 g++ 才可以编译。

再次进入 build 目录:

cmake ..

现在 cmake 工作正常了。

-- The C compiler identification is GNU 7.5.0
-- The CXX compiler identification is GNU 7.5.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/snake/test/build

重新列出 build 目录下的文件,Makefile 很熟悉吧,所以再次调用 make 命令就可以生成可执行 bin 文件了。cmake 原来只是生成了 Makefile,并没有直接生成最后的可运行二进制文件!

CMakeCache.txt  CMakeFiles  cmake_install.cmake  Makefile

build 目录下执行 make 命令。

make

输出如下:

[ 50%] Building CXX object CMakeFiles/helloworld.dir/main.cpp.o
[100%] Linking CXX executable helloworld
[100%] Built target helloworld

helloworld bin 可执行文件已经生成。

build 目录运行 helloworld bin 程序。

./helloworld

输出如下:

hello world!

三、CMake 常用命令

确切的说,CMake 命令分为三种:脚本命令、项目命令、CTest 命令。

3.1 project

设置项目的名称,并将其存储在变量 PROJECT_NAME 中。当从顶级 CMakeLists.txt 中调用时,它还将项目名称存储在变量 CMAKE_PROJECT_NAME 中。

project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>[VERSION <major>[.<minor>[.<patch>[.<tweak>]]]][DESCRIPTION <project-description-string>][HOMEPAGE_URL <url-string>][LANGUAGES <language-name>...])

3.2 cmake_minimum_required

为一个项目设置最低需要的 cmake 版本,还更新策略设置。

cmake_minimum_required(VERSION <min>[...<policy_max>] [FATAL_ERROR])

<min> 和可选的 <policy_max> 都是 CMake 格式的版本:major.minor[.patch[.tweak]]

如果运行的 CMake 版本低于 <min> 需要的版本,它将停止处理项目并报告一个错误。可选的 <policy_max> 如果指定了版本,则必须至少为 <min> 版本,并影响策略设置,如策略设置中所述。如果运行版本的 CMake 是比 3.12 更老的,额外的…圆点将被视为版本组件分隔符,导致…部分被忽略,保留 3.12 之前的基于 <min> 的政策行为。

这个命令将 CMAKE_MINIMUM_REQUIRED_VERSION 变量的值设置为 。

FATAL_ERROR 选项会被 CMake 2.6 及更高版本所忽略。

策略设置

cmake_minimum_required(VERSION) 命令隐式地调用 cmake_policy(VERSION) 命令来指定当前项目代码是为给定的 CMake 版本范围编写的。所有 CMake 运行版本中已知并在 <min>(或 <max> 如果指定)版本或更早版本将被设置为使用 NEW 行为。后续版本中引入的所有策略都将被取消设置。这有效地请求首选行为作为一个给定的 CMake 版本,并告诉新的 CMake 版本警告他们的新策略。

当一个 高于 2.4 的版本被指定为该命令隐式调用的版本。

cmake_policy(VERSION <min>[...<max>])

3.3 aux_source_directory

找到一个目录中的所有源文件。收集指定目录下所有源文件的名称,并将列表存储在提供的 <variable> 变量中。此命令用于使用显式模板实例化的项目。模板实例化文件可以存储在 Templates 子目录中,并使用此命令自动收集,以避免手动列出所有实例化。

使用此命令可以避免为库或可执行目标编写源文件列表。虽然这看起来是可行的,但 CMake 无法生成一个知道何时添加了新源文件的构建系统。通常生成的构建系统知道什么时候需要重新运行 CMake,因为 CMakeLists.txt 文件被修改以添加一个新的源文件。当源代码只是添加到目录而没有修改该文件时,必须手动重新运行 CMake 来生成一个包含新文件的构建系统。

aux_source_directory(<dir> <variable>)

3.4 add_executable

添加一个名为 <name> 的可执行目标,从命令调用中列出的源文件中构建。<name> 对应于逻辑目标名称,并且在项目中必须是全局唯一的。所构建的可执行文件的实际文件名是根据本地平台的约定构造的(例如<name>.exe 或仅仅是<name>)。

add_executable(<name> [WIN32] [MACOSX_BUNDLE][EXCLUDE_FROM_ALL][source1] [source2 ...])

3.5 set

将普通变量、缓存变量或环境变量设置为给定值。

设置普通变量

在当前函数或目录范围内设置给定的 <variable> 变量。

set(<variable> <value>... [PARENT_SCOPE])

设置缓存变量

设置给定的缓存 <variable> 变量(缓存条目)。由于缓存条目旨在提供用户可设置的值,因此默认情况下不会覆盖现有的缓存条目。使用 FORCE 选项覆盖现有条目。

set(<variable> <value>... CACHE <type> <docstring> [FORCE])

设置环境变量

将环境变量设置为给定值。后续调用 $ENV{<variable>} 将返回这个新值。

set(ENV{<variable>} [<value>])

3.6 add_subdirectory

将子目录添加到 build 中。source_dir 指定源 CMakeLists.txt 和代码文件所在的目录。如果它是一个相对路径,它将根据当前目录进行计算(这是典型用法),但它也可能是一个绝对路径。binary_dir 指定存放输出文件的目录。如果它是一个相对路径,它将根据当前输出目录求值,但它也可能是一个绝对路径。如果未指定 binary_dir,将在展开任何相对路径之前使用 source_dir 的值(典型用法)。CMake 将立即处理指定源目录中的 CMakeLists.txt 文件,然后继续处理当前输入文件。

如果提供了 EXCLUDE_FROM_ALL 参数,那么子目录中的目标将默认不包含在父目录的 ALL 目标中,并且将从 IDE 项目文件中排除。用户必须在子目录中显式地构建目标。这适用于子目录包含项目的一个单独的部分,这些部分是有用的,但不是必需的,比如一组示例。

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

3.7 find_library

该命令用于查找库。一个缓存条目,或者一个普通变量(如果指定了NO_CACHE),<VAR> 变量用于存储此命令的结果。如果找到库,则将结果存储在变量中,并且除非清除变量,否则不会重复搜索。如果没有找到任何东西,结果将是 <VAR>-NOTFOUND。

find_library (<VAR> name1 [path1 path2 ...])find_library (<VAR>name | NAMES name1 [name2 ...] [NAMES_PER_DIR][HINTS [path | ENV var]... ][PATHS [path | ENV var]... ][PATH_SUFFIXES suffix1 [suffix2 ...]][DOC "cache documentation string"][NO_CACHE][REQUIRED][NO_DEFAULT_PATH][NO_PACKAGE_ROOT_PATH][NO_CMAKE_PATH][NO_CMAKE_ENVIRONMENT_PATH][NO_SYSTEM_ENVIRONMENT_PATH][NO_CMAKE_SYSTEM_PATH][CMAKE_FIND_ROOT_PATH_BOTH |ONLY_CMAKE_FIND_ROOT_PATH |NO_CMAKE_FIND_ROOT_PATH])

3.8 file

这个命令专门用于需要访问文件系统的文件和路径操作。

Readingfile(READ <filename> <out-var> [...])file(STRINGS <filename> <out-var> [...])file(<HASH> <filename> <out-var>)file(TIMESTAMP <filename> <out-var> [...])file(GET_RUNTIME_DEPENDENCIES [...])Writingfile({WRITE | APPEND} <filename> <content>...)file({TOUCH | TOUCH_NOCREATE} [<file>...])file(GENERATE OUTPUT <output-file> [...])file(CONFIGURE OUTPUT <output-file> CONTENT <content> [...])Filesystemfile({GLOB | GLOB_RECURSE} <out-var> [...] [<globbing-expr>...])file(MAKE_DIRECTORY [<dir>...])file({REMOVE | REMOVE_RECURSE } [<files>...])file(RENAME <oldname> <newname> [...])file(COPY_FILE <oldname> <newname> [...])file({COPY | INSTALL} <file>... DESTINATION <dir> [...])file(SIZE <filename> <out-var>)file(READ_SYMLINK <linkname> <out-var>)file(CREATE_LINK <original> <linkname> [...])file(CHMOD <files>... <directories>... PERMISSIONS <permissions>... [...])file(CHMOD_RECURSE <files>... <directories>... PERMISSIONS <permissions>... [...])Path Conversionfile(REAL_PATH <path> <out-var> [BASE_DIRECTORY <dir>] [EXPAND_TILDE])file(RELATIVE_PATH <out-var> <directory> <file>)file({TO_CMAKE_PATH | TO_NATIVE_PATH} <path> <out-var>)Transferfile(DOWNLOAD <url> [<file>] [...])file(UPLOAD <file> <url> [...])Lockingfile(LOCK <path> [...])Archivingfile(ARCHIVE_CREATE OUTPUT <archive> PATHS <paths>... [...])file(ARCHIVE_EXTRACT INPUT <archive> [...])

3.9 add_definitions

在编译源文件时添加 -D define 标志。

add_definitions(-DFOO -DBAR ...)

3.10 add_library

使用指定的源文件向项目添加库。

add_library(<name> [STATIC | SHARED | MODULE][EXCLUDE_FROM_ALL][<source>...])add_library(<name> OBJECT [<source>...])   add_library(<name> INTERFACE)add_library(<name> <type> IMPORTED [GLOBAL])add_library(<name> ALIAS <target>)

3.11 target_include_directories

指定编译给定目标时要使用的 include 目录。<target> 必须由 add_executable() 或 add_library() 等命令创建,并且不能是 ALIAS 目标。

target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]<INTERFACE|PUBLIC|PRIVATE> [items1...][<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

3.12 target_link_libraries

指定连接给定目标和/或其依赖项时要使用的库或标志。来自链接库目标的使用需求将被传播。目标依赖项的使用需求会影响其自身源的编译。

target_link_libraries(<target> ... <item>... ...)

3.13 set_target_properties

目标可以具有影响其构建方式的属性。设置目标的属性。该命令的语法是列出想要更改的所有目标,然后提供接下来想要设置的值。

set_target_properties(target1 target2 ...PROPERTIES prop1 value1prop2 value2 ...)

3.14 include_directories

将 include 目录添加到构建中。

include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])

3.15 message

日志消息。

General messagesmessage([<mode>] "message text" ...)Reporting checksmessage(<checkState> "message text" ...)

四、CMake 实战 Live555 移植

写一份移植 Live555 到 Android 平台的 CMakeLists.txt。

cmake_minimum_required(VERSION 3.4.1)set(LIVE555_LIB_NAME Live555)file(GLOB BasicUsageEnvironmentFiles ${CMAKE_CURRENT_SOURCE_DIR}/BasicUsageEnvironment/*.cpp)
file(GLOB groupsockFiles ${CMAKE_CURRENT_SOURCE_DIR}/groupsock/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/groupsock/*.c)
file(GLOB liveMediaFiles ${CMAKE_CURRENT_SOURCE_DIR}/liveMedia/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/liveMedia/*.c)
file(GLOB UsageEnvironmentFiles ${CMAKE_CURRENT_SOURCE_DIR}/UsageEnvironment/*.cpp)include_directories(${CMAKE_CURRENT_SOURCE_DIR}/BasicUsageEnvironment/include/)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/groupsock/include/)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/liveMedia/include/)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/UsageEnvironment/include/)add_definitions(-D LOCALE_NOT_USED)
# android 版本高于 24 才能使用 getifaddrs、freeifaddrs
add_definitions(-D NO_GETIFADDRS)
# bind() error (port number: 8554): Address already in use
add_definitions(-D ALLOW_SERVER_PORT_REUSE)set(OPENSSL_LIBS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../libs)message(STATUS "OPENSSL_LIBS_DIR = ${OPENSSL_LIBS_DIR}.")add_library(crypto STATIC IMPORTED)
set_target_properties(cryptoPROPERTIES IMPORTED_LOCATION ${OPENSSL_LIBS_DIR}/${ANDROID_ABI}/libcrypto.a)add_library(ssl STATIC IMPORTED)
set_target_properties(sslPROPERTIES IMPORTED_LOCATION ${OPENSSL_LIBS_DIR}/${ANDROID_ABI}/libssl.a)include_directories(${OPENSSL_LIBS_DIR}/include/)find_library(z-lib z)add_library( # Sets the name of the library.${LIVE555_LIB_NAME}# Sets the library as a shared library.SHARED# Provides a relative path to your source file(s).${BasicUsageEnvironmentFiles}${groupsockFiles}${UsageEnvironmentFiles}${liveMediaFiles})target_link_libraries( # Specifies the target library.${LIVE555_LIB_NAME}# Links the target library to the third library# included in the NDK.sslcrypto${z-lib})

编译后报错:invalid conversion from ‘int*’ to ‘socklen_t*’

修改 groupsock/include/NetCommon.h 123 行

#define SOCKLEN_T int 改为 #define SOCKLEN_T socklen_t

参考资料:

  1. https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html

CMake 基础用法,掌握 CMake 诀窍相关推荐

  1. 现代 CMake 简明教程(一)- CMake 基础

    系列文章目录 现代 CMake 简明教程(一)- CMake 基础 现代 CMake 简明教程(二)- 设计理念与使用 文章目录 系列文章目录 前言 CMake 基础 1. Modern CMake ...

  2. 学习C++:C++进阶(三)CMake基础篇---用一个小型项目了解CMake及环境构建

    V1.1 于2022年7月15日第二次修改:添加了比较多的解释图,解读了各类库的CMakelist.txt文件 目录 第一部分 基础篇(Basics) 1.0 本部分主要学什么(Intro) 1.1 ...

  3. cmake基础到实战

    cmake从基础到实战 前言 当初对cmake也是怀有恐惧心理,但是想着总要学会,便花了一个周末时间带着问题去查资料,在解决问题中也算是对cmake入门了. 有很多事情都是有个大概的想法就要开始做,不 ...

  4. CMake基础 第7节 编译标志

    引言# CMake支持以多种不同方式设置编译标志: 使用target_compile_definitions()函数 使用CMAKE_C_FLAGS和CMAKE_CXX_FLAGS变量. 本教程中的文 ...

  5. CMake基础 第2节 分离编译

    介绍# 展示一个hello world示例,它使用不同的文件夹来存储源文件和头文件. 本教程中的文件包括: B-hello-headers$ tree . ├── CMakeLists.txt ├── ...

  6. linux cmake 编译项目,使用CMake构建复杂工程

    0. 什么是CMake CMake是一个跨平台的编译.安装.测试以及打包工具:CMake不直接编译软件,而是结合原生构建系统来构建软件.CMake配置文件是CMakeList.txt文件(每个源码文件 ...

  7. Pandas基础用法合集(中文官档)

    本节介绍 pandas 数据结构的基础用法.下列代码创建示例数据对象: In [1]: index = pd.date_range('1/1/2000', periods=8) In [2]: s = ...

  8. Promise基础用法

    什么是Promise? Promise是用来处理异步的; Promise就是承诺,对未来的承诺; 所谓的Promise(承诺),里面保存着未来才会结束的事件的结果; Promise是异步编程的一种解决 ...

  9. pandas object转float_数据分析篇 | Pandas基础用法6【完结篇】

    这是最后一篇,至此Pandas系列终于连载完了,有需要的也可以看看前面6篇,尽请收藏. 数据分析篇 | Pandas 概览 数据分析篇 | Pandas基础用法1数据分析篇 | Pandas基础用法2 ...

最新文章

  1. SQLite中使用全文搜索FTS
  2. CCNA学习笔记--静态路由
  3. CTFshow 反序列化 web255
  4. 【算法入门漫画】:“排序算法” 大总结
  5. router vue 多个路径_多个vue子路由文件自动化合并的方法,
  6. 解决一个驱动代码解耦合问题
  7. nginx的指令root和alias的区别
  8. 使用aliyun镜像源下载镜像及仓库搭建
  9. java+垃圾回收器+的功能_JAVA-JVM 垃圾回收器
  10. mschart mysql_在VB mschart里面可以一个MSCHART同时显示曲线和状图吗?
  11. spring5.0学习笔记4
  12. Leetcode116. 填充每个节点的下一个右侧节点指针(宽搜或深搜)
  13. 博图如何上载wincc程序_博图导入触摸屏程序 如何通过博图下载触摸屏程序
  14. 网易邮箱客户端服务器设置
  15. 苹果iOS 8.0正式发布啦
  16. 鬼谷子谋略之空手套白狼
  17. 涨点技巧:基于Yolov5的微小目标检测,多头检测头提升小目标检测精度
  18. 【已修复】Error: ValueError: The last dimension of the inputs to `Dense` should be defined. Found `None`
  19. addons软件下载_addons中国版
  20. 竞价排名中的道德争议

热门文章

  1. 彩虹六号mute影响服务器笑话,有哪些《彩虹六号》玩家才懂的笑话?
  2. [BZOJ 3811]玛里苟斯(线性基)尽量理解的题解
  3. 《精彩网址大全——工商经济科学教育卷》内容简介
  4. hls.js下载m3u8视频播放hls.js
  5. html有序无序标签,HTML标签有序标签和无序标签
  6. React之npm发布Antd样式的组件
  7. node配置淘宝镜像
  8. 如何获取瘦人肠道菌群_与瘦人接吻,交换肠道菌群,就能减肥?
  9. 写好作文的6大步骤,把写作文变成一件“轻松事儿”!
  10. 代码中的下划线_是什么意思呢?