gcc编译器常用选项及功能

文章目录

  • gcc提供的工具
  • gcc常用选项
  • 预处理阶段常用选项
  • 生成库文件
    • 静态链接库
    • 动态链接库
  • 链接库文件
    • 链接动态库文件
    • 链接静态库文件
    • 查看库的依赖属性
  • 动态加载库文件

gcc提供的工具

gcc编译器常用选项及功能_第1张图片

gcc常用选项

选项 说明 示例
-E 预处理指定的源文件,不进行编译,生成.i文件 gcc -E circle.c -o circle.i
-S 编译指定的源文件,但是不进行汇编,生成.s文件
-c 编译、汇编但是不连接,生成.o文件 gcc -c test1.c test2.c test3.c
-o 编译,输出 gcc main.c func.c -o app.out
-I dir 指定 include 包含文件的搜索目录 gcc test.c -I ./testdir/
-g 生成调试信息,该程序可以被调试器调试
-save-temps 不删除生成的中间文件

预处理阶段常用选项

  • -C:对于包含的头文件,不去删除它的注释
    gcc编译器常用选项及功能_第2张图片

  • -D:增加一个宏,并可以对其赋值,与源文件的条件编译(#if #ifdef #ifndef)配合使用
    增加-D选项后,验证如下,其中对宏的赋值可以选择省略,省略情况下默认为1
    gcc编译器常用选项及功能_第3张图片

  • -U:删除一个宏,与-D起相反作用,根据在编译中出现的顺序起作用
    gcc编译器常用选项及功能_第4张图片

  • -I(大写,i的大写,Include):如果包含的头文件不在系统目录或当前目录下,则需要另行指定
    从实测中看出,新增了一个目录和头文件,里面只写了一句宏定义,包含这个头文件时,用""<>都是可以的,但是会报找不到的错误,这时加上了-I选项指定目录,编译器就会到该目录下搜寻头文件,这样就可以完成编译
    gcc编译器常用选项及功能_第5张图片

生成库文件

静态链接库

制作链接库的目的是希望别人使用我们已经实现的功能,但又不希望别人看到我们的源代码
Linux下的静态链接库是以.a结尾的二进制文件,它作为程序的一个模块,在链接期间被组合到程序中。和静态链接库相对的是动态链接库(.so文件),它在程序运行阶段被加载进内存。

静态库生成步骤

//1 对所有源文件,只编译不链接
gcc -c test.c
//2 利用ar命令,生成库文件
ar rcs libtest.a test.o

ar 是 Linux 的一个备份压缩命令,它可以将多个文件打包成一个备份文件(也叫归档文件),也可以从备份文件中提取成员文件,最常见的用法是将目标文件打包为静态链接库。

对参数的说明:

  • 参数 r 用来替换库中已有的目标文件,或者加入新的目标文件。
  • 参数 c 表示创建一个库。不管库否存在,都将创建。
  • 参数 s 用来创建目标文件索引,这在创建较大的库时能提高速度。

动态链接库

Linux 下动态链接库(shared object file,共享对象文件)的文件后缀为.so,它是一种特殊的目标文件(object file),可以在程序运行时被加载(链接)进来。

使用动态链接库的优点是:程序的可执行文件更小,便于程序的模块化以及更新,同时,有效内存的使用效率更高

如果想创建一个动态链接库,可以使用 GCC 的-shared选项。输入文件可以是源文件、汇编文件或者目标文件。

另外还得结合-fPIC选项。-fPIC 选项作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code);这样一来,产生的代码中就没有绝对地址了,全部使用相对地址,所以代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

例如,从源文件生成动态链接库:
$ gcc -fPIC -shared func.c -o libfunc.so
从目标文件生成动态链接库:
$ gcc -fPIC -c func.c -o func.o
$ gcc -shared func.o -o libfunc.so
-fPIC 选项作用于编译阶段,在生成目标文件时就得使用该选项,以生成位置无关的代码。

链接库文件

链接库文件有两种办法,一个是直接指定,二是在搜索路径下去找
链接静态库和动态库都可以使用这两种办法
gcc编译器常用选项及功能_第6张图片

由于直接指定路径比较简单,所以不多做介绍,下面介绍第二种方法

链接动态库文件

链接库文件时,最重要的两个选项

选项 功能
-L 指定要链接的库的目录
-l 指定要链接哪个库,注意这里是小写的L,不是大写的i

在链接的过程中,不仅要链接生成的.o文件,还要链接一些公共的库文件,默认情况下只链接了libc.alibc.so,使用其它的库,都需要额外指定

如果说我在main.c中,想用另一个文件test.c定义的函数,有三种办法,第一个是在test.h中对函数声明,在main.c中包含头文件,实现调用,第二个是直接在main.c中用extern对要调用的函数进行声明,第三个是将test.c做成一个库文件,链接时将库加进来。下面实测一下最后一种方法

首先cat查看一下测试的代码,test.c完成功能,main.c完成调用,然后将test.c做成共享库,编译的时候,需要加大写的-L指定链接库的路径,然后加小写的L,后面接库的名字也就是-ltest,注意库的全名是libtest.so,这里将lib.so全舍去后,加到-l后。如果使用绝对路径,就不需要加-L指定搜索路径,但是最常用的办法还是将所有要搜索的库目录,放到环境变量LIBRARYPATH

gcc编译器常用选项及功能_第7张图片

链接静态库文件

  • 与链接动态库文件基本相同,不同的是,使用动态库无需添加头文件,而使用静态库,需要添加对应的头文件,这就是学习c语言时,为什么每次都要#include 的原因
  • 静态库文件包含了真正的函数代码,也即函数定义部分,而头文件包含了函数的调用方法,也即函数声明部分。

查看库的依赖属性

  • objdump -x 共享库名或可执行程序名 | grep NEEDED
    8
  • ldd 库名或程序名
    gcc编译器常用选项及功能_第8张图片

动态加载库文件

在程序运行的过程中,可以自己编写代码加载共享库文件,加载动态链接库时,首先要为共享库分配物理内存,然后在进程对应的页表项中建立虚拟页和物理页面之间的映射

常用的四个函数如下,需要加头文件dlfcn.h

  • dlopen():dlopen用于打开指定名字(filename)的动态链接库(最好文件绝对路径)
  • dlsym():dlsym 根据动态链接库操作句柄 (handle) 与符号 (symbol)
  • dlerror():当动态链接库操作函数执行失败时,dlerror 可以返回出错信息
  • dlclose():dlclose 用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为 0 时,才会真正被系统卸载

编译的时候需要注意,需要添加链接选项-ldl,例如gcc main.c -ldl -o main,还有就是在执行程序的时候需要把动态库文件放到指定的位置,否则就会出现动态库找不到的错误信息

你可能感兴趣的:(Linux)