1. Compiling a single source file into an executable

CMakeLists.txt

  • cmake_minimum_required: 设置CMake所需的最低版本
  • project: 声明项目名称, 支持的编程语言
    • LANGUAGES选项显示声明项目的语言
  • 指示CMake创建一个新目标
    • add_executable: 可执行文件, 用过编译和链接源文件hello-world.cpp生成
    • CMake将为编译器使用默认设置,并自动选择生成工具 ```

      set minimum cmake version

      cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project name and language

project(recipe-01 LANGUAGES CXX)

add_executable(hello-world hello-world.cpp)

  1. `hello-world.cpp`
  2. ```cpp
  3. #include <cstdlib>
  4. #include <iostream>
  5. #include <string>
  6. std::string say_hello() { return std::string("Hello, CMake world!"); }
  7. int main() {
  8. std::cout << say_hello() << std::endl;
  9. return EXIT_SUCCESS;
  10. }

image.png

  1. mkdir -p build
  2. cd build
  3. cmake..

cmake -H. Bbuild等效

尝试命令行执行后失败,.并未生成可执行文件

  • 根据提示,未找到编译器

image.png image.png

文件

  • cmake_install.cmake
  • Makefile
  • CMakefile
  • CMakeCache.txt

cmake不强制指定构建目录执行名称或位置

Running CMake

  1. PS C:\DevelopProject\SourceCode\LearnCmake\00_HelloWorld\cmake-build-debug> cmake --build . --target help
  2. The following are some of the valid targets for this Makefile:
  3. ... all (the default if no target is provided)
  4. ... clean
  5. ... depend
  6. ... edit_cache
  7. ... rebuild_cache
  8. ... hello-world
  9. ... hello-world.o
  10. ... hello-world.i
  11. ... hello-world.s
  • all(或Visual Studio generator中的ALL_BUILD)是默认目标,将在项目中构建所有目标。
  • clean,删除所有生成的文件。
  • rebuild_cache,将调用CMake为源文件生成依赖(如果有的话)。
  • edit_cache,这个目标允许直接编辑缓存。

对于更复杂的项目,通过测试阶段和安装规则,CMake将生成额外的目标:

  • test(或Visual Studio generator中的RUN_TESTS)将在CTest的帮助下运行测试套件。将在第4章中详细讨论测试和CTest。
  • install,将执行项目安装规则。我们将在第10章中讨论安装规则。
  • package,此目标将调用CPack为项目生成可分发的包。打包和CPack将在第11章中讨论。

2. Switching generators

3. Building and linking static and shared libraries

  • 项目中会有单个源文件构建的多个可执行文件的可能
  • 项目中有多个源文件,通常分布在不同子目录中

这种实践有助于项目的源代码结构,而且支持模块化、代码重用和关注点分离。同时,这种分离可以简化并加速项目的重新编译。

STATIC

CMakeLists.txt

  • add_library(message STATIC Message.hpp Message.cpp): 生成静态库
    • 第二个参数
      • STATIC: 用于创建静态库,即编译文件的打包存档,以便在链接其他目标时使用
      • SHARED: 用于创建动态库,即可以动态链接,并在运行时加载的库
      • OBJECT: 可将给定 add_library 的列表中的源码编译到目标文件,不将它们归档到静态库中,也不能将它们链接到共享对象中。如果需要一次性创建静态库和动态库,那么使用对象库尤其有用。
      • MODULE: 又为DSO组。与 SHARED 库不同,它们不链接到项目中的任何目标,不过可以进行动态加载。该参数可以用于构建运行时插件。
  • target_link_libraries: 将目标库链接到可执行目标 ```

    set minimum cmake version

    cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project name and language

project(BuildLibrary LANGUAGES CXX)

generate a library from sources

add_library(message STATIC Message.h Message.cpp )

add_executable(hello-world hello-world.cpp)

target_link_libraries(hello-world message)

  1. `hello-world.cpp`
  2. ```cpp
  3. #include "Message.cpp"
  4. #include <cstdlib>
  5. #include <iostream>
  6. int main() {
  7. Message say_hello("Hello, CMake World!");
  8. std::cout << say_hello << std::endl;
  9. Message say_goodbye("Goodbye, CMake World");
  10. std::cout << say_goodbye << std::endl;
  11. return EXIT_SUCCESS;
  12. }

Message.h

  1. #ifndef HELLO_WORLD_MESSAGE_H
  2. #define HELLO_WORLD_MESSAGE_H
  3. #include <iosfwd>
  4. #include <string>
  5. class Message {
  6. public:
  7. Message(const std::string &m) : message_(m) {}
  8. friend std::ostream &operator<<(std::ostream &os, Message &obj) {
  9. return obj.printObject(os);
  10. }
  11. private:
  12. std::string message_;
  13. std::ostream &printObject(std::ostream &os);
  14. };
  15. #endif //HELLO_WORLD_MESSAGE_H

Message.cpp

  1. #include "Message.h"
  2. #include <iostream>
  3. #include <string>
  4. std::ostream &Message::printObject(std::ostream &os) {
  5. os << "This is my very nice message: " << std::endl;
  6. os << message_;
  7. return os;
  8. }

CMake还能够生成特殊类型的库,这不会在构建系统中产生输出,但是对于组织目标之间的依赖关系,和构建需求非常有用:

  • IMPORTED: 此类库目标表示位于项目外部的库。此类库的主要用途是,对现有依赖项进行构建。因此, IMPORTED 库将被视为不可变的。
  • INTERFACE: 与 IMPORTED 库类似。不过,该类型库可变,没有位置信息。它主要用于项目之外的目标构建使用。
  • ALIAS: 顾名思义,这种库为项目中已存在的库目标定义别名。不过,不能为 IMPORTED 库选择别名。

    OBJECT

    CMakeLists.txt

  • add_library(Message-objs OBJECT Message.hpp Message.cpp)

  • set_target_properties(message-objs PROPERTIES POSITION_INDEPENDENT_CODE 1):保证编译的目标文件与生成位置无关

    • ```

      set minimum cmake version

      cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project name and language

project(recipe-03 LANGUAGES CXX)

generate an object library from sources

add_library(message-objs OBJECT Message.hpp Message.cpp )

this is only needed for older compilers

but doesn’t hurt either to have it

set_target_properties(message-objs PROPERTIES POSITION_INDEPENDENT_CODE 1 )

add_library(message-shared SHARED $ )

add_library(message-static STATIC $ )

add_executable(hello-world hello-world.cpp)

target_link_libraries(hello-world message-static)

  1. 是否可以让CMake生成同名的两个库?换句话说,它们都可以被称为 message ,而不是 message-static message-shared?<br />修改这两个目标的属性

add_library(message-shared SHARED $ )

set_target_properties(message-shared PROPERTIES OUTPUT_NAME “message” )

add_library(message-static STATIC $ )

set_target_properties(message-static PROPERTIES OUTPUT_NAME “message” ) ```