程序编译分为四个过程:
1.预编译--gcc -E xx.c -o xx.i(预处理器cpp对#做替换:头文件、宏,去掉注释,条件编译)
2.编译--gcc -S xx.i -o xx.s(编译器ccl对程序进行语法及词法分析)
3.汇编--gcc -c xx.s -o xx.o(汇编器as将汇编代码转换机器码 )
4.链接--gcc xx.o -o xx(链接器ld将.o文件链接到一起生成可执行程序)
.c .i .s 均为文本文件,.o为二进制文件
链接的时候需要链接到库,库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。
库分为:静态库和动态库两种。
静态库的命名方式:libxx.a
动态库的命名方式:libxx.so
如果想把file1.c,file2.c...filen.c做成库文件,可以通过以下命令来实现:
静态库:
gcc -c file1.c -o file1.o
gcc -c file2.c -o file2.o
......
gcc -c filen.c -o filen.o
ar -rcs libname.a file1.o file2.o...filen.o 通过此命令生成的静态库名字为libname.a
在链接库的时候需要加上 -l(小写的L)来指明需要链接的库的名字,比如:-lname,同时如果不是在系统库路径的库(即你自己写的静态库),则需要通过-L来指明库的路径,此路径最后为绝对路径。以下动态库同理。
使用静态库:gcc test.c -o test -L/.../ -lname
静态库优点:
1.发布程序的时候不需要提供对应的库(动态库需要);
2.加载库的速度快(库函数就在代码区)。
缺点:库被打包到代码中,增加了代码的体积;
2.库一旦发生了改变,需要对整个程序进行重新编译。
动态库:
gcc -shared -fPIC name.c -o libname.so file1.c file2.c......filen.c
通过此命令生成的动态库名字为libname.so
使用动态库:gcc test.c -o test -L/.../ -lname
如果当我们运行此可执行文件./test的时候报错:No such file or directory,可以考虑因为运行的可执行文件时操作系统默认到/bin、/usr/bin下去找,如果你的可执行文件不在这些路径下,系统就会找不到,此时需要通过设置环境变量来解决这一问题:
首先找到你要运行的可执行文件的位置,然后pwd得到绝对路径,然后export LD_LIBRARY_PATH=/../(刚刚得到的绝对路径),此时再运行./test就能成功了。此设置为临时设置,下一次运行还需要再设置。
动态库优点
1、执行程序体积小
2、动态库更新了,不需要重新编译程序
缺点:
1、发布程序的时候,需要将动态库提供给用户
2、动态库没有被打包到应用程序中,加载速度相对较慢(动态库在打包可执行程序的时候不会将动态库打包到可执行程序中,只会做一个标记,也就是需要调用哪些函数,在执行的时候需要先加载动态库,然后在调用动态库里面的函数然后执行相应的操作。)
区别:静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝。
动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。
当静态库和动态库同时存在时, gcc命令将优先使用动态库。