gcc入门

1 gcc编译流程

gcc编译程序主要经过四个过程:

  • 预处理(Pre-Processing)
  • 编译 (Compiling)
  • 汇编 (Assembling)
  • 链接 (Linking)

(1)预处理

在预处理阶段,编译器主要作加载头文件、宏替换、条件编译的作用。一般处理带“#”的语句。

我们可以通过gcc 的 -E 选项进行查看,如下所示:

gcc -E main.c -o main.i

编译器将main.c预处理结果输出 main.i 文件。

(2)编译

在编译过程中,编译器主要作语法检查和词法分析。在确认所有指令都符合语法规则之后,将其翻译成等价的中间代码或者是汇编代码。

gcc -S main.i -o main.s

编译器将预处理结果文件main.i翻译成汇编代码main.s

(3)汇编

汇编阶段是把编译阶段生成的”.s”文件转成二进制目标代码。

gcc -c main.s -o main.o

编译器将main.s文件转化为main.o 文件。

(4)链接

在成功编译之后,就进入了链接阶段。链接就是将目标文件、启动代码、库文件链接成可执行文件的过程,这个文件可被加载或拷贝到存储器执行。

gcc main.o -o main.exe

编译器将main.o链接成最终可执行文件main.exe

2 gcc常用选项

选项名 作用 生成
-o 产生目标 .i、.s、.o、可执行文件等
-E 只运行C预编译器 .c文件 -> .i文件
-S 告诉编译器产生汇编程序文件后停止编译 .i文件 -> .s文件
-c 通知gcc取消连接步骤,即编译源码,并在最后生成目标文件 .s文件 -> .o文件

现在我们有源文件hello.c,下面是一些gcc的使用示例:

gcc -E hello.c -o hello.i    对hello.c文件进行预处理,生成了hello.i文件
gcc -S hello.i -o hello.s    对预处理文件进行编译,生成了汇编文件
gcc -c hello.s -o hello.o    对汇编文件进行编译,生成了目标文件
gcc hello.o -o hello         对目标文件进行链接,生成可执行文件
gcc hello.c -o hello         直接编译链接成可执行目标文件
gcc -c hello.c 或 gcc -c hello.c -o hello.o 编译生成可重定位目标文件

3 gcc编译多个程序

// hello.c
#include<stdio.h>
#include"hello.h"
void printHello()
{
        printf("hello world!\n");
}
//main.c
#include<stdio.h>
#include"hello.h"
int main()
{
        printHello();
        return 0;
}
//hello.h
//头文件hello.h,仅包含函数声明
#ifndef _HELLO_
#define _HELLO_
void printHello();
#endif

编译这三个文件,可以一次编译生成可执行文件main

gcc hello.c main.c -o main

注意若不在同一目录下,需要用-I链接库文件路径(大写i)

在gcc 的-I参数后加上静态库头文件的路径。(大写i)
在gcc 的-L参数后加上库文件所在目录
在gcc 的-l参数后加上库文件名,不过要去掉lib和.a扩展名。(小写L)

也可以独立编译:

gcc -Wall -c main.c -o main.o
gcc -Wall -c hello.c -o hello.o
gcc -Wall main.o hello.o -o main

-Wall:使gcc对源文件的代码有问题的地方发出警告

4 生成静态库

静态库就是一些.o目标文件的集合,以.a结尾

为了生成.a文件,我们需要先生成.o文件。下面这行命令将我们的hello.o打包成静态库libhello.a

ar rcs libhello.a hello.o

注: rcs中的r表明将模块hello.o加入到静态库中,c表示创建静态库,s表示生产索引。

ar是gun归档工具,如果libhello之前存在,将创建新的libhello.a并将其替换。

然后就可以这样来使用静态库libhello.a

gcc -Wall main.c libhello.a -o main
./main

-L指定路径,-l指定具体库,配合使用

本例中-L.指示链接库路径(当前路径),-l指定链接库。库名为hello(不指定前缀lib和后缀.a)

-I参数用来指定头文件目录,用来指定程序要链接的库(库文件在/lib、/usr/lib和/usr/local/lib下)。-l参数紧接着就是库名,那么库名跟真正的库文件名有什么关系呢?就拿数学库来说,他的库名是m,他的库文件名是libm.so,很容易看出,把库文件名的头lib和尾.so去掉就是库名了。好了现在我们知道怎么得到库名了,比如我们自已要用到一个第三方提供的库名字叫libtest.so,那么我们只要把libtest.so拷贝到/usr/lib里,编译时加上-ltest参数,我们就能用上libtest.so库了

5 生成动态库

(1)理解动态库

在Linux系统下,创建动态链接库是件很简单的事情。只要在编译函数库源程序时加上-shared选项即可,这样所生成的执行程序即为动态链接库。从某种意义上来说,动态链接库也是一种执行程序。按一般规则,程序名应带.so后缀。

gcc -shared -fPIC -o libhello.so hello.c

参考博客:动态库基本原理和使用方法,-fPIC选项的来龙去脉 理解

(2)创建和使用动态链接库

gcc -c -fPIC hello.c
gcc -shared -o libhello.so hello.o
gcc main.c -L. -lhello
export LD_LIBRARY_PATH=./
./a.out

引用

posted @ 2022-09-25 19:50  20201324徐源  阅读(435)  评论(0编辑  收藏  举报