在软件开发中,使用库文件和记录日志是常见的任务。库文件(libraries)用于组织和共享代码。本教程将利用CMake,介绍如何在项目中包含库文件,让你轻松掌握这项基本技能。
在编写程序的过程中,可能会用到一些系统提供的动态库或者自己制作出的动态库或者静态库文件,cmake中也为我们提供了相关的加载动态库的命令。
在cmake中,链接静态库的命令如下:
link_libraries(<static lib> [<static lib>...])
参数1:指定出要链接的静态库的名字
可以是全名 libxxx.a
也可以是掐头(lib)去尾(.a)之后的名字 xxx
参数2-N:要链接的其它静态库的名字
比如,现在我的文件夹下面的build里面有.a静态库:
ubuntu@ubuntu-2204:~/C/csdn-cmake$ tree -L 2
.
├── a.cpp
├── bin
│ └── app
├── build
│ ├── app
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ ├── cmake_install.cmake
│ ├── libtestlib.a
│ ├── libtestlib.so
│ └── Makefile
├── CMakeLists.txt
├── include
│ └── func.h
└── src
├── func.cpp
└── main.cpp
5 directories, 12 files
接下来,我在cmake里面添加他
只需要添加下面这行即可,路径要写对,只需要写静态库,如果只有一个的话,多个在后面直接加 所在路径即可:
link_libraries(${CMAKE_CURRENT_SOURCE_DIR}/build)
现在cmake文件如下:
cmake_minimum_required(VERSION 3.0.0)
project(test)
set(SRC_LIST)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
link_libraries(${CMAKE_CURRENT_SOURCE_DIR}/build)
add_executable(app ${SRC_LIST})
接下来cmake+make即可:
ubuntu@ubuntu-2204:~/C/csdn-cmake/build$ cmake ..
-- Configuring done
WARNING: Target "app" requests linking to directory "/home/ubuntu/C/csdn-cmake/build". Targets may link only to libraries. CMake is dropping the item.
-- Generating done
-- Build files have been written to: /home/ubuntu/C/csdn-cmake/build
ubuntu@ubuntu-2204:~/C/csdn-cmake/build$ make
Consolidate compiler generated dependencies of target app
[ 33%] Linking CXX executable app
[100%] Built target app
ubuntu@ubuntu-2204:~/C/csdn-cmake/build
在程序编写过程中,除了在项目中引入静态库,好多时候也会使用一些标准的或者第三方提供的一些动态库,关于动态库的制作、使用以及在内存中的加载方式和静态库都是不同的,在此不再过多赘述,如有疑惑请参考
在cmake中链接动态库的命令如下:
target_link_libraries(
<target>
<PRIVATE|PUBLIC|INTERFACE> <item>...
[<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
target:指定要加载动态库的文件的名字
该文件可能是一个源文件,比如说:有一个main.cpp和func.cpp,只有main.cpp要用动态库,那就写main.cpp
该文件可能是一个动态库文件,比如说一个动态库里面用到了另一个动态库,就填这个
该文件可能是一个可执行文件,如果所有的源文件都用,就用这个
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中指定要链接的动态库的时候,应该将命令写到生成了可执行文件之后:
cmake_minimum_required(VERSION 3.0)
project(TEST)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
# 添加并指定最终生成的可执行程序名
add_executable(app ${SRC_LIST})
# 指定可执行程序要链接的动态库名字
target_link_libraries(app pthread)
在target_link_libraries(app pthread)中:
app: 对应的是最终生成的可执行程序的名字
pthread:这是可执行程序要加载的动态库,这个库是系统提供的线程库,全名为libpthread.so,在指定的时候一般会掐头(lib)去尾(.so)。
在这个cmake中:
cmake_minimum_required(VERSION 3.0.0)
project(test)
set(SRC_LIST)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
add_executable(app ${SRC_LIST})
target_link_libraries(app test)
看似没有问题,但是当我cmake+make之后,他成功的报错了:
ubuntu@ubuntu-2204:~/C/csdn-cmake/build$ cmake ..
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ubuntu/C/csdn-cmake/build
ubuntu@ubuntu-2204:~/C/csdn-cmake/build$ make
Consolidate compiler generated dependencies of target app
[ 33%] Linking CXX executable app
/usr/bin/ld: 找不到 -ltest: 没有那个文件或目录
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/app.dir/build.make:113:app] 错误 1
make[1]: *** [CMakeFiles/Makefile2:83:CMakeFiles/app.dir/all] 错误 2
make: *** [Makefile:91:all] 错误 2
这是因为可执行程序启动之后,去加载test这个动态库,但是不知道这个动态库被放到了什么位置,所以就加载失败了,在 CMake 中可以在生成可执行程序之前,通过命令指定出要链接的动态库的位置,指定静态库位置使用的也是这个命令:
link_directories(path)
该过之后的cmake如下所示:
cmake_minimum_required(VERSION 3.0.0)
project(test)
set(SRC_LIST)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/build)
add_executable(app ${SRC_LIST})
target_link_libraries(app libtestlib.so)
接下来cmake+make一下:
ubuntu@ubuntu-2204:~/C/csdn-cmake/build$ cmake ..
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ubuntu/C/csdn-cmake/build
ubuntu@ubuntu-2204:~/C/csdn-cmake/build$ make
Consolidate compiler generated dependencies of target app
[ 33%] Linking CXX executable app
[100%] Built target app
成功链接
通过本教程,我们学习了如何在CMake中包含库文件。包含库文件是为了在项目中使用外部代码。掌握这项技能将使你的项目更具可维护性和可追踪性。希望这份保姆级教程为你提供了简单而实用的指南,帮助你更好地使用CMake构建和管理你的项目。