初级代码游戏的专栏介绍与文章目录-CSDN博客
我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。
这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。
源码指引:github源码指引_初级代码游戏的博客-CSDN博客
很多人倡导把代码分成动态库或静态库,说这样有种种好处,比如动态升级、减少编译时间,不过其实,我看到的大部分这样做的项目,真正得到的好处是分目录开发,实现了“部分”分工协作。
为什么加了“部分”呢?因为非严格的动态库或静态库并非真正意义的库仅仅是模块分割。
一、真正意义的“库”是什么
真正意义的库是一个具有明确定义的导出符号和未决符号的包,这里面包含了几个要点:
- 头文件描述了所有导出符号,不多也不少,头文件也不应该包含与库接口无关的内容
- 库文件so、dll、a仅仅导出必须的符号,不导出不必要的符号,windows默认不导出任何符号,每个导出符号都必须明确指示为导出,unix上默认导出全部符号,这是不对的,应该用编译开关禁止
- 库文件有明确的依赖项,也就是这个库依赖哪些库,一个真正的库只能依赖另一些真正的库
二、为什么这么麻烦?符号冲突噩梦
当所有源代码都在你手里的时候,解决任何冲突都是很容易的(起码自己可以想办法)。但是当与一个没有源代码的库冲突的时候,这就是个噩梦。
- 未定义符号,这个简单,找啊
- 符号是隐藏的,不能被动态库引用,导出来啊,当然,得有源代码
- 符号冲突,设置为优先使用自己的(有链接参数指定),修改自己的源代码,如果是两个没有源代码的库冲突,傻眼了
- 版本升级,库增加了符号,导致新的冲突,难解决
- 版本差异,引用的共同头文件实际并不相同,导致不同模块对同一个符号的理解不同,运行时挂掉——基于这个原因,仅仅把项目拆分成库并不能带来很多好处,想正常运行还得完整编译
三、库的入门概念
so/a最基本的理解就是打包的.o文件,区别是:
- 链接时机,动态库在运行时加载,.o和.a直接“嵌入”主程序
- 链接规则,主程序的符号和动态库的符号只有导出部分能互相调用,.a和.o之间则无此限制
四、C++和C的区别
C++的类和类成员方法都是可以导出的,但是导出名称的规则是很复杂的,具有奇怪的前缀和后缀(但是是标准的,大家都用同样的规则),所以导出的C++类和方法只有C++能调用。
C++导出的全局函数也具有前缀和后缀,因此虽然看起来只是个函数,与C接口却是不一样的。
最好只导出C接口,也就是只导出用extert "C"包含的全局变量和函数,这样的库所有语言的程序都知道怎么调用。
五、如何隐藏和导出符号
这个我之前专门有一篇讲这个。
原则是默认隐藏所有符号,然后只导出必要的符号。
六、如何编写头文件
这是个技术活!
把项目拆开并不能得到真正的库。通常我们的头文件包含了一层又一层,有太多不相干的东西和inline方法,这些是导致运行时coredump的原因之一。
汗!我前几天才写了一篇谈论这个问题。
(这里是文档结束)