最简单的情况
main.cpp
1 |
|
hellp.cpp
1 |
|
CMakeLists.txt
1 | cmake_minimum_required(VERSION 3.12) |
将 hello.cpp
和 main.cpp
生成一个可执行文件
库
静态库
静态库可以当成多个 .o
文件的打包,相当于直接把代码插入到生成的可执行文件中,会导致生成的可执行文件体积变大。
而动态库则只在生成的可执行文件中生成“插桩”函数,当可执行文件被加载时会读取指定目录中的 .dll
文件(或 .so
),加载到内存中空闲的位置,并且替换相应的“插桩”指向的地址为加载后的地址,这个过程称为“重定向”。
CMakeLists.txt
1 | cmake_minimum_required(VERSION 3.12) |
通过 add_library
生成一个静态库,add_executable
生成可执行文件,target_link
将静态库链接到可执行文件
动态库
CMakeLists.txt
1 | cmake_minimum_required(VERSION 3.12) |
此处会生成一个动态库 libhellolib.so
,编译后,通过命令 ldd a.out
可见:
1 | linux-vdso.so.1 (0x00007ffe8b96d000) |
头文件递归引用
容易出现“菱形”引用问题,解决方法有两种,一种是在每个头文件的开始都加入 #pragma once
,另一种用宏定义的方式。
CMake中的子模块
1 | ── CMakeLists.txt |
hellolib/CMakeLists.txt
1 | add_library(hellolib STATIC hello.cpp) |
根目录下 CMakeLists.txt
1 | cmake_minimum_required(VERSION 3.12) |
要在根目录使用,可以用 CMake
的 add_subdirectory
添加子目录,子目录也包含一个 CMakeLists.txt
,其中定义的库在 add_subdirectory
之后就可以在外面使用
因为 hello.h
被移到了 hellolib
子文件夹里,因此 main.cpp
里也要改成 #include "hellolib/hello.h"
的形式。如果要避免修改代码,可以通过 target_include_directories
指定 a.out
的头文件搜索目录。
这样甚至可以用 #include <hello.h>
来引用这个头文件。
hellolib/CMakeLists.txt
1 | add_library(hellolib STATIC hello.cpp) |
根目录下 CMakeLists.txt
1 | cmake_minimum_required(VERSION 3.12) |
只需在生成 hellolib
库的时候定义头文件搜索路径,引用他的可执行文件 CMake
会自动添加这个路径。
其他选项
target_include_directories(myapp PUBLIC /usr/include/eigen3)
# 添加头文件搜索目录
target_link_libraries(myapp PUBLIC hellolib)
# 添加要链接的库
target_add_definitions(myapp PUBLIC MY_MACRO=1)
# 添加一个宏定义
target_compile_options(myapp PUBLIC -fopenmp)
# 添加编译器命令行选项
target_sources(myapp PUBLIC hello.cpp other.cpp)
# 添加要编译的源文件
以及可以通过以下指令(不推荐使用),把选项加到所有接下来的目标去:
include_directories(/opt/cuda/include)
# 添加头文件搜索目录
link_directories(/opt/cuda)
# 添加库文件的搜索路径
add_definitions(MY_MACRO=1)
# 添加一个宏定义
add_compile_options(-fopenmp)
# 添加编译器命令行选项
这些命令是全局的。
引用系统中预安装的第三方库,如使用 apt
或 pacman
等安装的库,可以使用下面的方式:
1 | find_package(fmt REQUIRED) |
现代 CMake 认为一个package可以提供多个components,如TBB这个包,就包含了tbb, tbbmalloc, tbbmalloc_proxy 这三个components,为避免冲突,每个package都享有一个独立的名字空间,以 ::
分割。可以手动指定需要的组件:
1 | find_package(TBB REQUIRED COMPONENTS tbb tbbmalloc REQUIRED) |