gcc/g++编译工具使用记录

本文详细介绍了GCC编译工具的使用,包括预编译、编译、汇编和链接四个阶段,以及如何生成动态和静态链接库。同时,文章提供了代码示例,演示了直接编译生成可执行文件、分步编译以及如何指定链接库和包含文件。通过理解GCC编译过程,有助于深入理解编译原理和提高开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

其实现在基本上不直接使用gcc/g++来编译了,因为工程中涉及的包、文件很多,用cmake比较方便。

但是记录一下gcc的使用,对于编译过程的理解还是有好处的。

注意:在使用上gcc和g++区别不大,g++在链接时会自动链接STL库但gcc不会。

gcc编译过程

如下图所见,包含预编译、编译、汇编和链接四个阶段。

预编译
编译
汇编
链接

预编译:把.h文件插入源文件中(#include),替换宏定义(#define),选择需要编译的代码(#ifdef等),删除注释等,产生预编译文件(.i文件)

编译:检查C代码语法错误,然后把C代码翻译为汇编代码(.s文件)。

汇编:将汇编代码翻译为机器代码(二进制.o文件)。

链接:将以上的二进制码文件与需要用到的各种库文件连接,生成可执行文件。

代码文件示例

新建一个文件夹example,在其中建立src、include、lib、bin和build五个文件夹:

mkdir example && cd example
mkdir src include lib bin build

然后在src中创建main.c如下:

#include "stdio.h"
#include "func.h"

int main(){
    int a=1, b=6;
    int c = func(a, b);
    printf("%d + %d = %d\n", a, b, c);
    return 1;
}

在lib中创建func.c如下:

int func(int a, int b){
    return a+b;
}

直接编译出可执行文件

在gcc中,直接使用gcc即可将源码编译为可执行文件,并自动命名为a.out:

# terminal在example/build目录下
gcc ../src/main.c ../lib/func.c
./a.out

在这里插入图片描述
可以通过-o参数设置编译产生文件的名字:

gcc -o main ../src/main.c ../lib/func.c
./main

在这里插入图片描述

分步编译

除了直接编译出可执行文件外,也可以通过参数设置,一步步的完成整个源码的编译。

预编译生成.i预编译文件

参数-E表示预编译后停止,与参数-o一同使用来保存预编译文件。

gcc -E -o main.i ../src/main.c
gcc -E -o func.i ../lib/func.c
ls
# func.i main.i

编译生成.s文件

参数-S表示编译后停止

gcc -S func.i main.i
ls
# func.s main.s func.i main.i

汇编生成.o文件

参数-c表示汇编后停止

gcc -c main.s
gcc -c func.s
ls
# func.o main.o func.s main.s func.i main.i

链接生成可执行文件

gcc func.o main.o -o main
ls
# a.out func.o main.o func.s main.s func.i main.i
./a.out
# 1 + 6 = 7

链接库

当源文件较多时不易于管理,编译多文件也会花费更多的时间,因此可以通过gcc将一些功能函数打包成库文件的形式,方便调用。

下面将把func.c打包成库文件。

动态编译

使用动态库(.so或.dll)进行链接。链接动态库时,基本不会把动态库中需要的代码拷贝到可执行文件中,仅在运行时执行相关函数时才进行真正的链接。

动态编译产生的可执行文件比较小。

生成动态链接库.so

通过-shared生成动态库,最好同时加上-fPIC命令:

gcc -shared -fPIC ../lib/func.c -o ../lib/func.so

静态编译

使用静态库(.a或.lib)进行链接。链接静态库时,编译器会把目标文件和静态库中目标文件需要的代码一同拷贝进可执行文件中。

静态编译产生的可执行文件较大,并且如果静态库发生了变化,就需要重新编译整个可执行文件。

生成静态链接库.a

通过ar生成静态库,需要从.o文件生成:

ar crsv ../lib/libfunc.a func.o

编译时指定链接库

无论静态编译还是动态编译都需要指定链接库,最直白的方法是直接通过路径链接,库的路径必须在.o文件的后面:

gcc main.o ../lib/libfunc.a
# or
gcc main.o ../lib/libfunc.so

也可以通过-l指定库的名字和-L指定编译时搜索库的路径,此时如果路径同时存在同名动态和静态库,会优先选择动态链接,可以使用-static强制静态链接:

# 动态链接
gcc main.o -lfunc -L ../lib
# 静态链接
gcc main.o -lfunc -L ../lib -static

运行时指定链接库

静态编译时,由于已经从链接库中把代码拷贝到可执行文件中,因此可以直接运行。

动态编译时,编译器只是将动态库符号位置告诉了可执行文件,在运行时仍然需要动态库来实现链接。而当动态编译时使用-L参数只是指定了编译时搜寻库的位置。

因此需要通过-rpath来指定运行时搜索库的位置:

gcc gcc main.o -lfunc -L ../lib -Wl,-rpath=../lib

指定包含文件

大型工程往往包含很多第三方头文件.h,这些文件的位置可以通过-I指定位置:

gcc -i ../include ../src/main.c

将.h文件对应的.c文件编译成库,然后将.h文件与库文件发布,可以较好的保护.c文件的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值