0x01 gcc安装

Linux下直接用包管理器

1
2
sudo apt update && sudo apt upgrade -y
sudo apt install gcc

0x02 gcc选项

1
2
# 查看gcc的帮助手册
man gcc
1
2
3
4
5
6
7
8
9
10
11
12
13
GCC(1)

NAME
gcc - GNU project C and C++ compiler

SYNOPSIS
gcc [-c|-S|-E] [-std=standard]
[-g] [-pg] [-Olevel]
[-Wwarn...] [-Wpedantic]
[-Idir...] [-Ldir...]
[-Dmacro[=defn]...] [-Umacro]
[-foption...] [-mmachine-option...]
[-o outfile] [@file] infile...

看上去选项并不多,对吗,将手册继续往下翻到OPTIONS的部分……

芜湖,是不是整个人都不好了,非常多的选项,相当复杂的设计。别担心,在之后的旅程中我们只会学习大部分重要的选项,更重要的是理解gcc这个强大而又复杂的编译器,以及它的整个运作机制,为后面的二进制学习打基础。

下面先介绍一些常见的选项,主要是上面基础用法中的:

1. 控制编译流程的选项

C语言源码生成可执行文件的流程如下

gcc-1-1
  • -E:预处理选项

    主要涉及到宏展开、条件编译和头文件包含。

  • -S:编译但不汇编和链接

    进行汇编代码的生成,这个部分非常负责,涉及到一系列的优化。

  • -c:汇编但不链接

    进行目标文件的生成

2. 指定头文件、库文件目录和生成文件

关于生成文件的指定,-o选项应该用不着过多介绍了吧,其重点是指定名称而不是指导过程(不要认为-o是生成可执行文件的选项,只是指定output的名称而已)

  • -I<dir>:指定头文件目录

  • -L<dir>:指定链接库目录

gcc的工作依赖于链接器ld,关于链接器和链接器脚本的部分非常有价值,后续再进行研究和记录。-L选项指定的是链接库的目录,而-l则精确的指定需要使用的库

info

头文件和链接库文件作用的时机和作用有很大的区别,头文件Include中主要用于编译时期,包含外部程序所需要使用的函数头信息,这样编译器可以在编译过程中进行检查参数的使用等。而库文件Lib主要用于链接时期,提供了外部程序的函数和数据的真正实现。

3. 优化级别设置

优化是编译器最核心的功能之一,这些选项控制了GCC对代码进行的优化程度。

  • -O0:不进行任何优化。这是默认设置,编译速度最快,但生成的可执行文件性能最低。适合开发和调试阶段。
  • -O1:基本的代码优化,例如删除不必要的代码、函数内联等。
  • -O2:更高级的优化,包括循环展开、寄存器分配等。这是最常用的优化级别,能在编译速度和程序性能之间取得很好的平衡。
  • -O3:最高级别的优化,会启用更多激进的优化,例如内联所有合适的函数。这可能会显著增加编译时间,但能生成最高性能的代码。
  • -Os:针对代码大小进行优化。这个选项会努力减小可执行文件的大小,同时尽量保持良好的性能。
  • -Og:针对调试优化。它会避免进行那些会严重干扰调试器的操作,生成程序的执行流程基本上会匹配你的源代码行。

4. 警告选项

这些选项用于控制GCC在编译时发出的警告信息。

  • -Wwarn...:启用特定警告。
    • -Wall 会启用所有常见的警告。
    • -Wextra 会启用更多有用的警告。
    • -Wformat 会警告格式字符串不匹配的问题。
  • -Wpedantic:启用严格警告。
    • 这个选项会警告所有不符合所选C语言标准的程序结构,即使这些结构是GCC的语言扩展。这对于编写严格符合标准、具有良好可移植性的代码非常有帮助。

5. 宏控制

下面的选项对于条件编译非常重要,通过宏的有无来进行。

  • -D<macro>:定义宏
  • -U<macro>:取消宏

info

用gcc编译项目的过程非常复杂,因此会用到make这样的编译管理和组织工具。而make的语法编写上也很复杂繁琐,尤其是跨平台上,所以后面有了cmake等一系列简化工具。

这让我想到从机器代码到汇编再到C然后是高级语言最后到自然语言驱动AI进行编码,工具链的迭代升级,目的还是为了通过抽象和封装来减少复杂性。