CMake学习

CMake如何编译成库?

  1. 为什么要有库?

库就是预先写好,编译好的代码集合。存在的意义,1)避免重复造轮子和重复编译,库是提前编译好的二进制文件 ,你的代码在编译时直接链接它,不需要把库的源码重新编译一遍,大大节省了编译时间。;2)保护源码(知识产权) :编译成库让别人可以直接调用我的函数,但看不到cpp源码,看不到里面的逻辑。3)模块化与复用:大项目可以拆分给不同的团队开发不同的库,最后拼在一起。

静态库:就是在程序编译和链接阶段,把库里被用到的代码部分,像打包裹一样,直接复制粘贴到最终的可执行文件(如 .exe 或 Linux 下的无后缀文件)里面。 静态库的后缀.lib(windows中),.a(Linux中) Archive。

  • 静态库本身 :是库的作者 把所有功能都编译好,打包成的一个**"大仓库"** 。它包含多余的代码。

动态库:又叫共享库,在编译链接阶段,程序只记录一个"依赖清单" ,并不复制代码。等到程序真正运行的时候,操作系统才会去把动态库加载到内存里,让大家一起用。

  • Windows 下后缀 :.dll (Dynamic Link Library)

  • Linux 下后缀 :.so (Shared Object)

  • 比喻 :你买了一个乐高说明书,需要玩的时候,去公共游乐场借公用的积木来拼。

特点:

  • 节省空间:十个程序用同一个动态库,内存里只有一份代码,大家共享。

  • 更新方便 :如果库出了新版本(且接口没变),你只要把电脑里的 .dll 或 .so 文件替换掉,程序不需要重新编译,下次运行自动就用新的。

  • 依赖环境:如果你把程序发给别人,别人电脑上没有这个动态库,程序就会报错打不开(常见的"缺少 xxx.dll"报错)。

便于后期迭代更新,且如果运行的时候没运行相关的接口程序,就不会占用内存。

  1. 省资源:多个程序(或同一程序的多个进程)在内存里共享同一份底层代码(如各种系统 DLL)。(更多的是用系统中原本就有的一些dll而不是程序下载的时候带来的)

  2. 好更新:改个 bug 只替换小 DLL,不用重装整个软件(你的理解)。

  3. 易扩展:支持插件化架构(比如浏览器加个插件、Photoshop 滤镜),主程序根本不需要重新编译。

对比维度 静态库(.a / .lib) 动态库(.so / .dll)
链接时机 编译时(打包进程序) 运行时(操作系统动态加载)
可执行文件体积 大(包含了库的代码) 小(只记录了依赖)
运行速度 略快(没有加载开销) 略慢一点点(启动时需加载)
内存/磁盘占用 浪费(多个程序各自存一份) 节省(多程序共享一份)
库更新 必须重新编译整个程序 直接替换库文件即可(接口不变)
程序发布 简单(一个文件走天下) 麻烦(需附带一堆 .dll / .so)

***********

add_executable(lesson1_1 main.cpp ../lesson1_2/add.cpp) 这是执行的核心,这是添加要编译的文件。

include_directories(../lesson1_1) 添加头文件中包含的路径

add_subdirectory(lesson1_1) 在外层CMakelists中添加要编译的子文件夹

关于动态库

在cpp文件的函数前面加 __declspec(dllexport)

cpp 复制代码
__declspec(dllexport) int add(int a, int b) {
    return a + b;
}

++一份 .dll 的朋友圈里一定有一个同名 .lib(导入库)------ 但链接时用 .lib,运行时用 .dll,而源码树里既不该有它们,也不该手工维护它们。++

要运行含有dll的exe文件,那么相应的dll文件,要在同级目录下,或者写在系统环境变量中

target_link_libraries和target_include_directories的作用区别:

  • target_include_directories :解决**"去哪找头文件(.h / .hpp)"**的问题(编译阶段)。

  • target_link_libraries :解决**"去哪找库文件(.a / .so / .lib)以及怎么把它们拼起来"**的问题(链接阶段)。 (也就是最终把多个.a 链接起来,最终生成可执行文件的过程,但不是建立 依赖关系,即 并不是 1.a中要调用2.a中的函数,就把1.a和2.a链接起来,不是这样的。 如果是1.a中要用到2.a中的函数,只能是在 都还是.o文件的时候通过

    复制代码
    add_library(add STATIC add.cpp $<TARGET_OBJECTS:common_object>) 这种方式建立连接,生成一个1.a)

也就是说,target_link_libraries 只能是把多个并列功能的.a(.lib)文件打包成可执行文件,而不能把前后依赖关系,打包成.a,也不能把两个.a文件进行合并。

如果是要链接前后依赖关系的库的话,应该用add_library

.a 相当于.lib,

.so相当于.dll

复制代码
# 告诉编译器,编译 add.cpp 的时候,去 当前 文件夹下找头文件
# 因为是 PRIVATE,如果别人链接了 add,他们得不到这个 include 路径(对外不公开)。 如果是PUBLIC就是如果A依赖了add这个,那么add能找到的头文件,A也能找到并使用(即对外公开)。
target_include_directories(add PRIVATE ./)

add_library 到底生成什么文件?完全取决于你给 add_library 传的第二个参数(类型)

类型参数 生成的文件 (Linux/macOS) 生成的文件 (Windows) 作用与特点
OBJECT .o 文件集合 .obj 文件集合 只编译,不打包。是最基础的"零件"。
STATIC .a 静态库 .lib 静态库 把 .o 文件打包成一个压缩包。程序运行时不需要它。
SHARED .so / .dylib 动态库 .dll (+ .lib 导入库) 动态链接库,程序运行时需要加载。
MODULE .so .dll 插件库,通常用 dlopen 动态加载,不直接链接。
INTERFACE 不生成任何文件 不生成任何文件 纯头文件库(Header-only),只用来传递编译属性(如 include 路径)。
ALIAS 不生成任何文件 不生成任何文件 给已有的 Target 起个别名(如 add_library(ns::my_lib ALIAS my_lib))
  • .o 是编译的产物(永远在后台默默发生)。

  • .a 是打包(归档) 的产物(STATIC 产生)。

  • target_link_libraries 是给最终链接(缝合) 阶段下达的指令,它绝对不会去修改现有的 .a 或 .o 文件本身。


vscode中没有相关显示cmkelist。

运行 CMake: Configure :这是最关键的一步。按 Ctrl+Shift+P,输入并选择 CMake: Configure。这个命令会强制 CMake Tools 加载项目并开始配置,配置完成后,状态栏的按钮通常就会出现。

相关推荐
只愿云淡风清26 分钟前
正则表达式学习笔记 02:基础语法
笔记·学习·正则表达式
wangqiaowq4 小时前
Ontology 学习 二
学习
该学习了咕咕10 小时前
顶刊论文学习笔记
学习
Linux-lucky12 小时前
45-Linux学习之旅之防火墙与WEB加固
linux·前端·网络·学习·ubuntu
li星野12 小时前
【学习记录】k-Wave 时间步长、CFL 稳定性与参数实验全解析
学习
心祭丫丫14 小时前
【每天一个 Python 小案例17】Python 实现通讯录
开发语言·人工智能·笔记·python·学习
Nerd(BUG版)17 小时前
Flutter学习day5--事件手势与命中测试
学习·flutter
Nerd(BUG版)19 小时前
KMP学习day4--Kotlin空安全与泛型
学习·安全·kotlin
東隅已逝,桑榆非晚19 小时前
算法6. 双指针法-查找总价格为目标的两个商品
c++·学习·算法