CMake官网教程学习

发布时间 2023-06-18 20:14:07作者: zhengcixi

简介

本文档是根据CMake的官方教程学习的笔记,同时将教程中C++实现的代码更改为C语言实现。当前还未学习完。

教程官网:CMake Tutorial — CMake 3.27.0-rc1 Documentation

中文教程:教程 — CMake 3.26.4 Documentation (cmake-doc.readthedocs.io)

官方教程源码下载:https://cmake.org/cmake/help/latest/_downloads/3c17a110086e62cc3d0b35abae2e4173/cmake-3.27.0-rc1-tutorial-source.zip

学习相关的代码存放在:cmake-3.27.0-rc1-tutorial-source · 简单/CMake学习 - 码云 - 开源中国 (gitee.com)

Step 1: A Basic Starting Point

参考:[Step 1: A Basic Starting Point — CMake 3.27.0-rc2 Documentation](https://cmake.org/cmake/help/latest/guide/tutorial/A Basic Starting Point.html)

本章介绍CMake基本的一些语法、指令和变量。

各子章节说明:

  • Goal:本章节学习的目的
  • Helpful Resources:使用到的命令帮助文档
  • Build and Run:构建和运行的命令

Exercise 1 - Building a Basic Project

最基本的CMake项目是从单个源文件开始构建。对于一个简单的工程,一个CMakeLists.txt文件通常需要三个命令。

注意:尽管CMake支持大写、小写、大小写混合命令,但是首选小写命令,并一直使用小写。

  • 一个CMakeLists.txt文件的开始命令应该使用cmake_minimum_required()指定CMak最低版本。它建立了策略设置,并确保下面的CMake命令都运行在兼容的版本上。
  • 启动工程,我们使用project()命令去设置工程名字。每一个工程都需要这个命令,并且应该在cmake_minimum_required()之后调用。该命令还可以指定其它项目信息,比如项目等级和使用的编程语言或者版本号。
  • 最后,使用add_executable()命令告诉CMake使用指定的源文件去创建一个可执行程序。

Goal

学习如何创建一个简单的CMake工程。

Helpful Resources

Build and Run

$ cd Step1
$ mkdir Step1_build
$ cd Step1_build
$ cmake ..
$ cmake --build .   # 运行, 生成可执行文件
$ ./Tutorial 4294967296
The square root of 4.29497e+09 is 65536
$ ./Tutorial 10
The square root of 10 is 3.16228

Exercise 2 - Specifying the C++ Standard

CMake有一些特殊变量,这些变量要么是隐式创建的,要么是工程中设置的。大部分这些变量以CMAKE_前缀修饰。在为项目创建变量时应该避免这种命令方式。其中两个特殊变量是CMAKE_CXX_STANDARDCMAKE_CXX_STANDARD_REQUIRED,他们通常一起使用去指定工程需要的C++版本。

Goal

添加C++ 11的特性。

Helpful Resources

Files to Edit

CMakeLists.txt

tutorial.cxx

Build and Run

同Exercise1

Exercise 3 - Adding a Version Number and Configured Header File

有时,在CMakeLists.txt文件中定义的变量在源文件中可能也是有用的,这种情况下,我们希望打印项目版本。

其中一种方式是使用配置好的头文件。我们创建一个输入文件,其中包含一个或多个需要替换的变量。这些变量使用类似@VAR@的特殊语法指定。然后,我们使用configure_file()命令去拷贝输入文件,并产生一个输出文件替换这些VAR变量。

虽然我们可以直接在代码中指定源码版本,但是这种方式是首选的,因为它指定了唯一来源,避免了重复定义。

Goal

定义和打印项目的版本号

Helpful Resources

Files to Edit

  • CMakeLists.txt
  • tutorial.cxx

Build and Run

$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.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 (0.3s)
-- Generating done (0.0s)
-- Build files have been written to: /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step1/Step1_build
[root@ubuntu] /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step1/Step1_build
$ cmake --build .
[ 50%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.o
[100%] Linking CXX executable Tutorial
[100%] Built target Tutorial
[root@ubuntu] /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step1/Step1_build
$ ./Tutorial
./Tutorial Version 1.0
Usage: ./Tutorial number

生成的TutorialConfig.in文件如下:

// the configured options and settings for Tutorial
// TODO 10: Define Tutorial_VERSION_MAJOR and Tutorial_VERSION_MINOR
#define Tutorial_VERSION_MAJOR 1
#define Tutorial_VERSION_MINOR 0

Step 2: Adding a Library

本章节,我们将使用CMake在工程中创建和使用库。

Exercise 1 - Creating a Library

在CMake中,使用add_library()命令指定哪些文件用来创建库。

相比于放置所有的源文件在一个目录,我们组织我们的工程使用一个或多个子目录。在这个例子中,我们将创建一个子目录来指定我们的库生成源文件。在子目录中我们添加一个新的CMakeLists.txt文件和源文件。在顶层CMakeLists.txt文件中,我们使用add_subdirectory()命令添加子目录去构建。

当我们的库创建后,链接到可执行文件使用target_include_directories()target_link_libraries()命令。

Goal

添加和使用一个库。

Helpful Resources

Getting Started

在这个例子中,我们将添加一个库到工程中,这个库包括计算平方根的实现。可执行文件可以使用这个库。

我们将库放在子目录MathFunctions中,这个目录已经包含头文件MathFunctions.hmysqrt.h,同时提供源码文件MathFunctions.cmysqrt.c

目录结构如下:

[root@ubuntu] /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step2
$ tree
.
├── CMakeLists.txt
├── MathFunctions
│   ├── CMakeLists.txt
│   ├── MathFunctions.cxx
│   ├── MathFunctions.h
│   ├── mysqrt.cxx
│   └── mysqrt.h
├── TutorialConfig.h.in
└── tutorial.cxx

Build and Run

$ mkdir Step2_build
$ cd Step2_build/
$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.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 (0.3s)
-- Generating done (0.0s)
-- Build files have been written to: /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step2/Step2_build
$ cmake --build .
$ ./Tutorial 10
Computing sqrt of 10 to be 5.5
Computing sqrt of 10 to be 3.65909
Computing sqrt of 10 to be 3.19601
Computing sqrt of 10 to be 3.16246
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
The square root of 10 is 3.16228
$ ls MathFunctions/    # 默认生成的是静态库
CMakeFiles/  cmake_install.cmake  libMathFunctions.a  Makefile

Exercise 2 - Adding an Option

在MathFunctions库添加一个选项,允许开发人员选择自定义开平方根实现或者使用标准库实现。

CMake可以使用option()命令实现,这为用户实现了一个可以在配置CMake构建时可以更改的变量。这个变量存放在缓存中,不需要用户每次构建CMake时都去设置这个值。

Goal

添加一个选项选择不使用MathFunctions

Helpful Resources

Build and Run

$ cmake ..
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step2/Step2_build
[root@ubuntu] /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step2/Step2_build
$ cmake --build .
[ 14%] Building CXX object MathFunctions/CMakeFiles/SqrtLibrary.dir/mysqrt.cxx.o
[ 28%] Linking CXX static library libSqrtLibrary.a
[ 28%] Built target SqrtLibrary
[ 42%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/MathFunctions.cxx.o
[ 57%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.cxx.o
[ 71%] Linking CXX static library libMathFunctions.a
[ 71%] Built target MathFunctions
[ 85%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.o
[100%] Linking CXX executable Tutorial
[100%] Built target Tutorial
[root@ubuntu] /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step2/Step2_build
$ ./Tutorial 10
Computing sqrt of 10 to be 5.5
Computing sqrt of 10 to be 3.65909
Computing sqrt of 10 to be 3.19601
Computing sqrt of 10 to be 3.16246
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
The square root of 10 is 3.16228
[root@ubuntu] /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step2/Step2_build
$ rm * -rf
[root@ubuntu] /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step2/Step2_build
$ cmake .. -DUSE_MYMATH=OFF
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.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 (0.3s)
-- Generating done (0.0s)
-- Build files have been written to: /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step2/Step2_build
[root@ubuntu] /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step2/Step2_build
$ cmake --build .
[ 20%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/MathFunctions.cxx.o
[ 40%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.cxx.o
[ 60%] Linking CXX static library libMathFunctions.a
[ 60%] Built target MathFunctions
[ 80%] Linking CXX executable Tutorial
[100%] Built target Tutorial
[root@ubuntu] /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step2/Step2_build
$ ./Tutorial 10
The square root of 10 is 3.16228

Step3: Adding Usage Requirements for a Library

Exercise 1 - Adding Usage Requirements for a Library

Usage requirements目标参数的使用允许对库或可执行文件的链接和包含行进行更好的控制,同时还可以更好地控制CMake内部目标的传递属性。使用Usage requirements主要的命令包括:

Goal

添加库的使用需求

Helpful Materials

Getting Started

在本例中,我们将使用主流CMake方法来重构添加一个库。我们将让库定义它自己的使用需求,以便根据需要将其传递给其它目标。MathFunctions将自己指定任何所需的包含目录。然后,Tutorial目标只需要链接到MathFunctions,而不需要担心额外的头文件目录。

Build and Run

[root@ubuntu] /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step3-Exercise1/Step3-build
$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.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 (0.3s)
-- Generating done (0.0s)
-- Build files have been written to: /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step3-Exercise1/Step3-build
[root@ubuntu] /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step3-Exercise1/Step3-build
$ cmake --build .
[ 16%] Building CXX object MathFunctions/CMakeFiles/SqrtLibrary.dir/mysqrt.cxx.o
[ 33%] Linking CXX static library libSqrtLibrary.a
[ 33%] Built target SqrtLibrary
[ 50%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/MathFunctions.cxx.o
[ 66%] Linking CXX static library libMathFunctions.a
[ 66%] Built target MathFunctions
[ 83%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.o
[100%] Linking CXX executable Tutorial
[100%] Built target Tutorial
[root@ubuntu] /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step3-Exercise1/Step3-build
$ ./Tutorial 10
Computing sqrt of 10 to be 5.5
Computing sqrt of 10 to be 3.65909
Computing sqrt of 10 to be 3.19601
Computing sqrt of 10 to be 3.16246
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
The square root of 10 is 3.16228

Exercise 2 - Setting the C++ Standard with Interface Libraries

既然我们已经切换到更现代的方法,让我们演示一种为多个目标设置属性的现代技术。

让我们使用INTERFACE库来重构现有代码。我们将在下一步中演示generator expressions的常用用法。

Goal

添加一个INTERFACE库来指定所需的C++标准。

Helpful Resources

Files to Edit

  • CMakeLists.txt
  • MathFunctions/CMakeLists.txt

Build and Run

同上

Step 4: Adding Generator Expressions

Generator expressions在构建系统期间求值,然后生成特定信息的配置信息。

很多生成目标属性的上下文都允许使用Generator expressions,比如LINK_LIBRARIES, INCLUDE_DIRECTORIES, COMPILE_DEFINITIONS 。在使用命令填充这些属性时也可以使用它们,比如命令target_link_libraries(), target_include_directories(), target_compile_definitions()

Generator expressions可用于启动条件链接、编译时的条件定义、条件头文件目录。这些条件基于构建配置、目标属性、平台信息或其它可查询信息。

Generator expressions包括逻辑表达式、提示表达式和输出表达式。

逻辑表达式用于产生条件输出,最基本的表达式是01,一个$<0:...>产生一个简单的字符串,一个<1:...>产生内容...,它们也可以嵌套。

Exercise 1 - Adding Compiler Warning Flags with Generator Expressions

Generator expressions的一个通用用法是有条件的添加编译选项,比如语言或者告警等级。一个不错的模式是将其关联到INTERFACE目标,从而允许这个扩展。

Goal

在构建的时候添加一个编译告警标识。

Helpful Resources

Build and Run

同上

Step 5: Installing and Testing

Exercise 1 - Install Rules

通常,仅仅构建可执行文件还不够,还应该能够安装。CMake使用特殊的命令install()来安装。本地安装很简单,指定本地安装路径和文件即可。

Goal

安装可执行文件Tutorial和库MathFunctions

Helpful Materials[¶](https://cmake.org/cmake/help/latest/guide/tutorial/Installing and Testing.html#helpful-materials)

Getting Started

  • 安装库MathFunctions/lib目录,安装库MathFunctions的头文件到/usr/include目录。
  • 安装可执行文件Tutorial/usr/bin目录,安装可执行文件Tutorial需要的头文件到/usr/include目录。

Build and Run

$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.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 (0.3s)
-- Generating done (0.0s)
-- Build files have been written to: /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step5-Exercise1/MathFunctions

[root@ubuntu] /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step5-Exercise1/MathFunctions
$ cmake --build .
[ 16%] Building C object MathFunctions/CMakeFiles/SqrtLibrary.dir/mysqrt.c.o
[ 33%] Linking C static library libSqrtLibrary.a
[ 33%] Built target SqrtLibrary
[ 50%] Building C object MathFunctions/CMakeFiles/MathFunctions.dir/MathFunctions.c.o
[ 66%] Linking C static library libMathFunctions.a
[ 66%] Built target MathFunctions
[ 83%] Building C object CMakeFiles/Tutorial.dir/tutorial.c.o
[100%] Linking C executable Tutorial
[100%] Built target Tutorial

[root@ubuntu] /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step5-Exercise1/MathFunctions
$ cmake --install .
-- Install configuration: ""
-- Installing: /usr/local/lib/libMathFunctions.a
-- Installing: /usr/local/lib/libSqrtLibrary.a
-- Installing: /usr/local/include/MathFunctions.h
-- Installing: /usr/bin/Tutorial
-- Installing: /usr/include/TutorialConfig.h

CMake变量CMAKE_INSTALL_PREFIX 用于指定安装目录的根路径,如果使用cmake --install命令,可以使用前缀--prefix参数覆盖前缀,比如:

[root@ubuntu] /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step5-Exercise1/MathFunctions
$ cmake --install . --prefix="/home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step5-Exercise1/MathFunctions/installdir"
-- Install configuration: ""
-- Installing: /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step5-Exercise1/MathFunctions/installdir/lib/libMathFunctions.a
-- Installing: /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step5-Exercise1/MathFunctions/installdir/lib/libSqrtLibrary.a
-- Installing: /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step5-Exercise1/MathFunctions/installdir/include/MathFunctions.h
-- Up-to-date: /usr/bin/Tutorial
-- Up-to-date: /usr/include/TutorialConfig.h

Exercise 2 - Testing Support

CTest提供了一种轻松的管理测试的方式。测试项可以通过命令add_test()添加。

Helpful Materials[¶](https://cmake.org/cmake/help/latest/guide/tutorial/Installing and Testing.html#id2)

Build and Run

$ cmake ..
$ cmake --build .
[ 16%] Building C object MathFunctions/CMakeFiles/SqrtLibrary.dir/mysqrt.c.o
[ 33%] Linking C static library libSqrtLibrary.a
[ 33%] Built target SqrtLibrary
[ 50%] Building C object MathFunctions/CMakeFiles/MathFunctions.dir/MathFunctions.c.o
[ 66%] Linking C static library libMathFunctions.a
[ 66%] Built target MathFunctions
[ 83%] Building C object CMakeFiles/Tutorial.dir/tutorial.c.o
[100%] Linking C executable Tutorial
[100%] Built target Tutorial
$ ctest -N
Test project /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step5-Exercise2/Step5-build
  Test  #1: Runs
  Test  #2: Usage
  Test  #3: StandardUse
  Test  #4: Comp4
  Test  #5: Comp9
  Test  #6: Comp5
  Test  #7: Comp7
  Test  #8: Comp25
  Test  #9: Comp-25
  Test #10: Comp0.0001

Total Tests: 10
[root@ubuntu] /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step5-Exercise2/Step5-build
$ ctest -vv
Test project /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step5-Exercise2/Step5-build
      Start  1: Runs
 1/10 Test  #1: Runs .............................   Passed    0.01 sec
      Start  2: Usage
 2/10 Test  #2: Usage ............................   Passed    0.00 sec
      Start  3: StandardUse
 3/10 Test  #3: StandardUse ......................***Failed  Required regular expression not found. Regex=[4 is 2
]  0.00 sec
      Start  4: Comp4
 4/10 Test  #4: Comp4 ............................***Failed  Required regular expression not found. Regex=[4 is 2
]  0.00 sec
      Start  5: Comp9
 5/10 Test  #5: Comp9 ............................***Failed  Required regular expression not found. Regex=[9 is 3
]  0.00 sec
      Start  6: Comp5
 6/10 Test  #6: Comp5 ............................***Failed  Required regular expression not found. Regex=[5 is 2.236
]  0.00 sec
      Start  7: Comp7
 7/10 Test  #7: Comp7 ............................***Failed  Required regular expression not found. Regex=[7 is 2.645
]  0.00 sec
      Start  8: Comp25
 8/10 Test  #8: Comp25 ...........................***Failed  Required regular expression not found. Regex=[25 is 5
]  0.00 sec
      Start  9: Comp-25
 9/10 Test  #9: Comp-25 ..........................***Failed  Required regular expression not found. Regex=[-25 is (-nan|nan|0)
]  0.00 sec
      Start 10: Comp0.0001
10/10 Test #10: Comp0.0001 .......................***Failed  Required regular expression not found. Regex=[0.0001 is 0.01
]  0.00 sec

20% tests passed, 8 tests failed out of 10

Total Test time (real) =   0.04 sec

The following tests FAILED:
          3 - StandardUse (Failed)
          4 - Comp4 (Failed)
          5 - Comp9 (Failed)
          6 - Comp5 (Failed)
          7 - Comp7 (Failed)
          8 - Comp25 (Failed)
          9 - Comp-25 (Failed)
         10 - Comp0.0001 (Failed)
Errors while running CTest
Output from these tests are in: /home/share/cmake/cmake-3.27.0-rc1-tutorial-source/Step5-Exercise2/Step5-build/Testing/Temporary/LastTest.log
Use "--rerun-failed --output-on-failure" to re-run the failed cases verbosely.

Step 10: Selecting Static or Shared Libraries

本章节,学习如何使用BUILD_SHARED_LIBS变量来控制add_library()命令的默认行为,并且允许控制没有显示类型(STATIC、SHARED、MODULE、OBJECT)的库的构建方法。

要实现这个目的,我们需要将BUILD_SHARED_LIBS变量添加到顶层CMakeLists.txt,可以使用option()命令来选择是否使用它。