Blog reference from: Da Cing who loves programming: https://subingwen.cn/cmake/CMake-primer/ , for learning and sharing only
If 项目很大
, or there are many source code directories in the project, if only one is used when managing the project through CMake CMakeLists.txt
, then this file will be relatively complicated. One 化繁为简
way is to 每个源码目录
add a CMakeLists.txt
file (the header file directory is not required), 这样每个文件都不会太复杂,而且更灵活,更容易维护
.
Let's take a look at the following directory structure:
$ tree
.
├── build
├── calc
│ ├── add.cpp
│ ├── CMakeLists.txt
│ ├── div.cpp
│ ├── mult.cpp
│ └── sub.cpp
├── CMakeLists.txt
├── include
│ ├── calc.h
│ └── sort.h
├── sort
│ ├── CMakeLists.txt
│ ├── insert.cpp
│ └── select.cpp
├── test1
│ ├── calc.cpp
│ └── CMakeLists.txt
└── test2
├── CMakeLists.txt
└── sort.cpp
6 directories, 15 files
include 目录
: header file directorycalc 目录
: The addition, subtraction, multiplication, and division algorithms corresponding to the four source files in the directory- The corresponding header file is calc.h
include
in
- The corresponding header file is calc.h
sort 目录
: The two source files in the directory correspond to the insertion sort and selection sort algorithms- The corresponding header file is
include
sort.h in
- The corresponding header file is
test1 目录
加、减、乘、除
: Test directory, to test the algorithm implemented in calctest2 目录
: Test directory, to test the sorting algorithm implemented in sort
As can be seen from the directory structure, two executable files will eventually be generated, one related to calculators and the other related to sorting. If all operations are written in the top level CMakeLists.txt
, then CMakeLists.txt
the content of this will be more complicated. Sometimes, in order to make these script files easier to maintain, we can split the content of the file by breaking them one by one, and process each source file CMakeLists.txt
separately
There are several source files in the calc directory, we add one in this directory CMakeLists
to manage these source files. There are two sorted source files in the sort directory, we can sort
also add one in the directory CMakeLists.txt
; for a test file in test
and respectively, we add one in andtest2
test1
test2
CMakeLists.txt
After adding these files, you need to CMakeLists.txt
define them through the top level 若干个CMakeLists.txt形成父子关系
. How to let the parent node bind these child nodes? Use add_subdirectory
to add these subdirectories. This way, the top-level CMakeLists knows about its children.
In each CMakeLists.txt, we can set some 变量
. When we define some variables in the parent node, the variables defined in the parent node can be used by the child nodes ( 父节点定义的这些变量是全局变量
), in 子节点中定义的变量称为局部变量
. Parent nodes cannot use variables of child nodes, but variables defined by parent nodes can be used in child nodes.
1 Preparations
1.1 Node relationship
As we all know, the Linux directory is a tree structure, so the nested CMake is also a tree structure, 最顶层
and the CMakeLists.txt is 根节点
, 其次
both 子节点
. Therefore, we need to know some information about the scope of variables in the CMakeLists.txt file:
根节点
Variables in CMakeLists.txt are globally available父节点
Variables in CMakeLists.txt can be used in child nodes子节点
Variables in CMakeLists.txt can only be used in the current node
1.2 Add a subdirectory
Next, we also need to know how the relationship between parent and child nodes is established in CMake. Here we need to use a CMake command
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
Note source_dir
that the specified is where the child node CMakeLists.txt is located目录
source_dir
: Specifies the location of the CMakeLists.txt source file and code file, which is actually the specified subdirectorybinary_dir
: Specify the path of the output file, generally do not need to specify, just ignore it.EXCLUDE_FROM_ALL
: The targets under the sub-path will not be included in the ALL target of the parent path by default, and will also be excluded from the IDE project file. Users must explicitly build targets under subpaths.
In this way between CMakeLists.txt files父子关系就被构建出来了
2 Examples
Project directory structure image
├── CMakeLists.txt
├── calc
│ ├── add.cpp
│ ├── CMakeLists.txt
│ ├── div.cpp
│ ├── mult.cpp
│ └── sub.cpp
├── include
│ ├── calc.h
│ └── sort.h
├── sort
│ ├── CMakeLists.txt
│ ├── insert.cpp
│ └── select.cpp
├── test1
│ ├── calc.cpp
│ └── CMakeLists.txt
└── test2
├── CMakeLists.txt
└── sort.cpp
- First there is a root node, there is one in the root node
CMakeList.txt
, and then there are4
child nodes, respectivelycalc
,sort
,test1
,test2
, and these child nodes have their ownCMakeLists.txt
分析:
The role of CMakeLists intest1
andtest2
is actually to generate them separately一个可执行程序
, assuming they are app1 and app2 respectively; forcalc
the four source files in the directoryadd.cpp
,div.cpp
,mult.cpp
,sub.cpp
, in fact, it provides an interface for calc.cpp in test1, so we need to put it Generate the corresponding库文件
(dynamic/static library).insert.cpp
The same is true for the source files in the sort directoryselect.cpp
, which provide an interface for sort.cpp in test2, and we also generate library files (dynamic/static libraries)库文件的本质其实还是代码,只不过是从文本格式变成了二进制格式
。
How to choose whether to generate a static library or a dynamic library?
- In the end is to generate a dynamic library or a static library? In fact, both of these are possible,
推荐
: in源文件非常多,推荐生成动态库;在源文件比较少的情况,推荐生成静态库
. - If generated
动态库
, its corresponding source code will not be in the packaged executable file, if it is,静态库
it will打包
go inside the executable file. If we finally require that the generated executable file is very small, then we can generate a dynamic library from these source files, and then when releasing the application, we must provide the dynamic library to the program user; There is no requirement for the size of the executable file, and it is required to be relatively easy to use. We can generate these source files into a static library. After the static library is generated, these source files will be packaged into an executable file. Just execute the program, no need to publish additional library files. - The usage
静态库的缺点
is finally generated可执行文件会比较大
, and if you start multiple executable programs, it takes up物理内存
more than the dynamic library大
. Because if the program is using动态库
, no matter how many executables are started, yes内存中动态库有且只有一份
, yes共享的
.
2.1 root directory
根目录
The CMakeLists.txt in the file can define some 全局变量
, and the defined variables can be used for sub-nodes, such as: definition 头文件的路径
, generation 可执行文件的名字
, and sub-node generation 库文件的存储路径
, etc., which can CMakeLists.txt
be defined first in the root directory. Later, directly use the variables defined by the root node in the child nodes to find the corresponding path.
The content of the CMakeLists.txt file in the root directory is as follows:
cmake_minimum_required(VERSION 3.0)
project(test)
# 定义变量
# 静态库生成的路径
set(LIB_PATH ${
CMAKE_CURRENT_SOURCE_DIR}/lib) #lib子目录不需要自己去创建,如果lib目录没有,会自动创建
# 测试程序生成的路径
set(EXEC_PATH ${
CMAKE_CURRENT_SOURCE_DIR}/bin) #bin 也会自动创建
# 头文件目录
set(HEAD_PATH ${
CMAKE_CURRENT_SOURCE_DIR}/include)
# 静态库的名字
set(CALC_LIB calc)
set(SORT_LIB sort)
# 可执行程序的名字
set(APP_NAME_1 test1)
set(APP_NAME_2 test2)
# 添加子目录
add_subdirectory(calc)
add_subdirectory(sort)
add_subdirectory(test1)
add_subdirectory(test2)
There are two main things done in the file corresponding to the root node: 定义全局变量
and 添加子目录
.
- Defined
全局变量主要是给子节点使用
, the purpose is to improve the readability and maintainability of the CMakeLists.txt file in the child node, avoid redundancy and reduce the probability of business trips. - A total of four subdirectories have been added, and each subdirectory has a
CMakeLists.txt
file , so their parent-child relationship is determined.
2.2 CMakeList.txt in the subdirectory
CMakeList.txt
After writing the top-level CMakeList.txt, files in the 4 subdirectories can now be written .
2.2.1 calc directory
The content of the CMakeLists.txt file in the calc directory is as follows:
cmake_minimum_required(VERSION 3.0)
project(CALCLIB)
aux_source_directory(./ SRC) # ./ 表示当前 cmakelist.txt所在目录下
include_directories(${
HEAD_PATH}) # 定义依赖的头文件的搜索路径
set(LIBRARY_OUTPUT_PATH ${
LIB_PATH})
add_library(${
CALC_LIB} STATIC ${
SRC})
- Line 3
aux_source_directory
: Search all source files in the current directory (calc directory) - Line 4
include_directories
: Contains the header file path, HEAD_PATH is defined in the root node file - Line 5
set
: Set the generated path of the library, LIB_PATH is defined in the root node file - Line 6
add_library
: Generate a static library, the name of the static libraryCALC_LIB
is defined in the root node file
2.2.2 sort directory
The sort directory is also a generated library file, which is actually similar to the writing method of CMakelists.txt in calc. The content of the CMakeLists.txt file in the sort directory is as follows:
cmake_minimum_required(VERSION 3.0)
project(SORTLIB)
aux_source_directory(./ SRC)
include_directories(${
HEAD_PATH})
set(LIBRARY_OUTPUT_PATH ${
LIB_PATH})
add_library(${
SORT_LIB} SHARED ${
SRC}) # 也可以生成静态库
- Line 6
add_library
: Generate a dynamic library, the dynamic library name SORT_LIB is defined in the root node file - The content in this file is similar to that in the calc node file, except that this time a dynamic library is generated.
When generating
库文件
, this library can be静态库
or can be动态库
, and generally needs to be determined according to the actual situation. If generated库比较大,建议将其制作成动态库
.
2.2.3 test1 directory
test1 is generated 可执行文件
, the executable depends on libcalc.a
the static library generated above. It needs to 链接静态库
be compiled to get the current executable program. The content of the CMakeLists.txt file in the test1 directory is as follows:
cmake_minimum_required(VERSION 3.0)
project(CALCTEST)
aux_source_directory(./ SRC) # 搜索的还是当前cmakelist目录下的源文件
include_directories(${
HEAD_PATH})
# include_directories(${
HEAD_PATH})
link_directories(${
LIB_PATH})
link_libraries(${
CALC_LIB})
set(EXECUTABLE_OUTPUT_PATH ${
EXEC_PATH})
add_executable(${
APP_NAME_1} ${
SRC})
Since the static library is generated by itself, just specify the static library name, cmake does not know the storage path of the static library, so you also need to specify the path of the static library that needs to be linked:link_directories
- Line 4
include_directories
: Specify the header file path, the HEAD_PATH variable is defined in the root node file - Line 6
link_libraries
: Specifies可执行程序要链接的静态库
that the CALC_LIB variable is defined in the root node file - Line 7
set
: Specify the path generated by the executable program, the EXEC_PATH variable is defined in the root node file - Line 8
add_executable
: Generate an executable program, the APP_NAME_1 variable is defined in the root node file
The executable program here is linked to the static library, and finally the static library will be packaged into the executable program. After the executable program is started, the static library will be loaded into the memory.
2.2.4 test2 directory
Like test1, the CMakeLists in the test2 directory also generates an executable file, and the instructions in CMakelists.txt are basically the same. The content of the CMakeLists.txt file in the test2 directory is as follows:
cmake_minimum_required(VERSION 3.0)
project(SORTTEST)
aux_source_directory(./ SRC)
include_directories(${
HEAD_PATH})
set(EXECUTABLE_OUTPUT_PATH ${
EXEC_PATH})
link_directories(${
LIB_PATH})
add_executable(${
APP_NAME_2} ${
SRC})
target_link_libraries(${
APP_NAME_2} ${
SORT_LIB})
- The fourth line
include_directories
: contains the header file path, the HEAD_PATH variable is defined in the root node file - The fifth line set: specify the path generated by the executable program, the EXEC_PATH variable is defined in the root node file
- Line 6
link_directories
: Specify the path of the dynamic library to be linked by the executable program, the LIB_PATH variable is defined in the root node file - Line 7
add_executable
: Generate an executable program, the APP_NAME_2 variable is defined in the root node file - The eighth line
target_link_libraries
: Specify the name of the dynamic library to be linked by the executable program,target_link_libraries
which needs to beadd_executable
after the command, because the executable file must be generated first, and then target_link_libraries can link the library file to the executable file
When generating an executable program,
动态库不会被打包到可执行程序内部。当可执行程序启动之后动态库也不会被加载到内存,只有可执行程序调用了动态库中的函数的时候,动态库才会被加载到内存中,且多个进程可以共用内存中的同一个动态库,所以动态库又叫共享库
.
2.2 Build the project
After everything is ready, start building the project, enter the build directory of the root node directory, and execute cmake
the command as follows:
$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/robin/abc/cmake/calc/build
一些文件
You can see that and are generated in the build directory 目录
, as follows:
$ tree build -L 1
build
├── calc # 目录
├── CMakeCache.txt # 文件
├── CMakeFiles # 目录
├── cmake_install.cmake # 文件
├── Makefile # 文件
├── sort # 目录
├── test1 # 目录
└── test2 # 目录
Then execute the make command in the build directory:
the following information can be obtained through the above figure:
lib
The static library is generated in a directory in the root of the projectlibcalc.a
lib
The dynamic library is generated in the directory of the root of the projectlibsort.so
- The executable program is generated in
bin
the directorytest1
bin
The executable program is generated in the directory of the root directory of the projecttest2
Finally, let’s take a look at whether the files mentioned above are actually generated into the corresponding directories:
$ tree bin/ lib/
bin/
├── test1
└── test2
lib/
├── libcalc.a
└── libsort.so
At this point, the project is built.
In the project, if a module in the program is made into a dynamic library or a static library
并且在CMakeLists.txt 中指定了库的输出目录
, and then other modules need to load the generated library file, it can be used directly at this time,如果没有指定库的输出路径或者需要直接加载外部提供的库文件,此时就需要使用 link_directories 将库文件路径指定出来
.