gcc命令

gcc命令

介绍

GCC (GNU Compiler Collection)是 GNU 工具链的主要组成部分,是一套以GPLLGPL许可证发布的程序语言编译器自由软件。

GCC 原名为 GNU C 语言编译器,因为它原本只能处理 C 语言,但如今的 GCC 不仅可以编译 C、C++Objective-C,还可以通过不同的前端模块支持各种语言,包括 Java、Fortran、Ada、Pascal、GoD 语言等等。

GCC 的编译过程可以划分为四个阶段:

  1. 预处理(Pre-Processing)
  2. 编译(Compiling)
  3. 汇编(Assembling)
  4. 链接(Linking)

Linux 程序员可以根据自己的需要控制 GCC 的编译阶段,以便检查或使用编译器在该阶段的输出信息,帮助调试和优化程序。以 C 语言为例,从源文件的编译到可执行文件的运行,整个过程大致如下。

各文件后缀说明如下:

后缀描述后缀描述
.cC 源文件.s/.S汇编语言源文件
.C/.cc/.cxx/.cppC++ 源文件.o/.obj目标文件
.hC/C++ 头文件.a/.lib静态库
.i/.ii经过预处理的 C/C++ 文件.so/.dll动态库

语法:

gcc [options] file...

在阶段编译示例之前,我们先来介绍下示例中用到的参数。

-o <file>:指定输出文件。

-E:仅执行预处理(不要编译、汇编或链接)。

-S:只预处理和编译(不汇编或链接)。

-c:预处理、编译和汇编,但不链接。

示例

阶段编译

假设有文件 hello.c,内容如下:

#include <stdio.h>

int main(void)
{
    printf("Hello World!");
    return 0;
}

.c输出a.out

编译 hello.c,默认输出a.out

gcc hello.c

在这里插入图片描述

.c源文件输出.i预处理文件

只执行预处理,输出hello.i文件

gcc -E hello.c -o hello.i

在这里插入图片描述

.c源文件/.i预处理文件输出.s汇编文件

只执行预处理和编译,输出hello.s汇编文件

gcc -S hello.c

在这里插入图片描述

也可以由hello.i文件生成hello.s汇编文件

gcc -S hello.i -o hello.s

在这里插入图片描述

.c源文件/.i预处理文件/.s汇编文件输出.o目标文件

只执行预处理、编译和汇编,输出hello.o文件

gcc -c hello.c

在这里插入图片描述

也可以由hello.ihello.s生成hello.o目标文件

gcc -c hello.i -o hello.o
gcc -c hello.s -o hello.o

在这里插入图片描述

.o目标文件链接成可执行文件

gcc hello.o -o hello

在这里插入图片描述

使用静态库

在使用静态库示例之前,我们先来介绍下示例中用到的参数。

-static:此选项将禁止使用动态库,所以生成文件比较小,但是需要系统有动态库。

-L:指定链接库的包含路径。

-l:链接时搜索指定的函数库。

创建一个foo.c源文件,内容如下:

#include <stdio.h>

void foo(void)
{
    printf("Here is a static library\n");
}

.c源文件编译成静态库.a

gcc -c foo.c           # 生成foo.o目标文件
ar rcs libfoo.a foo.o  # 生成libfoo.a静态库。 ar Linux命令,用于建立或修改库,
                       # rcs是ar命令的参数。

在这里插入图片描述

修改hello.c文件,调用foo函数

#include <stdio.h>

void foo(void);

int main(void)
{
    printf("Hello World!\n");
    foo();
    return 0;
}

编译.c文件,并链接静态库.a(加上 -static选项)

gcc hello.c -static  libfoo.a -o hello

也可以使用-L指定库的搜索路径,并使用-l指定库名

gcc hello.c -static -L. -lfoo -o hello

运行结果

在这里插入图片描述

使用共享库

修改 foo.c 文件,内容如下:

#include <stdio.h>

void foo(void)
{
    printf("Here is a shared library\n");
}

.c源文件编译为 动态库/共享库。由于动态库可以被多个进程共享加载,所以需要使用-fPIC选项生成位置无关的代码。

gcc foo.c -shared -fPIC -o libfoo.so

在这里插入图片描述

编译.c并链接共享库.so

gcc hello.c libfoo.so -o hello

但是此时运行 hello 程序失败

在这里插入图片描述

原因是找不到.so共享库

在这里插入图片描述

这是因为.so并不在 Linux 系统的默认搜索目录中,解决办法是我们主动告诉系统,.so共享库在哪里。

方法一:设置环境变量LD_LIBRARY_PATH

export LD_LIBRARY_PATH=$(pwd) # Linux 命令

.so所在的当前目录添加到LD_LIBRARY_PATH变量,再次执行hello

方法二:使用rpath将共享库位置嵌入到程序

gcc hello.c -L. -lfoo -Wl,-rpath='pwd' -o hello

rpathrun path,是种可以将共享库位置嵌入程序中的方法,从而不用依赖于默认位置和环境变量。这里在链接时使用 -Wl,-rpath=/path/to/yours 选项,-Wl 会发送以逗号分隔的选项到链接器,注意逗号分隔符后面没有空格。

这种方式要求共享库必须有一个固定的安装路径,欠缺灵活性,不过如果设置了LD_LIBRARY_PATH,程序加载时也是会到相应路径寻找共享库的。

方法三:将.so共享库添加到系统路径

sudo cp libfoo.so /usr/lib/ # Linux 命令

如果 hello 程序仍然运行失败,请尝试执行 ldconfig 命令更新共享库的缓存列表。

执行程序

在这里插入图片描述

此时,再次查看 hello 程序的共享库依赖

在这里插入图片描述

可以看到.so已经被发现了,其中/lib/usr/lib目录的软链接。


a.out文件介绍

a.out是“assembler output”(汇编程序输出)的缩写形式。

Linux 下编译链接程序时,如果不用-o选项来指定输出文件名称,默认情况下就输出名为a.out可执行文件。

为什么默认是a.out而不是别的名称呢?这是一个历史遗留问题。

**注意:**在 Linux 图形界面无法双击运行 gcc生成的a.out,一般是因为编写的程序是控制台程序,而不是 GUI 程序,不是程序不运行,而是因为没有 GUI 界面,所以看不到效果。正确的做法是在终端运行./a.out

参考: https://blog.csdn.net/To_Be_IT_1/article/details/30212467

.i文件介绍

预处理源文件后,预处理器执行宏替换、条件编译以及包含指定的文件。

.s文件介绍

用汇编语言编写的源代码文件。可以汇编为目标文件的纯汇编代码。

大写.S文件代表仍必须通过预处理的汇编代码。

.o文件介绍

object,目标文件,相当于 Windows 下的obj文件,该文件是指源代码经过编译过程产生的且能被 CPU 直接识别的二进制代码。

可执行文件介绍

Windows 下后缀exe(executable ),Linux 不使用文件名扩展来识别文件类型,所以一般没有后缀名,有可执行权限的文件都是可执行文件,与后缀没有关系。当程序要执行时还需要进行链接(link),链接之后再将一个或多个.o文件与系统库文件链接,就成了一个可执行文件。


参考: https://getiot.tech/zh/linux-command/gcc

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值