1、制作库
-
有些时候我们编写的源代码并不需要将他们编译生成可执行程序,而是生成一些静态库或者动态库提供给第三方使用,而在CMake中生成这两类库文件的方法
-
在CMake中制作静态库需要使用如下的命令:
add_library(库名称 STATIC/SHARED [源文件1 源文件2 ...])# Makfile中的制作静态库的命令 ar -r libcalc.a *.cpp# Makfile中的制作动态库的命令 g++ -shared -fPIC *.cpp -o libcalc.so
- STATIC:表示制作静态库,格式:
lib
+库名字
+.a
(Linux)、lib
+库名字
+.lib
(Windows) - SHARED:表示制作动态库,格式:
lib
+库名字
+.so
(Linux)、lib
+库名字
+.dll
(Windows) - CMake中只需要指定库名字就可以,另外两部分在生成该文件的时候自动填充
- STATIC:表示制作静态库,格式:
$ tree
.
├── build
├── CMakeLists.txt
├── inc
│ └── head.h
├── lib
└── src├── add.cpp├── dived.cpp├── mul.cpp└── sub.cpp
-
build:CMake编译目录,生成Makefile文件并继续执行make生成库
-
lib:存放生成的库文件目录
-
inc:头文件目录
-
src:存放需要制作库的源代码
-
CMakeLists.txt文件编写:
cmake_minimum_required(VERSION 3.10.2)# 指定标准 set(CMAKE_CXX_STANDARD 14)# 指定源文件列表 aux_source_directory(${PROJECT_SOURCE_DIR}/src src_list)# 生成一个静态库 ar rcs libcalc.a *.cpp add_library(calc STATIC ${src_list})# 制作动态库 g++ -shared -fPIC *.cpp -o libcalc.so #add_library(calc SHARED ${src_list})# 设置静态库的存放路径 set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
- LIBRARY_OUTPUT_PATH:库文件输出位置宏,将库文件生成到指定的位置
2、连接使用库
-
对于使用静态库和动态库是有区别的
- 静态库在编译可执行程序期间会将所有源代码引入到可执行程序中进行编译
- 动态库则是在编译时预留一部分的地址,当使用时进行加载。
-
链接器:工作于链接阶段,工作时需要-l和-L分别指定库名和动态库路径
-
动态链接器:工作与程序运行阶段,工作时需要提供动态库所在目录位置,而动态库加载,程序是默认从几个系统指定的位置加载。当前位置的加载,因此需要给给定一个路径使得系统能够加载到动态库
2.1、链接使用静态库
在CMakeLists.txt中进行链接静态库
# 添加静态库名称
link_libraries(calc)# 添加静态库头文件路径
link_directories(${PROJECT_SOURCE_DIR}/lib)# 生成目标路径, 在当前目录下bin文件夹下
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)# 生成可执行程序
add_executable(main main.cpp)
link_libraries
:指定出要连接的静态库的名称- 可以链接一个静态库和可以链接多个静态库
- 传入的名字可以是全名
libxxx.a
,也可以是掐头(lib
)去尾(.a
)之后的名字xxx
link_directories
:如果该静态库不是系统提供的(自己制作的或者使用第三方提供的静态库)可能出现静态库找不到的情况,需要将静态库的路径制定出来
2.2、链接使用动态库
-
在程序编写过程中,除了在项目中引入静态库,好多时候也会使用一些标准的或者第三方提供的动态库,例如:基础IO流库、多线程库…
-
在CMake中链接动态库
target_link_libraries(<target><PRIVATE | PUBLIC | INTERFACE> <item>...[<PRIVATE | PUBLIC | INTERFACE> <item>...])
-
target:指定要加载的动态库的文件的名字
- 该文件可能是一个源文件、动态库文件、可执行文件
-
PRIVATE | PUBLIC | INTERFACE:动态库的访问权限,默认为PUBLIC
-
如果各个动态库之间没有依赖关系,无序做任何设置,三者没有任何区别(一般都使用默认的PUBLIC)
-
传递性:动态库的链接具有传递性,如果动态库A链接了动态库B、C,动态库D链接了动态库A,此时动态库D相当于也链接了动态库B、C,并可以使用动态库B、C中定义的方法
target_link_libraries(A B C) target_link_libraries(D A)
-
PUBLIC:在public后面的库会被Link到前面的target中,并且里面的符号也会被导出,提供给第三方使用
-
PRIVATE:在private后面的库仅被link到前面的target中,并且终止掉,第三方不能感知调用了哪个库
-
INTERFACE:在interface后面引入的库不会被链接到前面的target中,只会导出符号。
-
-
-
动态库的链接和静态库的链接是完全不同的
- 静态库在生成可执行程序的链接阶段会被打包到可执行程序中,所以可执行程序启动静态库就一起被加载到内存中
- 动态库在生成可执行程序的链接阶段不会被打包到可执行程序中,当可执行程序启动并且调用动态库中的函数时候,动态库才会被加载到内存
-
在CMake中指定要连接的动态库的时候,应该将命令写到生成了可执行文件之后
add_executable(main main.cpp) target_link_libraries(main pthread)
在
target_link_libraries(main pthread)
中:main
:对应的是最终的生成的可执行程序的名字pthread
:这是可执行程序需要加载的动态库,这个库是系统提供的多线程库,全名libpthread.so
,在指定的时候掐头去尾
-
CMakeLists.txt编写
cmake_minimum_required(VERSION 3.10.2)# 指定标准 set(CMAKE_CXX_STANDARD 14)# 指定源文件列表 aux_source_directory(${PROJECT_SOURCE_DIR}/src src_list)# 制作动态库 g++ -shared -fPIC *.cpp -o libcalc.so add_library(calc SHARED ${src_list})# 设置静态库的存放路径 set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)# 生成目标路径, 在当前目录下bin文件夹下 set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) # 生成可执行程序 add_executable(main main.cpp)# 链接动态库 link_directories(${PROJECT_SOURCE_DIR}/inc) target_link_libraries(main calc)