这两天由于想要研究一下socket的相关内容,但是没想到引入外部库还有这么多门道。
根据维基百科定义:一个现代编译器的主要工作流程如下:源代码(source code)→ 预处理器(preprocessor)→ 编译器(compiler)→ 汇编程序(assembler)→ 目标代码(object code)→ 链接器(linker)→ 可执行文件(executables),最后打包好的文件就可以给计算机去判读运行了。所谓的IDE(集成开发环境)不过是把这些步骤集成到一起,程序员可以专注于代码实现。
.cpp文件编译过程
以hello.cpp文件为例,编译执行这个文件需要经过一下几个步骤:
- 预处理:执行
gcc -E hello.cpp > hello.i
对.cpp文件进行预处理,产出hello.i文件(由于这个文件不可以直接看到的,所以我对指令增加了重定向>
) - 编译:执行
gcc -S hello.cpp
对.cpp文件进行编译,将高级语言转换成汇编语言,产出hello.s文件 - 汇编:执行
gcc -c hello.cpp
将汇编指令转换成机器语言,产出hello.o目标文件(二进制) - 链接:执行
gcc hello.cpp -o hello
将一个或多个由编译器或汇编器生成的目标文件和外部库链接为一个可执行文件,产出hello.exe文件
静态库
是一个外部函数与变量的集合体。静态库的文件内容,其内容不像动态链接库那么复杂,在编译期间由编译器与链接器将它直接集成至应用程序内,并产出目标文件以及可以独立运作的可执行文件。Windows下静态库库为.lib后缀,在linux下为.a后缀。
动态库
是一个包含可由多个程序同时使用的代码和数据的库。DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数,并且允许进程可以共享调用。Windows下动态库为.dll后缀,在linux下为.so后缀。
由于C/C++的语言特性,所有的函数必须先声明再调用,所有单纯的动态库是无法被直接调用的,而导出库的作用就是用来包含动态库中所有的的函数声明。导出库虽然与静态库都是.lib文件,但是二者内容并不相同。
区别
相比于静态库直接集成到应用程序中,动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,不使用的时候再从内存释放。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。
Visual Studio引入
在VS工程中,在C/C++工程中引入外部库的基本步骤:
- 配置所有:右键工程根目录→ 属性 → 最上面修改为“所有配置”、“所有平台”
- 添加头文件目录:右键工程根目录→ 属性 → C/C++ → 常规 → 附加包含目录,添加include目录。
- 添加lib静态库:右键工程根目录 → 属性 → 链接器 → 常规 → 附加库目录,添加lib目录。
添加工程引用的lib文件名:工程 → 属性 → 链接器 → 输入 → 附加依赖项:输入lib文件名。
注意:有时候lib下并非实际的静态库,针对不同版本还要继续找 - 添加dll动态库:把引用的dll放到工程的可执行文件所在目录即可。