一、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