源代码、目标文件、可执行文件、静态库文件、动态库文件
名词介绍都以 C++ 源代码为例, 使用的编译系统为 clang++。
1.名词介绍
- 源代码: 编码文件源码, C++中是 .cpp 扩展名文件、 C 中则是 .c 文件而 OC 是 .m 文件
- 目标文件: 通过编译器编译命令生成的中间文件通常是 .o 文件
- 可执行文件: 通过目标文件直接生成件或者通过链接静态库、动态库文件生成的可被计算机直接运行以开辟进程的文件
- 静态库文件: 可通过目标文件压缩得到的文件,其特性是在被链接到可执行文件时直接拷贝到可执行文件, C++ 中静态库文件的扩展名是
.a
。 - 动态库文件: 通过目标文件生成的文件,其特性是被链接时不拷贝到可执行文件,而是通过动态链接器在程序执行前链接到动态库的地址, C++ 中动态库的扩展名是
.so
。
2. clang++ 使用
2.1源代码
创建两个 cpp 文件:add.cpp 和 main.cpp
- add.cpp文件如下, 实现 add 函数来对两整数求和
// add.cpp , 该文件实现 add 函数来对两整数求和
#include
using namespace std;
int add(int a, int b) {
return a + b;
}
- main.cpp 文件如下,提供程序入口点 main() 并输出 两数求和结果。
声明 add 函数方便下文使用静态库和动态库链接并生成可执行文件。
#include
using namespace std;
int add(int a, int b);
int main(int argc, const char * argv[]) {
cout << add(2, 4) << endl;
return 0;
}
2.2 使用源码生成目标文件
- C++ 中目标文件以
.o
为扩展名,使用如下命令编译 add.cpp 并生成目标文件 add.o
clang++ -c add.cpp
使用 file add.o 命令输出目标文件类型, 可以看到 add.o 也是 Mach-O 文件的一种
add.o: Mach-O 64-bit object x86_64
- 为 main.cpp 生成目标文件
使用如下命令生成 main.o 目标文件,我们并没有对add
函数提供实现只是为其声明,可见编译生成目标文件并不需要对某个函数提供具体实现只要找到其申明过程就行。
clang++ -c main.cpp
file add.o
结果:
add.o: Mach-O 64-bit object x86_64
file main.o
结果:
main.o: Mach-O 64-bit object x86_64
通过以上两个步骤我们分别生成了 add.o 以及 main.o 两个目标文件, 并且可见目标文件是 Mach-O 文件。
2.3 使用目标文件生成静态库
这里我们有两个目标文件 add.o
和 main.o
,其关系是 main.o
是主程序目标文件而 add.o
是依赖目标文件,我们最终目标是生成 main
可执行文件去满足对 add
加和函数的结果输出,因此生成静态库文件则是对 add.o
文件作处理,使用如下命令生成 libadd.a
静态库。
ar -r libadd.a add.o
结果如下:
ar: creating archive libadd.a
file libadd.o
结果如下:
libadd.a: current ar archive random library
可见 .a 静态库文件并不是 Mach-O 文件
以上ar
命令是archive
的缩写,也就是其实是对 目标文件的压缩,据了解静态库是 一系列目标文件的组合。
2.4 使用目标文件生成动态库文件
使用 目标文件 add.o 生成动态库 libadd.so
clang++ add.o -shared -fPIC -o libadd.so
file libadd.so
输出结果:
libadd.so: Mach-O 64-bit dynamically linked shared library x86_64
可见 .so 可见是 Mach-O 文件
2.5 可执行文件生成
2.5.1 不使用依赖库生成可执行文件
- 1.创建如下
app.cpp
代码, 在函数中打印Hello World!
# app.cpp
#include
using namespace std;
int main(int argc, const char * argv[]) {
cout << "Hello World!" << endl;
return 0;
}
- 2.编译生成目标文件 app.o
clang++ -c app.cpp
-
- 使用目标文件 app.o 生成可执行文件 app
clang++ app.o -o app
file app
结果:
app: Mach-O 64-bit executable x86_64
-
- 执行可执行文件,注意
./app
之前的空格不能缺失
- 执行可执行文件,注意
./app
结果:
Hello World!
2.5.2 使用静态库生成可执行文件
使用静态库生成可执行的文件时需要链接对应的静态依赖库, 这里需要链接 libadd.a
, 以下命令可以理解为, 通过链接静态库libadd.a
为目标文件 main.o
生成可执行文件 main
, 由于我们通过上述几个步骤即生成了静态库也生成了动态库,则链接是优先使用动态库链接,但这里我们需要使用静态库因此先把动态库 libadd.so 删除。
L.
命令将当前目录添加至编译库搜索目录,如果动态库和静态同时存在则优先选择动态库ladd
表示查找的静态库是 libadd.a 或者 动态库为libadd.so 的文件进行链接。
rm -rf libadd.so
clang++ main.o -L. -ladd -o main
file main
结果:
main: Mach-O 64-bit executable x86_64
2.5.3 使用动态库生成可执行文件
动态库生成可执行文件与静态库命令一致,链接时优先使用动态库链接,但我们之前把动态库删除了需要先生成动态库。
clang++ add.o -shared -fPIC -o libadd.so
clang++ main.o -L. -ladd -o main
可执行文件也是 Mach-O 文件
3. 动态库与静态库区别
- 使用静态库生成的可执行文件比动态库大。
由于其生成可执行文件时是拷贝到其中的而动态库则是动态链接的。每个使用静态库生成的可执行文件都会包含对应静态库而动态库生成的则只会链接对应的同一份动态库。
使用静态库生成的可执行文件可脱离静态库执行而动态库生成的则需要动态库存在才可运行可执行文件
动态库可被多个程序同时使用可节省内存,但其在启动程序时则更耗费时间