CMake 笔记 | [39] 构建项目策略及限制变量范围2

注意
本文最后更新于 2024-02-01,文中内容可能已过时。

一、导言

导言

本篇,我们将讨论上一篇的另一种方法,并不使用add_subdirectory的情况下,使用module include组装不同的CMakeLists.txt文件。其允许我们使用target_link_libraries链接到当前目录之外定义的目标。

就项目架构而言,不推荐本篇的构建方式。

二、项目结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
.
├── CMakeLists.txt
├── external
│   ├── CMakeLists.txt
│   ├── conversion.cpp
│   └── conversion.hpp
├── src
│   ├── CMakeLists.txt
│   ├── evolution
│   │   ├── CMakeLists.txt
│   │   ├── evolution.cpp
│   │   └── evolution.hpp
│   ├── initial
│   │   ├── CMakeLists.txt
│   │   ├── initial.cpp
│   │   └── initial.hpp
│   ├── io
│   │   ├── CMakeLists.txt
│   │   ├── io.cpp
│   │   └── io.hpp
│   ├── main.cpp
│   └── parser
│       ├── CMakeLists.txt
│       ├── parser.cpp
│       └── parser.hpp
└── tests
    ├── catch.hpp
    ├── CMakeLists.txt
    └── test.cpp

项目地址:

https://gitee.com/jiangli01/tutorials/tree/master/cmake-tutorial/chapter7/08

三、相关源码

将使用与上一篇相同的源代码。唯一的更改将出现在CMakeLists.txt文件中,我们将在下面的部分中讨论这些更改。 CMakeLists.txt

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(example LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(GNUInstallDirs)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
# defines targets and sources
include(src/CMakeLists.txt)
include(external/CMakeLists.txt)
enable_testing()
add_subdirectory(tests)

src/CMakeLists.txt

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
add_library(automaton "")
add_library(evolution "")
include(${CMAKE_CURRENT_LIST_DIR}/evolution/CMakeLists.txt)
include(${CMAKE_CURRENT_LIST_DIR}/initial/CMakeLists.txt)
include(${CMAKE_CURRENT_LIST_DIR}/io/CMakeLists.txt)
include(${CMAKE_CURRENT_LIST_DIR}/parser/CMakeLists.txt)
add_executable(automata "")
target_sources(automata
  PRIVATE
      ${CMAKE_CURRENT_LIST_DIR}/main.cpp
  )
target_link_libraries(automata
  PRIVATE
    automaton
    conversion
  )

src/evolution/CMakeLists.txt

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
target_sources(automaton
  PRIVATE
      ${CMAKE_CURRENT_LIST_DIR}/evolution.cpp
  PUBLIC
      ${CMAKE_CURRENT_LIST_DIR}/evolution.hpp
  )
target_include_directories(automaton
  PUBLIC
      ${CMAKE_CURRENT_LIST_DIR}
  )
target_sources(evolution
  PRIVATE
      ${CMAKE_CURRENT_LIST_DIR}/evolution.cpp
  PUBLIC
      ${CMAKE_CURRENT_LIST_DIR}/evolution.hpp
  )
target_include_directories(evolution
  PUBLIC
      ${CMAKE_CURRENT_LIST_DIR}
  )

其余CMakeLists.txt文件和src/initial/CMakeLists.txt相同。

src/initial/CMakeLists.txt

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
target_sources(automaton
  PRIVATE
      ${CMAKE_CURRENT_LIST_DIR}/initial.cpp
  PUBLIC
      ${CMAKE_CURRENT_LIST_DIR}/initial.hpp
  )
target_include_directories(automaton
  PUBLIC
      ${CMAKE_CURRENT_LIST_DIR}
  )

定义了三个库:

  • conversion(在external定义)
  • automaton(包含除转换之外的所有源)
  • evolution(在src/evolution中定义,并通过cpp_test链接)

我们通过使用include()引用CMakeLists.txt文件,在父范围内,仍然能保持所有目标可用。

1
2
include(src/CMakeLists.txt)
include(external/CMakeLists.txt)

构建一个包含树,记住当进入子目录(src/CMakeLists.txt)时,我们需要使用相对于父范围的路径:

1
2
3
4
include(${CMAKE_CURRENT_LIST_DIR}/evolution/CMakeLists.txt)
include(${CMAKE_CURRENT_LIST_DIR}/initial/CMakeLists.txt)
include(${CMAKE_CURRENT_LIST_DIR}/io/CMakeLists.txt)
include(${CMAKE_CURRENT_LIST_DIR}/parser/CMakeLists.txt)

这样,我们就可以定义并链接到通过include()语句访问文件树中任何位置的目标。

四、结果展示

1
2
3
4
5
6
7
8
$ cd build
$ cmake ..
$ cmake --build build
$ ctest
Running tests...
Start 1: test_evolution
1/1 Test #1: test_evolution ................... Passed 0.00 sec
100% tests passed, 0 tests failed out of 1

补充内容

我们可以再次使用CMakeGraphviz生成这个项目的依赖关系图:

1
2
3
$ cd build
$ cmake --graphviz=example.dot ..
$ dot -T png example.dot -o example.png


项目结构

Buy me a coffee~
支付宝
微信
0%