一、GCC编译器的常用选项
1.1 gcc基本用法
使用GCC编译器的时候,我们必须给出一系列必要的调用参数和文件名称。GCC编译器的调用参数大约有100多个,这里只介绍其中最基本、最常用的参数。
GCC最基本的用法∶gcc [参数] [文件名称]
1.2 常用的参数
-c 只编译:不链接成为可执行文件,编译器只是由输入的.c等源代码文件生成.o为后缀的目标文件,通常用于编译不包含主程序的子程序文件。
-o output_filename:确定输出文件的名称为output_filename,同时这个名称不能和源文件同名。如果不给出这个选项,gcc就给出预设的可执行文件a.out。
-g:产生符号调试工具(GNU的gdb)所必要的符号信息,要想对源代码进行调试,我们就必须加入这个选项。
-O:对程序进行优化编译、链接,采用这个选项,整个源代码会在编译、链接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是,编译、链接的速度就相应地要慢一些。
-O2:比-O更好的优化编译、链接,当然整个编译、链接过程会更慢。
-E:仅执行编译预处理;
-S:将C代码转换为汇编代码;
示例:
# gcc test.c -o app
1.3 编译时指定库与头文件路径
-L:指定动态库路径。
示例:gcc test.c -o app -L/usr/lib
-I: 指定头文件存放的路径。
示例:gcc test.c -o app -I/usr/include
-l: 指定库名称。
示例:gcc test.c -o app -lpthread
二、动态库与静态库的介绍
通常把一些公用函数制作成函数库,供其它程序使用。函数库分为静态库和动态库两种。
通常情况下,对函数库的链接是放在编译时期(compile time)完成的。所有相关的对象文件(object file)与牵涉到的函数库(library)被链接合成一个可执行文件(executable file)。程序在运行时,与函数库再无瓜葛,因为所有需要的函数已拷贝到相应目录下下。所以这些函数库被成为静态库(static libaray),通常文件名为“libxxx.a”的形式。
两句话介绍解释:
静态库:在编译的时候加载生成目标文件,在运行时不用加载库,在运行时对库没有依赖性。
动态库:在目标文件运行时加载,对库有依赖性。
三、动态库的创建与调用
3.1 生成和使用动态库的步骤
linux下动态库文件的文件名形如 libxxx.so,其中so是 Shared Object 的缩写,即可以共享的目标文件。
在链接动态库生成可执行文件时,并不会把动态库的代码复制到执行文件中,而是在执行文件中记录对动态库的引用。
程序执行时,再去加载动态库文件。如果动态库已经加载,则不必重复加载,从而能节省内存空间。
Linux下生成和使用动态库的步骤如下:
1. 编写源文件。
2. 将一个或几个源文件编译链接,生成共享库。
3. 通过 -L<path> -lxxx 的gcc选项链接生成的libxxx.so。
4. 把libxxx.so放入链接库的标准路径,
或指定 LD_LIBRARY_PATH,才能运行链接了libxxx.so的程序。
3.2 编译生成共享库的命令格式
gcc -fPIC -shared -o <库文件名称>.so 源文件名称.c
示例:
gcc -fPIC -shared -o libabc.so abc.c
执行上面代码之后我们会得到libabc.so。
生成共享库之后可以通过file命令查看共享库的信息。
[wbyq@wbyq linux-share-dir]$ file sum/libsum.so
sum/libsum.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, not stripped
实际上上述过程分为编译和链接两步, -fPIC是编译选项,PIC表示要生成位置无关的代码,这是动态库需要的特性; -shared是链接选项,告诉gcc生成动态库而不是可执行文件。
上述的一行命令等同于:
gcc -c -fPIC abc.c
gcc -shared -o libabc.so abc.o
3.3 调用动态库的例子
gcc test.c -L ./ -labc 生成a.out,其中-labc表示要链接libabc.so。
-L ./表示指定搜索要链接的库文件时包含的路径。
注意,如果同一目录下同时存在同名的动态库和静态库,比如libmax.so 和 libmax.a 都在当前路径下,则gcc会优先链接动态库。
执行程序:
运行./a.out 会得到以下的错误提示。
./a.out: error while loading shared libraries: libabc.so: cannot open shared object file: No such file or directory
找不到libabc.so,Linux是通过
/etc/ld.so.cache文件搜寻要链接的动态库的。
而 /etc/ld.so.cache 是 ldconfig 程序读取
/etc/ld.so.conf 文件生成的。
(注意,/etc/ld.so.conf 中并不必包含 /lib 和/usr/lib,ldconfig程序会自动搜索这两个目录)
如果把 libabc.so 所在的路径添加到
/etc/ld.so.conf 中,再以root权限运行ldconfig 程序,
更新 /etc/ld.so.cache ,a.out运行时,就可以找到 libabc.so。
但作为一个简单的测试例子,改动系统的东西,似乎不太合适。
还有另一种简单的方法,就是为a.out指定LD_LIBRARY_PATH。
LD_LIBRARY_PATH=. ./a.out
程序就能正常运行了。LD_LIBRARY_PATH=. 是告诉 a.out,先在当前路径寻找链接的动态库。
或者直接将xx.so拷贝到/lib下也可以。
3.4 查看系统环境变量
设置系统环境变量: export <环境变名称>=环境变量的值
查看本地所有的环境变量: env
查看shell所有的环境变量: set
查看本地所有环境变量: export
四、静态库的创建与调用
4.1 静态库介绍
Linux上的静态库,其实是目标文件的归档文件。
在Linux上创建静态库的步骤如下:
1. 写源文件,通过 gcc -c xxx.c 生成目标文件。
2. 用 ar 归档目标文件,生成静态库。
3. 配合静态库,写一个使用静态库中函数的头文件。
4. 使用静态库时,在源码中包含对应的头文件,链接时记得链接自己的库。
4.2 创建静态库
使用 ar将目标文件归档:
ar crv libmylib.a my_print.o my_math.o
执行上面代码得到了libmylib.a,这就是需要的静态库。
上述命令中crv 是 ar的命令选项:
c 如果需要生成新的库文件,不要警告
r 代替库中现有的文件或者插入新的文件
v 输出详细信息
通过 ar t libmylib.a 可以查看libmylib.a 中包含的目标文件。
注意:要生成的库的文件名必须形如 libxxx.a ,链接这个库时,就可以用 -lxxx。
反过来讲,当告诉编译器 -lxxx时,编译器就会在指定的目录中搜索 libxxx.a 或是 libxxx.so。
4.3 调用静态库
执行程序:
执行: gcc test.c -L. -lmylib
将会生成a.out,通过 ./a.out 可以运行该程序。说明静态库能正常工作。
上面的命令中 -L. 告诉 gcc 搜索链接库时包含当前路径, -lmylib 告诉 gcc 生成可执行程序时要链接 libmylib.a。
注意: 当同一个目录下,静态库与动态库重名时,优先使用动态库。
例如:libsum.a libsum.so
优先使用libsum.so