本文详细讨论了在 windows 和 linux 平台使用不同编译器以及 cmake 中关于使用共享库和静态库的相关内容
后文提到了如下几个编译器:
- linux-gcc 就是 linux 下最常用的编译器了
- windows-msvc-cl 指 windows 的官方编译器,VS 中默认使用它,其中 cl 是命令行中的编译器命令
- windows-mingw-gcc 指 windows 下开源的 mingw-64 gcc 编译器实现,某些 windows IDE 会内置这种编译器,比如 CLion 或 QTCreator
- 绝大多数默认行为与 linux-gcc 保持一致,但不可将二者完全是为行为一致
- clang 编译器用的少,不熟悉,暂不讨论
共享库符号导出
符号导出是接触 windows 共享库开发之后才了解的概念,以前一直在 linux 下开发,linux 的默认行为比较开放,不特殊设置就会执行导出符号的行为,所以没意识到过这个问题
之所以要有符号导出,是基于共享库的原理做出的设计,共享库文件是在可执行程序运行时才加载的,这有多个好处:
- 减小了可执行程序文件的大小
- 共享库可以加载一次,然后在多个可执行程序进程间共享,减少了内存占用
- 减小更新包大小,当只有共享库的代码改动时,只需要重新编译更新共享库即可应用新代码,不用重新编译整个项目
有这么些好处,那符号导出这个操作到底意味着什么?是个什么原理呢?
注意:处理导入导出符号是编译过程中链接阶段链接器的工作,这里为了方便起见,后文仍然将其视为编译器的功能,以便行文流畅思路清晰
大体上来说是把共享库里被导出的符号与其对应的代码实现拆分,先让可执行程序只拿到其需要的符号,这样就足够完成编译过程,生成可执行程序文件了,然后在运行时把符号对应的代码实现填充给可执行程序,如此一来可执行程序就完整了,可以正常运行了。有点类似于 C 语言中的 extern 关键字的作用,先用 extern 声明一个符号临时占位拿来用着,而这个符号对应的定义却在其他地方。