Basic 04-shared-library
# 介绍
这个例子只要解释 CMake 的两个知识:
- 如何创建并使用一个共享库
- 如何创建并使用一个目标别名 (alias target)
- 理解静态库和共享库
本例的目录🌲:
.
├── CMakeLists.txt
├── include
│ └── shared
│ └── Hello.h
└── src
├── Hello.cpp
└── main.cpp
2
3
4
5
6
7
8
# 概念解释
# 创建一个共享库
具体解释见 [03-static-library]。
add_library(hello_library SHARED
src/Hello.cpp
)
2
3
# 目标别名 (Alias Target)
目标别名是一个目标的另一个名字,可以在只读 (read-only) 的环境中和目标的真实名字发生替换。使用别名有助于使代码更易于阅读和理解,因为它们允许您使用更具描述性的名称来引用目标,同时保留了原始目标的构建属性。
add_library(hello::library ALIAS hello_library)
# 链接一个共享库
链接一个共享库和链接一个静态库是类似的,都是使用 target_link_library() 进行链接。
add_executable(hello_binary
src/main.cpp
)
target_link_libraries(hello_binary
PRIVATE
hello::library
)
2
3
4
5
6
7
8
这会告诉 CMake 将 hello_binary 和 hello_library 进行链接 (这里使用的是 hello_library 的别名 (hello::library))
(同时记得哦,hello_library 的 INTERFACE_INCLUDE_DIRECTORIES 属性中的路径会传到 hello_binary 的包含路径 INCLUDE_DIRECTORIES 属性中, 这一点以后看到 target_link_libraries 要有本能的反应)
在本例中这会在链接器中产生如下命令:
/usr/bin/c++ CMakeFiles/hello_binary.dir/src/main.cpp.o -o hello_binary -rdynamic libhello_library.so -Wl,-rpath,/home/matrim/workspace/cmake-examples/01-basic/D-shared-library/build
-Wl,-rpath,/home/matrim/workspace/cmake-examples/01-basic/D-shared-library/build : 选项表示告诉链接器在运行时将搜索库的路径,这里是将要链接的共享库的路径。
# 构建本例
$ mkdir build
$ cd build
$ cmake ..
-- The C compiler identification is GNU 9.4.0
-- The CXX compiler identification is GNU 9.4.0
-- Check for working C compiler: /usr/lib/ccache/cc
-- Check for working C compiler: /usr/lib/ccache/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/lib/ccache/c++
-- Check for working CXX compiler: /usr/lib/ccache/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/tartarus/cmake/cmake-examples/01-basic/D-shared-library/build
$ make
Scanning dependencies of target hello_library
[ 25%] Building CXX object CMakeFiles/hello_library.dir/src/Hello.cpp.o
[ 50%] Linking CXX shared library libhello_library.so
[ 50%] Built target hello_library
Scanning dependencies of target hello_binary
[ 75%] Building CXX object CMakeFiles/hello_binary.dir/src/main.cpp.o
[100%] Linking CXX executable hello_binary
[100%] Built target hello_binary
$ ls
CMakeCache.txt CMakeFiles cmake_install.cmake hello_binary libhello_library.so Makefile
$ ./hello_binary
Hello Shared Library!
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
30
31
32
33
34
35
36
# 共享库和静态库的区别
静态库(Static Library)是一组编译好的目标文件的集合,它们被打包在一起形成一个单独的文件,通常以 ".a" 或 ".lib" 为扩展名。静态库在链接时被静态地链接到目标二进制文件中,也就是说,目标文件会把整个静态库的代码复制一份并打包进二进制文件中。这意味着,它们被完全包含在生成的可执行文件中。静态库的优点是便于使用,没有外部依赖,而且在编译时就可以检测到库的错误。但是,它们的缺点是增加了可执行文件的大小,因为库的所有代码都会被复制到每个使用它的二进制文件中,也就是说每个目标文件都包含一份完整的代码。
共享库(Shared Library),也称为动态库(Dynamic Library),是一组被编译好的目标文件的集合,它们被打包在一起形成一个单独的文件,通常以 ".so" 或 ".dll" 为扩展名。共享库在链接时动态地链接到目标二进制文件中,也就是说,在运行时,目标文件会通过动态链接器从共享库中获取所需的函数或符号。这意味着,共享库可以被多个可执行文件共享使用,并且在可执行文件中只需要包含对共享库的引用,而不是整个库的代码,因此可以减小可执行文件的大小。但是,共享库需要在运行时进行加载和链接,因此会增加一些额外的运行时开销,并且需要注意共享库的版本问题,以免出现不兼容的情况。
查看 03-static-library 和 04-shared-library 两个例子中可执行文件的大小:
// 03-static-library
-rwxrwxr-x 1 tartarus tartarus 18K Apr 15 23:37 hello_binary
// 04-shared-library
-rwxrwxr-x 1 tartarus tartarus 17K Apr 16 00:11 hello_binary
2
3
4
5
6