首页 > 系统相关 >【Linux探索学习】第八弹——Linux工具篇(三):Linux 中的编译器 GCC 的编译原理和使用详解

【Linux探索学习】第八弹——Linux工具篇(三):Linux 中的编译器 GCC 的编译原理和使用详解

时间:2024-10-26 22:47:57浏览次数:3  
标签:文件 GCC gcc 链接 编译 编译器 Linux hello

#1024程序员节|征文#

Linux下的vim编辑器:【Linux探索学习】第七弹——Linux的工具(二):Linux下vim编辑器的使用详解-CSDN博客

前言:

在上一篇我们学习了如何在Linux环境下直接用vim编辑器来进行编辑代码,今天我们来学习如何运行我们所编辑的代码,运行代码就需要编译器,也就是我们下文要讲的gcc编译器

提醒:本文是在Ubuntu系统下进行的操作

目录

一、什么是GCC

二、背景知识

三、GCC的使用

3.1 安装GCC

3.2 基本语法

3.3 使用方法

四、GCC如何完成编译

4.1 预处理

4.2 编译 

4.3 汇编

4.4 链接 

五、函数库

六、常用选项

七、总结


一、什么是GCC

GCC 是一个开源的编译器,它由 GNU 项目开发,最初只支持 C 语言,后来扩展支持 C++、Fortran、Ada、Objective-C 及其他语言。它是 Linux 和其他 UNIX 系统中最常用的编译器之一。

二、背景知识

在我们正式讲解GCC如何编译及其背后原理之前,我们先来了解一个背景知识,这个在我们之前用VS学习C语言和C++的时候是学过的,那就是——我们所编写的代码是如何经编译器处理一步步生成一个可执行程序并得到执行的?

主要是分四步走:

1. 预处理——预处理功能主要包括宏替换,去注释,条件编译等

2. 编译——生成汇编

3. 汇编——生成机器可识别代码

4. 连接——生成可执行文件或库文件

三、GCC的使用

3.1 安装GCC

在 Ubuntu 系统中,可以使用以下命令安装 GCC:

sudo apt update
sudo apt install build-essential

build-essential 软件包包含了 GCC 及其相关的工具和库。

3.2 基本语法

GCC 的基本语法如下:

gcc [options] [source files] [object files] [libraries]

3.3 使用方法

gcc编译的基本语法就是上面的那种格式,那么具体该如何使用呢?我们通过一个C语言的代码来试一下

我们创建一个C语言文件hello.c

用vim打开,在里面写入这样一段简单代码

#include <stdio.h>

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

写入之后通过以下命令编译该程序:

gcc hello.c -o hello

(hello.c就是我们需要编译的文件,-o是gcc的一个选项,作用是将编译后的可执行文件给定一个文件名,hello就是我们所指定的文件名,编译好后的可执行文件就是这个)

写入后我们用ls查看我们目前所拥有的文件

我们可以发现我们有了一个叫hello的文件,而这个文件正是我们上面的编译命令所生成的可执行文件

上面编译得到的hello可执行程序,可以使用以下命令来运行它:

./hello

运行如下:

四、GCC如何完成编译

上面我们讲了gcc如何进行编译,下面我们就来思考一下,gcc是如何处理的,能让hello.c这样一个C语言文件生成一个可执行程序hello的呢?

这就与我们上面讲到的背景知识有关,gcc编译代码的逻辑也是那四步:

下面是对这四步进行详解:

4.1 预处理

在这个阶段,GCC 处理源代码中的预处理指令。预处理器主要完成以下任务:

  • 宏替换:将定义的宏(如 #define)替换为实际的值。
  • 文件包含:处理 #include 指令,将被包含的文件内容插入到源文件中。
  • 条件编译:根据条件指令(如 #ifdef#ifndef 等)选择性地编译代码。

预处理的结果是一个扩展名为 .i 的中间文件,包含了所有的宏替换和文件包含后的代码。

gcc -E hello.c -o hello.i

选项-E的作用就是让gcc在预处理结束之后停止编译,.i的中间文件就是原本代码进行预处理之后所得到的中间代码

4.2 编译 

在这个阶段,GCC 将预处理后的源代码转换为汇编语言。编译器会将每个源文件解析成相应的汇编指令。此过程包括以下几个步骤:

  • 词法分析:将源代码分解成 tokens(词法单元)。
  • 语法分析:根据语言的语法规则检查语句的正确性。
  • 语义分析:检查程序的语义,例如变量是否已定义、类型是否匹配等。

编译的结果是一个扩展名为 .s 的汇编语言文件。

gcc -S hello.i -o hello.s

4.3 汇编

汇编阶段的任务是将汇编语言代码转换为机器码。GCC 使用汇编器(如 as)将 .s 文件转换为目标文件(.o 文件)。目标文件是二进制格式,包含了机器码和必要的符号信息。

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

4.4 链接 

最后一步是链接。链接器(如 ld)将一个或多个目标文件和所需的库文件(如标准库)结合起来,生成最终的可执行文件。链接器的主要任务包括:

  • 符号解析:在目标文件之间解决函数和变量的引用。
  • 地址分配:为代码和数据分配内存地址。

链接的结果是一个可执行的二进制文件,通常以无扩展名或 .out 扩展名表示。

gcc hello.o -o hello

链接是这几步里面最需要讲解的,因为它涉及到一个叫函数库的概念,函数库我们在下面详细讲解吧


GCC 的编译过程可以概括为以下几个步骤:

  1. 预处理:处理宏和头文件,生成 .i 文件。
  2. 编译:将 .i 文件转换为 .s 汇编文件。
  3. 汇编:将 .s 文件转换为 .o 目标文件。
  4. 链接:将 .o 文件和库文件链接,生成可执行文件。

五、函数库

在我们代码中,会有printf等函数,我们并没有对它们的实现,而且预编译"stdio.h"中,也只有对它的声明,没有对它的实现,那么这些函数是在哪进行实现的呢?

其实系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到
系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函
数“printf”了,而这也就是链接的作用

我们可以查看路径”usr/lib“中所有的函数:

函数库分为静态库和动态库两种

        静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”
        动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件

我们用ldd指令可以查看一个可执行程序所依赖的动态库:

gcc在编译时默认使用的是动态链接,要想使其静态链接,需要在编译时在后面加上-static

如下所示:

动态链接:

gcc test.c -o mytest

静态链接:

gcc test.c -o mytest -static

我们在平时使用时也不一定是纯动态链接或纯静态链接,也可能是两者混合

file指令可以帮助我们查看我们所调用的库类型

方式:file 可执行文件名

比如上面的hello文件:

我们就可以看到它调用的是.so结尾的动态库

六、常用选项

GCC 提供了多种选项,以满足不同的需求。以下是一些常用的选项:

  • -o <file>: 指定输出文件名。
  • -Wall: 开启所有警告信息。
  • -g: 生成调试信息,用于调试程序。
  • -O<level>: 优化级别,-O0(无优化)、-O1(基本优化)、-O2(较高优化)、-O3(最高优化)。
  • -c: 仅编译源代码,不进行链接,生成目标文件(.o)。

例子

  1. 生成调试信息:

    gcc -g hello.c -o hello
  2. 开启所有警告信息:

    gcc -Wall hello.c -o hello
  3. 进行优化编译:

    gcc -O2 hello.c -o hello

七、总结

GCC 是 Linux 中强大的编译工具,灵活且功能丰富。熟练掌握 GCC 的使用,有助于提升编程效率,并使得开发过程更加顺畅。希望本文能为你提供一个良好的起点,帮助你开始使用 GCC 编译器。

感谢各位大佬观看,创作不易,还望各位大佬点赞支持!!!

标签:文件,GCC,gcc,链接,编译,编译器,Linux,hello
From: https://blog.csdn.net/2301_80220607/article/details/143218012

相关文章

  • linux之系统调用与文件IO编程
    linux之系统调用与文件IO编程系统调用主要包含以下内容:文件操作:打开、读取、写入、关闭文件。目录和文件系统:创建目录、遍历目录、文件属性管理。进程管理:进程创建、进程终止、信号处理、进程间通信(IPC)。内存管理:内存映射、共享内存、动态内存分配。时间管理:时间获取、时......
  • linux学习day1
    1.常见命令介绍(1)ctrlc:取消命令,并且换行(2)ctrlu:清空本行命令(3)tab键:可以补全命令和文件名,如果补全不了快速按两下tab键,可以显示备选选项(4)ls:列出当前目录下所有文件,蓝色的是文件夹,白色的是普通文件,绿色的是可执行文件(5)pwd:显示当前路径(6)cdXXX:进入......
  • 0-petalinux2018.3 摸索记录 - 快速亮机
    一、环境搭建1、环境要求①需要注意petalinux、vivado、vitis、linux之间的版本对应关系,在ug1144上可以找到②需要注意linux的硬件要求,运存8G以上不然会报错等等2、环境依赖配置2018.3_PetaLinux_Package_List.xlsx①安装包sudoapt-getinstalltofrodos......
  • Linux基础命令指南
    Linux是一个强大的操作系统,广泛用于服务器、桌面、移动设备和嵌入式系统。掌握一些基础的Linux命令对于任何想要高效使用Linux的用户来说都是至关重要的。以下是一些最常用的Linux命令及其简要说明。1.文件和目录操作ls列出目录内容。ls-l #以长格式列出文件和目录ls......
  • 【Linux】线程池详解及其基本架构与单例模式实现
    目录1.关于线程池的基本理论     1.1.线程池是什么?1.2.线程池的应用场景:2.线程池的基本架构2.1.线程容器2.2.任务队列2.3.线程函数(HandlerTask)2.4.线程唤醒机制3.添加单例模式3.1.单例模式是什么?3.2.饿汉实现方式和懒汉实现方式饿汉式单例模式:懒汉式单例......
  • Linux 操作系统下 dstat 命令介绍和使用案例
    Linux操作系统下dstat命令介绍和使用案例dstat命令介绍dstat是一个功能强大的Linux系统监控工具,旨在替代多个传统命令,如vmstat、iostat、netstat、nfsstat和ifstat。它能够实时收集和显示系统性能数据,包括CPU、内存、磁盘I/O和网络流量等信息,帮助用户快速识别和......
  • Linux 操作系统下 dris 命令介绍和使用案例
    Linux操作系统下dris命令介绍和使用案例dris命令在Linux中用于显示和清空目录堆栈中的内容dris命令简介功能:dris命令用于显示当前的目录堆栈,并可以清空堆栈中的内容。语法:bashdris[选项]常用选项+n:显示从左边算起第n个目录。-n:显示从右边算起第n个目录。......
  • 修改Linux服务的文件打开句柄数
    在bash中,有个ulimit命令,提供了对shell及该shell启动的进程的可用资源控制。主要包括打开文件描述符数量、用户的最大进程数量、coredump文件的大小等。在centos5/6等版本中,资源限制的配置可以在/etc/security/limits.conf设置,针对root/user等各个用户或者*代表所有用户来设......
  • windows--linux系统共享文件配置
    1.操作系统ubuntu22042.相关依赖sudoaptupdate更新sudoaptinstallnet-toolspython3-dnspythonpython3-sambasamba-common-bintdb-toolslibldb2libtalloc2libtdb1libtevent0libwbclient0samba-libssudoapt--fix-brokeninstall尝试安装缺失的依赖,并......
  • GNU编译器(GCC)原理简介
    GNU编译器(GCC)原理简介  GNU编译器(GCC,GNUCompilerCollection)是GNU工具链的关键组件,与GNU、Linux相关项目的标准编译器。它设计之初仅用来处理C语言的(也被称为GNUC编译器),紧接着扩展到C++、Objective-C/C++、Fortran、Java、Go等编程语言。目前,GCC已经被以知道各种指令集体......