现代CMake高级教程 - 第 3 章:链接库文件

这篇具有很好参考价值的文章主要介绍了现代CMake高级教程 - 第 3 章:链接库文件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

双笙子佯谬老师的【公开课】现代CMake高级教程课程笔记

第 3 章:链接库文件

main.cpp 调用 mylib.cpp 里的 say_hello 函数

$tree
.
├── CMakeLists.txt
├── main.cpp
├── mylib.cpp
└── mylib.h	
// main.cpp
#include "mylib.h"

int main() {
	say_hello();
}
// mylib.h
#pragma once

void say_hello();
// mylib.cpp
#include "mylib.h"
#include <cstdio>

void say_hello() 
{
	printf("hello, mylib!\n");
}	

1. 直接链接到一起编译

# CMakeLists.txt
add_executable(main main.cpp mylib.cpp)	

2. mylib 作为一个静态库

add_library(mylib STATIC mylib.cpp)

add_executable(main main.cpp)

target_link_libraries(main PUBLIC mylib)

编译:

$cmake --build build
[build] [1/3  33% :: 0.194] Building CXX object CMakeFiles/mylib.dir/mylib.cpp.o
[build] [2/3  66% :: 0.420] Linking CXX static library libmylib.a
[build] [3/3 100% :: 0.741] Linking CXX executable main
[build] Build finished with exit code 0	

生成了 libmylib.a:

$ls build
CMakeCache.txt  CMakeFiles  build.ninja  cmake_install.cmake  compile_commands.json  libmylib.a  main  mylib

3. mylib 作为一个动态库

add_library(mylib SHARED mylib.cpp)

add_executable(main main.cpp)

target_link_libraries(main PUBLIC mylib)

编译:

[main] Building folder: CMakeLession 
[build] Starting build
[proc] Executing command: /usr/bin/cmake --build /mnt/h/Code/lessonCode/CMakeLession/build --config Debug --target all --
[build] [1/3  33% :: 0.485] Building CXX object CMakeFiles/mylib.dir/mylib.cpp.o
[build] [2/3  66% :: 0.786] Linking CXX shared library libmylib.so
[build] [3/3 100% :: 1.071] Linking CXX executable main
[build] Build finished with exit code 0
[main] Building folder: CMakeLession 
[build] Starting build
[proc] Executing command: /usr/bin/cmake --build /mnt/h/Code/lessonCode/CMakeLession/build --config Debug --target all --
[build] [1/3  33% :: 0.485] Building CXX object CMakeFiles/mylib.dir/mylib.cpp.o
[build] [2/3  66% :: 0.786] Linking CXX shared library libmylib.so
[build] [3/3 100% :: 1.071] Linking CXX executable main
[build] Build finished with exit code 0	

4. mylib 作为一个对象库

对象库类似于静态库,但不生成 .a 文件,只由 CMake 记住该库生成了哪些对象文件

add_library(mylib OBJECT mylib.cpp)

add_executable(main main.cpp)

target_link_libraries(main PUBLIC mylib) 	

编译:

cmake --build build
[ 33%] Building CXX object CMakeFiles/mylib.dir/mylib.cpp.o
[ 33%] Built target mylib
[ 66%] Building CXX object CMakeFiles/main.dir/main.cpp.o
[100%] Linking CXX executable main
[100%] Built target main	

对象库类似于静态库,但不生成 .a 文件,只由 CMake 记住该库生成了哪些对象文件,对象库是 CMake 自创的,绕开了编译器和操作系统的各种繁琐规则,保证了跨平台统一性。在自己的项目中,我推荐全部用对象库(OBJECT)替代静态库(STATIC)避免跨平台的麻烦。

对象库仅仅作为组织代码的方式,而实际生成的可执行文件只有一个,减轻了部署的困难。

ls build/CMakeFiles/mylib.dir
DependInfo.cmake  build.make  cmake_clean.cmake  compiler_depend.make  compiler_depend.ts  depend.make  flags.make  mylib.cpp.o  mylib.cpp.o.d  progress.make

静态库的麻烦:GCC 编译器自作聪明,会自动剔除没有引用符号的那些对象
例:
CMakeLists.txt

add_library(mylib STATIC mylib.cpp)	

mylib.cpp

#include <cstdio>

// 此处进行静态初始化
static int unused = printf("mylib initialized!");

main.cpp

#include <cstdio>

int main()
{
	printf("main function\n");
}

编译:

❯ cmake --build build
[ 50%] Built target mylib
Consolidate compiler generated dependencies of target main
[ 75%] Building CXX object CMakeFiles/main.dir/main.cpp.o
[100%] Linking CXX executable main
[100%] Built target main	

查看符号:

.init_array:0000000000003DB8 _init_array     segment qword public 'DATA' use64
.init_array:0000000000003DB8                 assume cs:_init_array
.init_array:0000000000003DB8                 ;org 3DB8h
.init_array:0000000000003DB8 __frame_dummy_init_array_entry dq offset frame_dummy
.init_array:0000000000003DB8                                         ; DATA XREF: LOAD:0000000000000168↑o
.init_array:0000000000003DB8                                         ; LOAD:00000000000002F0↑o
.init_array:0000000000003DB8 _init_array     ends

这里可以看到没有 mylib 的初始化

对象库可以绕开编译器的不统一:保证不会自动剔除没引用到的对象文件。我们改成 OBJECT:
CMakeLists.txt

add_library(mylib STATIC mylib.cpp)

使用 ida 可以看到 mylib 初始化:

.init_array:0000000000003DA8 _init_array     segment qword public 'DATA' use64
.init_array:0000000000003DA8                 assume cs:_init_array
.init_array:0000000000003DA8                 ;org 3DA8h
.init_array:0000000000003DA8 __frame_dummy_init_array_entry dq offset frame_dummy
.init_array:0000000000003DA8                                         ; DATA XREF: LOAD:0000000000000168↑o
.init_array:0000000000003DA8                                         ; LOAD:00000000000002F0↑o
.init_array:0000000000003DB0                 dq offset _GLOBAL__sub_I_mylib_cpp
.init_array:0000000000003DB0 _init_array     ends	

虽然动态库也可以避免剔除没引用的对象文件,但引入了运行时链接的麻烦

小技巧

add_library 无参数

add_library 无参数时,是静态库还是动态库?

会根据 BUILD_SHARED_LIBS 这个变量的值决定是动态库还是静态库。ON 则相当于 SHARED,OFF 则相当于 STATIC。如果未指定 BUILD_SHARED_LIBS 变量,则默认为 STATIC。

因此,如果发现一个项目里的 add_library 都是无参数的,意味着你可以用:cmake -B build -DBUILD_SHARED_LIBS:BOOL=ON 来让他全部生成为动态库。稍后会详解命令行传递变量的规则。

设定一个变量的默认值

要让 BUILD_SHARED_LIBS 默认为 ON,可以用下图这个方法:
如果该变量没有定义,则设为 ON,否则保持用户指定的值不变。
这样当用户没有指定 BUILD_SHARED_LIBS 这个变量时,会默认变成 ON。
也就是说除非用户指定了 -DBUILD_SHARED_LIBS:BOOL=OFF 才会生成静态库,否则默认是生成动态库。

if (NOT DEFINED BUILD_SHARED_LIBS)
	set(BUILD_SHARED_LIBS ON)
endif()

常见坑点

动态库无法链接静态库(3.22.1 可以正常链接)

add_library(otherlib STATIC otherlib.cpp)

add_library(mylib SHARED mylib.cpp)

target_link_libraries(mylib PUBLIC otherlib)

add_executable(main main.cpp)
target_link_libraries(main PUBLIC mylib)

让静态库编译时也生成位置无关的代码(PIC),这样才能装在动态库里

也可以只针对一个库,只对他启用位置无关的代码(PIC)文章来源地址https://www.toymoban.com/news/detail-434369.html

add_library(otherlib STATIC otherlib.cpp)
set_property(TARGET otherlib PROPERTY POSITION_INDEPENDENT_CODE ON)

add_library(mylib SHARED mylib.cpp)

target_link_libraries(mylib PUBLIC otherlib)

add_executable(main main.cpp)
target_link_libraries(main PUBLIC mylib)

到了这里,关于现代CMake高级教程 - 第 3 章:链接库文件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ESP32工程中CMake使用及加入第三方SDK库文件

            本文中使用的是乐鑫官方推出的 ESP-IDF v5.1 对 ESP32S3 设备开发,并非是Arduino、Micro-python等第三方工具开发。在ESP-IDF框架中,乐鑫官方已经将 CMake 和 Ninja 编译构建工具 集成到了ESP-IDF中。         ESP-IDF 即乐鑫物联网开发框架,可为在 Windows、Linux 和 macOS 系统平台

    2024年02月20日
    浏览(32)
  • 现代CMake高级教程 - 第 5 章:链接第三方库

    双笙子佯谬老师的【公开课】现代CMake高级教程课程笔记 案例 使用 tbb 库 main.cpp 直接链接 tbb CMakeLists.txt 直接链接 tbb 的缺点: 如果这样直接指定 tbb,CMake 会让链接器在系统的库目录里查找 tbb,他会找到 /usr/lib/libtbb.so 这个系统自带的,但这对于没有一个固定库安装位置的

    2024年02月02日
    浏览(34)
  • windows执行完LoadLibrary()后,可以删除源动态库文件,函数不会锁库文件

    windows执行完LoadLibrary()后,可以删除源动态库文件,函数不会锁库文件。 运行结果:

    2024年02月13日
    浏览(28)
  • 【Linux基础】库文件

    (꒪ꇴ꒪ ),hello我是 祐言 博客主页:C语言基础,Linux基础,软件配置领域博主🌍 快上🚘,一起学习! 送给读者的一句鸡汤🤔: 集中起来的意志可以击穿顽石! 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏 ​​         在Linux系统中,库文件(Library files)是一

    2024年02月16日
    浏览(41)
  • 【实用技巧】更改ArduinoIDE默认库文件位置,解放系统盘,将Arduino15中的库文件移动到其他磁盘

    本文主要介绍更改Arduino IDE (含2.0以上版本)默认库文件位置的方法。  原创文章,转载请注明出处: 【实用技巧】更改ArduinoIDE默认库文件位置,解放C盘,将Arduino15中的库文件移动到其他磁盘-CSDN博客 文章浏览阅读185次。本文主要介绍更改Arduino IDE (含2.0以上版本)默认库

    2024年02月03日
    浏览(49)
  • linux下头文件及库文件搜索路径知识汇总

    跟gcc相关的搜索目录: 安装gcc时,如果有指定prefix的话,那么系统的默认搜索路径为: C_INCLUDE_PATH:编译 C 程序的时候使用的环境变量 CPLUS_INCLUDE_PATH:编译 C++ 程序的时候使用的环境变量 CPATH:编译 C、 C++及Objective-C 程序时使用的环境变量 OBJC_INCLUDE_PATH:编译 Objective-C 程序

    2023年04月27日
    浏览(33)
  • C标准库文件&常用函数

    编号 头文件 C标准版本 介绍 1 assert.h C89/C90 条件编译宏,将参数与零比较 2 ctype.h C89/C90 用来确定包含于字符数据中的类型的函数 3 errno.h C89/C90 报告错误条件的宏 4 float.h C89/C90 浮点数类型的极限 5 limits.h C89/C90 基本类型的大小 6 locale.h C89/C90 本地化工具 7 math.h C89/C90 常用数据函

    2024年02月12日
    浏览(35)
  • C++有哪些常用的库文件

    常用库文件: iostream:  输入输出流库,包含cin、cout、cerr等标准输入输出对象。 string : 字符串库,包含字符串类型std::string及相关操作函数。 vector : 动态数组库,包含vector类型及相关操作函数。 map:  字典库,包含map、multimap、set、multiset等关联容器类型及相关操作函数。 algorithm

    2024年02月02日
    浏览(35)
  • 现代CMake高级教程 - 第 7 章:变量与缓存

    双笙子佯谬老师的【公开课】现代CMake高级教程课程笔记 重复执行 cmake -B build 会有什么区别? 可以看到第二次的输出少了很多,这是因为 CMake 第一遍需要检测编译器和 C++ 特性等比较耗时,检测完会把结果存储到缓存中,这样第二遍运行 cmake -B build 时就可以直接用缓存的值

    2024年02月02日
    浏览(30)
  • 7-LINUX--库文件的生成与使用

    库是一组预先编译好的方法的集合。Linux系统存储的库的位置一般在:/lib 和 /usr/lib。 在 64 位的系统上有些库也可能被存储在/usr/lib64 下。库的头文件一般会被存储在 /usr/include 下或其子目录下。 库有两种,一种是静态库,其命令规则为 libxxx.a,一种是共享库,其命令规则为

    2024年03月16日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包