2.2. 使用 GCC 构建代码
了解源代码必须转换为可执行代码的情况。
2.2.1. 代码表单之间的关系 复制链接链接已复制到粘贴板!
C 和 C++ 语言具有三种形式的代码,它们通过构建过程的不同阶段创建。了解这些关系可帮助您有效地使用 GCC。
C 和 C++ 语言有三种形式的代码:
用 C 或 C++ 语言编写的 源代码,以纯文本文件形式呈现。
文件通常使用如
.c
,.cc
,.cpp
,.h
,.hpp
,.i
,.inc
的扩展名。有关支持的扩展及其解释的完整列表,请查看 gcc 手册页:man gcc
$ man gcc
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 目标代码,是使用 编译器 编译 源代码创建的。这是一种中间形式。
目标代码文件使用
.o
扩展名。可执行代码,通过带有一个 linker 的 linking 对象代码来创建。
Linux 应用程序可执行文件不使用任何文件名扩展名。共享目标(library)可执行文件使用
.so
文件名扩展名。
也存在用于静态链接的库存档文件。这是使用 .a
文件名扩展名的目标代码的变体。不建议使用静态链接。请参阅 静态和动态链接。
从源代码生成可执行代码分为两个步骤,这需要不同的应用程序或工具:
- 源文件编译成目标文件。
- 目标文件和库被链接(包括之前编译的源)。
GCC 可用作编译器和链接器的智能驱动程序。这允许您将单个 gcc
命令用于任何必要的操作(编译和链接)。GCC 自动选择操作及其序列。
您可以运行 GCC 来仅编译、链接或执行这两个步骤。这由输入的类型和输出的请求类型决定。
因为大型项目需要一个通常为每个操作单独运行 GCC 的构建系统,因此最好始终将编译和链接视为两个不同的操作,即使 GCC 可以同时执行这两个操作。
2.2.2. 将源文件编译成目标代码 复制链接链接已复制到粘贴板!
要从源代码文件而不是可执行文件立即创建目标代码文件,必须指示 GCC 仅将目标代码文件创建为其输出。此操作代表了大型项目的构建过程的基本操作。
先决条件
- C 或 C++ 源代码文件。
- 在系统上安装了 GCC
流程
- 在终端中,打开包含源代码文件的目录。
使用
-c
选项运行gcc
:gcc -c source.c another_source.c
$ gcc -c source.c another_source.c
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 创建目标文件,其文件名反了映原始源代码文件:
source.c
会生成source.o
。注意使用 C++ 源代码,将
gcc
命令替换为g++
,以方便处理 C++ 标准库依赖项。
2.2.3. 使用 GCC 启用 C 和 C++ 应用程序的调试 复制链接链接已复制到粘贴板!
编译器默认省略调试信息,以保持二进制文件小。要使用它启用 C 和 C++ 应用程序的调试,您必须明确指示编译器创建调试数据。
流程
要在编译并使用 GCC 编译和链接 C 或 C++ 应用程序时生成调试信息,请在编译命令中添加 the
-g
选项:gcc ... -g ...
$ gcc ... -g ...
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 这个选项指示 GCC 在输出二进制文件中包含调试信息。有关 the
-g
选项和其他调试选项的更多信息,请参阅 GCC 手册页。要在调试信息中包含宏定义,请使用 the
-g3
选项而不是-g
:gcc ... -g3 ...
$ gcc ... -g3 ...
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 要测试 debug 选项不会影响可执行代码,请使用 the
-fcompare-debug
GCC 选项。这个选项:- 使用调试信息编译代码两次 - 次,一次使用调试信息,没有
- 比较生成的二进制文件
如果两个二进制文件都相同,则通过测试
此测试可防止调试选项在您的代码中引入隐藏的错误。请注意,use
-fcompare-debug
会显著增加编译时间。如需了解更多详细信息,请参阅 GCC 手册页。重要编译器和链接器优化可能会导致调试困难:
为获得更好的调试体验,请考虑使用 the
-Og
选项。但是,更改的优化级别可能会改变可执行的代码行为,并可能会隐藏错误。
2.2.4. 使用 GCC 进行代码优化 复制链接链接已复制到粘贴板!
一个程序可以转换为多个计算机指令序列。如果在编译过程中分配更多资源来分析代码,您可以获得更优的结果。
有了 GCC,您可以使用 -Olevel
选项设置优化级别。这个选项接受一组值来代替 level。
级别 | 描述 |
---|---|
| 编译速度的优化 - 无代码优化(默认)。 |
| 优化以加快代码执行速度(数量越多,速度越快)。 |
| 文件大小的优化。 |
|
与级别 |
| 调试体验的优化。 |
对于版本构建,请使用优化选项 -O2
。
在开发过程中,-Og
选项在某些情况下对于调试程序或库很有用。由于某些 bug 只在某些优化级别上出现,因此请使用版本优化级别测试程序或库。
GCC 提供了大量选项来启用单个优化。如需更多信息,请参阅 gcc
man page。
2.2.5. 使用 GCC 强化代码的选项 复制链接链接已复制到粘贴板!
当编译器将源代码转换为目标代码时,它可以添加各种检查来防止经常被利用的情况,并提高安全性。选择正确的编译器选项集可帮助生成更安全的程序和库,而无需更改源代码。
- 发行版本选项
对于以 Red Hat Enterprise Linux 为目标的开发人员,推荐使用以下选项列表:
gcc ... -O2 -g -Wall -Wl,-z,now,-z,relro -fstack-protector-strong -fstack-clash-protection -D_FORTIFY_SOURCE=3 ...
$ gcc ... -O2 -g -Wall -Wl,-z,now,-z,relro -fstack-protector-strong -fstack-clash-protection -D_FORTIFY_SOURCE=3 ...
Copy to Clipboard Copied! Toggle word wrap Toggle overflow -
对于程序,添加
-fPIE
和-pie
位置独立可执行文件选项。 -
对于动态链接库,强制
-fPIC
(Position Independent Code)选项会间接提高安全性。
-
对于程序,添加
- 开发选项
使用以下选项来检测开发过程中的安全漏洞:使用这些选项与发行版本的选项相结合:
gcc ... -Walloc-zero -Walloca-larger-than -Wextra -Wformat-security -Wvla-larger-than ...
$ gcc ... -Walloc-zero -Walloca-larger-than -Wextra -Wformat-security -Wvla-larger-than ...
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - -
fhardened
-
GCC 14 提供了一个新标志,
-fhardened
,其反过来启用许多其他标志,来改进生成的代码的安全性,而不影响 ABI。 - -
fanalyzer
-
GCC 提供了一个标志,
-fanalyzer
,其触发源代码中潜在问题的警告,包括与安全相关的问题。因为-fanalyzer
经常有误报和漏报,所以应该使用它来定位应该进一步调查的潜在 bug,而不是作为正式的分析工具。这个标志在编译过程中大大增加了所花费的时间和内存。仅对 C 代码使用。
2.2.6. 链接代码以创建可执行文件 复制链接链接已复制到粘贴板!
构建 C 或 C++ 应用程序时,链接是最后一步。链接将所有目标文件和库合并到一个可执行文件中。
先决条件
- 一个或多个目标文件。
- 系统上必须安装了 GCC
步骤
- 进到包含目标代码文件的目录。
运行
gcc
:gcc ... objfile.o another_object.o ... -o executable-file
$ gcc ... objfile.o another_object.o ... -o executable-file
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 从提供的目标文件和库创建一个名为 executable-file的可执行文件。要链接其他库,请在目标文件列表后添加所需的选项。
如需更多信息,请参阅在 GCC 中使用库。
注意使用 C++ 源代码,将
gcc
命令替换为g++
,以方便处理 C++ 标准库依赖项。
其他资源
2.2.7. 示例:使用 GCC 构建一个 C 程序(在一步中编译和链接) 复制链接链接已复制到粘贴板!
本例演示了构建一个简单示例 C 程序的确切步骤。
在本例中,编译和链接代码在一个步骤中完成。
流程
创建一个目录
hello-c
,并进到其中:mkdir hello-c cd hello-c
$ mkdir hello-c $ cd hello-c
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 创建包含以下内容的文件
hello.c
:Copy to Clipboard Copied! Toggle word wrap Toggle overflow 使用 GCC 编译和链接代码:
gcc hello.c -o helloworld
$ gcc hello.c -o helloworld
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 这会编译代码,创建目标文件
hello.o
,并从目标文件链接可执行文件helloworld
。运行生成的可执行文件:
./helloworld
$ ./helloworld Hello, World!
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
2.2.8. 示例:使用 GCC 构建一个 C 程序(在两步中编译和链接) 复制链接链接已复制到粘贴板!
本例演示了构建一个简单示例 C 程序的确切步骤。
在本例中,编译和链接代码是两个独立的步骤。
流程
创建一个目录
hello-c
,并进到其中:mkdir hello-c cd hello-c
$ mkdir hello-c $ cd hello-c
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 创建包含以下内容的文件
hello.c
:Copy to Clipboard Copied! Toggle word wrap Toggle overflow 使用 GCC 编译代码:
gcc -c hello.c
$ gcc -c hello.c
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 目标文件
hello.o
已创建。从目标文件链接可执行文件
helloworld
:gcc hello.o -o helloworld
$ gcc hello.o -o helloworld
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 运行生成的可执行文件:
./helloworld
$ ./helloworld Hello, World!
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 可选:再次删除所有文件:
cd .. rm -r hello-c
$ cd .. $ rm -r hello-c
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
2.2.9. 示例:使用 GCC 构建一个 C++ 程序(在一步中编译和链接) 复制链接链接已复制到粘贴板!
本例显示了构建最小 C++ 程序的确切步骤。
在本例中,编译和链接代码在一个步骤中完成。
流程
创建
hello-cpp
目录,并进到其中:mkdir hello-cpp cd hello-cpp
$ mkdir hello-cpp $ cd hello-cpp
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 创建包含以下内容的文件
hello.cpp
:Copy to Clipboard Copied! Toggle word wrap Toggle overflow 使用
g++
编译和链接代码:g++ hello.cpp -o helloworld
$ g++ hello.cpp -o helloworld
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 这会编译代码,创建目标文件
hello.o
,并从目标文件链接可执行文件helloworld
。运行生成的可执行文件:
./helloworld
$ ./helloworld Hello, World!
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 可选:再次删除所有文件:
cd .. rm -r hello-cpp
$ cd .. $ rm -r hello-cpp
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
2.2.10. 示例:使用 GCC 构建一个 C++ 程序(在两步中编译和链接) 复制链接链接已复制到粘贴板!
本例显示了构建最小 C++ 程序的确切步骤。
在本例中,编译和链接代码是两个独立的步骤。
流程
创建
hello-cpp
目录,并进到其中:mkdir hello-cpp cd hello-cpp
$ mkdir hello-cpp $ cd hello-cpp
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 创建包含以下内容的文件
hello.cpp
:Copy to Clipboard Copied! Toggle word wrap Toggle overflow 使用
g++
编译代码:g++ -c hello.cpp
$ g++ -c hello.cpp
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 目标文件
hello.o
已创建。从目标文件链接可执行文件
helloworld
:g++ hello.o -o helloworld
$ g++ hello.o -o helloworld
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 运行生成的可执行文件:
./helloworld
$ ./helloworld Hello, World!
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 可选:再次删除所有文件:
cd .. rm -r hello-cpp
$ cd .. $ rm -r hello-cpp
Copy to Clipboard Copied! Toggle word wrap Toggle overflow