CMake 基础用法,掌握 CMake 诀窍

本文详细介绍了CMake的安装过程,包括Ubuntu 18.04的步骤,并通过CMake Hello World实例展示其基本使用。随后讲解了CMake常用命令及其在Live555移植到Android平台的实战应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 51s

2021-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 of
  CMake.

  Update the VERSION argument <min> value or use a ...<max> suffix to tell
  CMake 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

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

Reading
  file(READ <filename> <out-var> [...])
  file(STRINGS <filename> <out-var> [...])
  file(<HASH> <filename> <out-var>)
  file(TIMESTAMP <filename> <out-var> [...])
  file(GET_RUNTIME_DEPENDENCIES [...])

Writing
  file({WRITE | APPEND} <filename> <content>...)
  file({TOUCH | TOUCH_NOCREATE} [<file>...])
  file(GENERATE OUTPUT <output-file> [...])
  file(CONFIGURE OUTPUT <output-file> CONTENT <content> [...])

Filesystem
  file({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 Conversion
  file(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>)

Transfer
  file(DOWNLOAD <url> [<file>] [...])
  file(UPLOAD <file> <url> [...])

Locking
  file(LOCK <path> [...])

Archiving
  file(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 value1
                      prop2 value2 ...)

3.14 include_directories

将 include 目录添加到构建中。

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

3.15 message

日志消息。

General messages
  message([<mode>] "message text" ...)

Reporting checks
  message(<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(crypto
        PROPERTIES IMPORTED_LOCATION ${OPENSSL_LIBS_DIR}/${ANDROID_ABI}/libcrypto.a)

add_library(ssl STATIC IMPORTED)
set_target_properties(ssl
        PROPERTIES 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.
        ssl
        crypto
        ${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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TYYJ-洪伟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值