标题:Gcc 最常用的标志
来源网址:https://dvergeylen.github.io/gcc-most-common-used-flags
发布时间:2020-11-19T10:30:00+00:00
Markdown 内容:
介绍
从命令行使用 gcc
或 clang
进行编译一开始可能会让人感到害怕,但掌握一些技巧后,它们会变得非常有用且令人兴奋。
在这篇博客文章/参考页面中,我将描述我认为的最佳实践,至少是我在 C/C++ 项目中使用的一些技巧,这些技巧为我节省了数小时的头痛时间。
只要有时间,我会定期更新这篇文章,以涵盖使用 gcc
/ clang
编译时所需的材料,使您充满信心。
Gcc vs clang vs …?
我听过很多次这个问题。哪个更好/更快/更强?这是一个错误的问题!如果你试图将它们对立起来,你就错了!🙅
它们有时表现更好,有时表现更差。其他编译器也是如此。我不是在谈论它们生成的二进制文件(尽管观察到来自多个编译器的二进制文件之间的显著性能或大小差异可能会突出一些代码弱点或至少一些奇怪之处,因为这意味着它们并没有以相同的方式解释你的代码→很可能是代码味道 🧦),而是关于它们可以提供的(调试)信息。
我使用的最佳实践是,我用它们都来编译我的代码(显然不是同时)。当面对你不完全理解的编译错误时,这特别有用,因为一个有时可以输出比另一个更清晰的错误,反之亦然。它们各自的静态分析器(从 GCC 10+ 开始)将帮助你找到这些错误,并告诉你为什么这是非法代码。这显然并不意味着你的代码在没有警告/错误的情况下编译后就能正常工作,但至少是一个好的开始!
不要将编译器对立起来,接受它们的不同。让你的代码在许多编译器上编译是一个非常好的信号,表明你的代码是可移植的并且符合标准。
最常用的 gcc 标志
你可以通过 sudo apt install gcc-doc
安装 gcc
手册页。
GCC 编译标志按用途分组在 man gcc
中。在所有类别中,第一个要考虑的是:警告选项。
它列出了控制编译警告的标志。有很多标志,你不需要全部知道。有些非常具体,只在你(交叉)编译到一些不常见的架构或处理一些硬件时有用,如果没有正确配置,这些硬件的行为可能会混淆编译器。
以下是一些非常有用的警告,当一起使用时,涵盖了大多数用例:
-Wall
显示所有警告。它不会像名字所暗示的那样激活所有警告,但已经包含了很多;-Wextra
激活一些额外的警告;-Werror
将警告视为错误。你需要这个。我总是认为_“编译时的警告是运行时的错误”_。相信我,它会为你节省一些时间!-Wfatal-errors
在遇到第一个错误时停止。不要让g++
变得_那么_冗长 🙉;-Wpedantic
发出严格的 ISO C 和 ISO C++ 要求的所有警告;拒绝所有使用禁止扩展的程序,以及一些不符合 ISO C 和 ISO C++ 的程序。-pedantic-errors
只要基本标准要求诊断,就给出错误。
🧐 始终将 -Wpedantic
和 -pedantic-errors
视为调试标志。
永远不要在生产代码中使用 -Wpedantic
,因为输出的警告可能会因标准而异。简单地升级你的编译器版本可能会使其将更新的标准视为新的默认标准,并且可能会出现一些新的严格警告/错误,阻止你的代码编译。突然间,你的客户开始对你大喊大叫,因为她无法再编译你的代码,而你的代码没有任何变化!小心 🛡️!
除了警告选项类别的标志外,你还可能需要另外三个标志来使你的代码在现实世界中编译:-I
、-L
和 -l
。这三个标志分别告诉编译器在哪里查找头文件(描述库的 API)、库的位置以及要链接哪些库。
正如 man gcc
中所述,写 -l
的位置很重要:
链接器按指定的顺序搜索和处理库和目标文件。因此,foo.o -lz bar.o 在文件 foo.o 之后但在 bar.o 之前搜索库 z。如果 bar.o 引用了 z 中的函数,这些函数可能不会被加载。
一个典型的 gcc
命令行将是:
gcc -Wall -Werror ... -Ipath/to/header/files -Lpath/to/library/locations -lmylib
你可以多次使用 -I
、-L
和 -l
标志。
🧐 我应该修复第三方库的警告吗?
使用 -Werror
编译时使用第三方库可能会很麻烦。这些库可能会生成一些警告,你的代码将无法编译。尽管你可以提交 Pull Requests 来修复它们(如果相关的话),你也可能会认为生活就是这样,你对此无能为力。最简单的解决方案是使用 -isystem
而不是 -I
将它们包含为系统库。GCC 会知道你无法对这些源代码做任何事情,不会再打扰你。很整洁!
pkg-config 来救援
在多个平台/操作系统上编译时,知道头文件/库文件的位置可能很困难。pkg-config
可以通过输出配置了正确位置的编译器标志来帮助你。例如:
# 库 cURL,名为 libcurl
pkg-config --libs --cflags libcurl
# 将输出:
-I/usr/include/x86_64-linux-gnu -lcurl
在编写 Makefile 时非常方便(见下文)!
参考 Makefile
以下是一个最小的参考 Makefile。假设 libcurl
是我们需要链接的依赖项。
在同一目录下输入 make
来构建你的程序。
EXEC=my_output
CC=g++
DEBUGFLAGS=-g -Wpedantic -pedantic-errors
CPPFLAGS=-Wall -Werror -Wextra -Wfatal-errors
IFLAGS=$(shell pkg-config --cflags libcurl)
LFLAGS=$(shell pkg-config --libs libcurl)all: $(EXEC)$(EXEC):$(CC) $(DEBUGFLAGS) $(CPPFLAGS) $(IFLAGS) $(LFLAGS) main.cpp -o $(EXEC)clean:rm -f *.o $(EXEC)
EXEC
是可执行文件的名称(最终输出);CC
是你使用的 C(++) 编译器。g++
是gcc
的一部分;DEBUGFLAGS
是调试标志。-g
使编译器在二进制文件中输出符号,允许调试器运行它并设置断点。严格标志在此列为调试标志,如上所述;CPPFLAGS
是编译标志;- 你可能想通过
-std=c2x
添加你的代码所写的标准。
- 你可能想通过
IFLAGS
:预处理期间要搜索头文件的目录列表。包含一个或多个-I
标志,后跟相对或绝对路径。LFLAGS
:要链接的库列表。