1. 预处理:头文件、宏展开 2. 编译: 3. 汇编:生成目标文件 4. 链接:链接其他的程序库生成可执行文件 接下来先看gcc的常用选项
-o :产生目标(.i、.s、.o、可执行文件等 -E:只运行C预编译器 -S:告诉编译器产生汇编语言文件后停止编译,产生的汇编语言文件扩展名为.s -c:通知gcc取消链接步骤,即编译源码并在最后生成目标文件 -Wall:使gcc对源文件的代码有问题的地方发出警告(建议都加上) -I[dir]:将dir目录加入搜索头文件的目录路径 -L[dir]:将dir目录加入搜索库的目录路径 -l[lib]:链接lib库 -g:在目标文件中嵌入调试信息,以便gdb之类的调试程序调试 123456789 123456789下面看gcc模拟编译的几个步骤
#hello.c文件内容 #include <stdio.h> #define HELLO "hello!!\n" int main(void) { printf(HELLO); return 0; } 123456789 123456789 #预编译,之后查看hello.i文件可查看到宏展开、头文件展开等 gcc -E hello.c -o hello.i #编译,查看hello.s是个汇编文件 gcc -S hello.i -o hello.s #汇编 gcc -c hello.s -o hello.o #链接 gcc hello.o -o hello #上诉过程可以一次性完成,(编译生成可重定位目标文件) gcc -c hello.c或gcc -c hello.c -o hello.o 1234567891011 1234567891011常用头文件和库的位置
/usr/include及其子目录底下的include文件夹 /usr/local/include及其子目录底下的include文件夹 /usr/lib /usr/local/lib 1234 1234先看一个例子,程序如下
#include <math.h> #include <stdio.h> int main(void) { double x = pow(2.0, 3.0); printf("The cubed is %f\n", x); return 0; } 123456789 123456789 #-lm表示要链接libm.so或者libm.a库文件 gcc -Wall calc.c -o calc -lm 12 12静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库;动态库(.so或.sa):程序在运行的时候才去链接共享库的代码,多个程序共享使用库的代码。
以下为动态库的运行原理: 一个与共享库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码;在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该共享库中复制到内存中,这个过程称为动态链接(dynamic linking);共享库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份共享库被要用到该库的所有进程共用,节省了内存和磁盘空间。
现在将hello_fn.c模块生成库,库可以认为是个归档文件,将.o文件打包生成库。 见以下说明
#先生成.o文件,别忘了-c,若不加-c就是生成可执行文件了 gcc -Wall -c hello_fn.c -o hello_fn.o #ar是归档文件,rcs(replace and create) ar rcs libhello.a hello_fn.o #两种方式使用libhello.a (1) gcc -Wall main.c libhello.a -o main (2) #或(注意提示错误,因为默认情况下不会在当前目录下查找库) gcc -Wall main.c -o main -lhello #正确(-L.表示库文件的位置在这地下,否则在系统的目录下搜索) gcc -Wall -L. main.c -o main -lhello #说明下,这时生成main可执行程序后,若删掉libhello.a静态库后,也不会影响,因为静态库是链接到可执行文件中了 12345678910111213 12345678910111213按顺序来: 1. 从左到右搜索-I(指定头文件的目录) -L指定的目录(指定库的目录) 2. 由环境变量指定的目录(环境变量可在~/.bash_profile(对当前用户生效)下设置LIBRARY_PATH(静态库路径)或C_INCLUDE_PATH(c头文件),CPLUS_INCLUDE_PATH(c++头文件)),或/etc/profile(对所有用户生效) 3. 由系统指定的目录
shared: 表示生成共享库格式 fPIC:产生位置无关码(position independent code) (解释下:允许它在任何位置加载) 库名规则:libxxx.so
gcc -shared -fPIC hello.o –o libhello.so 1 1使用共享库 编译选项 l:链接共享库,只要库名即可(去掉lib以及版本号) L:链接库所在的路径. 示例:
gcc main.o -o main –L. -lhello 1 1如何解决经常找不到库的问题共享库运行时需要的设置 1. 拷贝.so文件到系统共享库路径下 一般指/usr/lib 2. 更改LD_LIBRARY_PATH(动态库),LIBRARY_PATH(静态库) (在配置文件~/.bash_profile下(当前用户下) ) 3. ldconfig(全局的) 配置ld.so.conf(/etc/ld.so.conf下配置库),之后再调用ldconfig更新ld.so.cache即可
可以用ldd main(可执行程序名)查看链接的库