在 hello-cmake 中,我们只用了一个单文件 main.cpp,现在开始用多文件学习编译。

一、文件树

  1. ├── CMakeLists.txt
  2. ├── include
  3. └── Hello.h
  4. └── src
  5. ├── Hello.cpp
  6. └── main.cpp

以下是上述文件树中的文件具体内容

1.1 Hello.h

  1. /* 声明了Hello类,Hello的方法是print() */
  2. #ifndef __HELLO_H__
  3. #define __HELLO_H__
  4. class Hello {
  5. public:
  6. void print();
  7. };
  8. #endif

1.2 Hello.cpp

  1. /* 实现了Hello::print() */
  2. #include <iostream>
  3. #include "Hello.h"
  4. void Hello::print()
  5. {
  6. std::cout << "Hello Headers!" << std::endl;
  7. }

1.3 main.cpp

  1. #include "Hello.h"
  2. int main(int argc, char *argv[])
  3. {
  4. Hello hellObj;
  5. hellObj.print();
  6. return 0;
  7. }

1.4 CMakeLists.txt

  1. cmake_minimum_required(VERSION 3.5) # 最低CMake版本
  2. project(hello_headers) # 工程名
  3. set(SOURCES # 创建一个变量,名为SOURCE,它包含所有的cpp文件
  4. src/Hello.cpp
  5. src/main.cpp
  6. )
  7. # 指定源文件
  8. add_executable(hello_headers ${SOURCES}) # 用所有的源文件生成一个可执行文件,因为这里
  9. # 定义了 SOURCE 变量,所以就不需要罗列文件
  10. ##等价命令 add_executable(hello_headers src/Hello.cpp src/main.cpp)
  11. # 指定头文件
  12. target_include_directories(hello_headers # 设置这个可执行文件hello_headers需要包含的
  13. PRIVATE # 库的路径
  14. ${PROJECT_SOURCE_DIR}/include
  15. )

上述命令中的指令解释如下:

  • PROJECT_SOURCE_DIR:工程顶层目录
  • PROJECT_BINARY_DIR:编译目录
  • PRIVATE:指定库的范围

二、CMake解析

2.1 各种可用变量

CMake 语法指定了许多变量,可用于帮助您在项目或源代码树中找到有用的目录。 其中一些包括:

Variable Info
CMAKE_SOURCE_DIR 根源代码目录,工程顶层目录。暂认为就是 PROJECT_SOURCE_DIR
CMAKE_CURRENT_SOURCE_DIR 当前处理的 CMakeLists.txt 所在的路径
PROJECT_SOURCE_DIR 工程顶层目录
CMAKE_BINARY_DIR 运行 cmake 的目录。外部构建时就是build目录
CMAKE_CURRENT_BINARY_DIR The build directory you are currently in.当前所在 build 目录
PROJECT_BINARY_DIR 暂认为就是 CMAKE_BINARY_DIR

想仔细体会一下,可以在 CMakeLists.txt 中,利用 message() 命令输出一下这些变量。

另外,这些变量不仅可以在 CMakeLists.txt 中使用,同样可以在 源代码.cpp 中使用。

2.2 源文件变量(不建议!)

创建一个包含源文件的变量,以便于将其轻松添加到多个命令中,例如 add_executable() 函数。

  1. set(SOURCES
  2. src/Hello.cpp
  3. src/main.cpp
  4. )
  5. add_executable(${PROJECT_NAME} ${SOURCES})

SOURCES 变量中设置特定文件名的另一种方法是使用 GLOB 命令使用通配符模式匹配来查找文件。file(GLOB SOURCES "src/*.cpp")使用*这个通配符,表示所有.cpp结尾的文件都会包含到这个SOURCES变量。

对于 modern CMake,不建议对源文件使用变量。 不建议使用 glob

相反,通常直接在 add_xxx 函数中声明源文件。

这对于 glob 命令尤其重要,如果添加新的源文件,这些命令可能不会始终为您显示正确的结果。在 CMake 中指定源文件的最佳方法是明确列出它们。

2.3 包含目录

当您有其他需要包含的文件夹(文件夹里有头文件)时,可以使用以下命令使编译器知道它们: **target_include_directories()**。 编译此目标时,这将使用 -I 标志将这些目录添加到编译器中,例如-I /目录/路径

  1. target_include_directories(target
  2. PRIVATE
  3. ${PROJECT_SOURCE_DIR}/include
  4. )

PRIVATE 标识符指定包含的范围。 这对库很重要,将在下一个示例中进行说明。 有关该功能的更多详细信息,请参见以下链接:https://cmake.org/cmake/help/v3.0/command/target_include_directories.html

2.4 详细输出

在前面的示例中,运行 make 命令时,输出仅显示构建状态。 要查看用于调试目的的完整输出,可以在运行 make 时添加 VERBOSE=1标志。

下面的代码是使用 VERBOSE 的命令

  1. mkdir build
  2. cd build/
  3. cmake ..
  4. make VERBOSE=1
  • 没有 VERBOSE

    1. make
    2. [ 33%] Building CXX object CMakeFiles/hello_headers.dir/src/Hello.cpp.o
    3. [ 66%] Building CXX object CMakeFiles/hello_headers.dir/src/main.cpp.o
    4. [100%] Linking CXX executable hello_headers
    5. [100%] Built target hello_headers
  • VERBOSE

    1. make VERBOSE=1
    2. /usr/bin/cmake -S/root/CmakeTest -B/root/CmakeTest/build --check-build-system CMakeFiles/Makefile.cmake 0
    3. /usr/bin/cmake -E cmake_progress_start /root/CmakeTest/build/CMakeFiles /root/CmakeTest/build//CMakeFiles/progress.marks
    4. make -f CMakeFiles/Makefile2 all
    5. make[1]: Entering directory '/root/CmakeTest/build'
    6. make -f CMakeFiles/hello_headers.dir/build.make CMakeFiles/hello_headers.dir/depend
    7. make[2]: Entering directory '/root/CmakeTest/build'
    8. cd /root/CmakeTest/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /root/CmakeTest /root/CmakeTest /root/CmakeTest/build /root/CmakeTest/build /root/CmakeTest/build/CMakeFiles/hello_headers.dir/DependInfo.cmake --color=
    9. make[2]: Leaving directory '/root/CmakeTest/build'
    10. make -f CMakeFiles/hello_headers.dir/build.make CMakeFiles/hello_headers.dir/build
    11. make[2]: Entering directory '/root/CmakeTest/build'
    12. [ 33%] Building CXX object CMakeFiles/hello_headers.dir/src/Hello.cpp.o
    13. /usr/bin/c++ -I/root/CmakeTest/include -MD -MT CMakeFiles/hello_headers.dir/src/Hello.cpp.o -MF CMakeFiles/hello_headers.dir/src/Hello.cpp.o.d -o CMakeFiles/hello_headers.dir/src/Hello.cpp.o -c /root/CmakeTest/src/Hello.cpp
    14. [ 66%] Building CXX object CMakeFiles/hello_headers.dir/src/main.cpp.o
    15. /usr/bin/c++ -I/root/CmakeTest/include -MD -MT CMakeFiles/hello_headers.dir/src/main.cpp.o -MF CMakeFiles/hello_headers.dir/src/main.cpp.o.d -o CMakeFiles/hello_headers.dir/src/main.cpp.o -c /root/CmakeTest/src/main.cpp
    16. [100%] Linking CXX executable hello_headers
    17. /usr/bin/cmake -E cmake_link_script CMakeFiles/hello_headers.dir/link.txt --verbose=1
    18. /usr/bin/c++ -rdynamic CMakeFiles/hello_headers.dir/src/Hello.cpp.o CMakeFiles/hello_headers.dir/src/main.cpp.o -o hello_headers
    19. make[2]: Leaving directory '/root/CmakeTest/build'
    20. [100%] Built target hello_headers
    21. make[1]: Leaving directory '/root/CmakeTest/build'
    22. /usr/bin/cmake -E cmake_progress_start /root/CmakeTest/build/CMakeFiles 0