gcc 标志重复和顺序重要吗?

Mas*_*gol 3 gcc compiler-flags

在为 python 构建 C 扩展时,我看到一些gcc重复的标志。当我跑步时:

python setup.py build_ext
Run Code Online (Sandbox Code Playgroud)

正在运行的构建命令如下所示:

gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -march=x86-64 -mtune=generic -O3 -pipe -fstack-protector-strong -fno-plt -flto=4 -fuse-linker-plugin -ffat-lto-objects -flto-partition=none -march=x86-64 -mtune=generic -O3 -pipe -fstack-protector-strong -fno-plt -march=x86-64 -mtune=generic -O3 -pipe -fstack-protector-strong -fno-plt -fPIC -I/usr/include/python3.7m -c /tmp/src/source.c -o build/temp.linux-x86_64-3.7/tmp/src/source.o
gcc -pthread -shared -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now -flto=4 -fuse-linker-plugin -ffat-lto-objects -flto-partition=none -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now build/temp.linux-x86_64-3.7/tmp/src/source.o -L/usr/lib -lpython3.7m -o build/lib.linux-x86_64-3.7/source.cpython-37m-x86_64-linux-gnu.so
Run Code Online (Sandbox Code Playgroud)

好吧,那是一篇很长的文章。但是,正如您所看到的,一些标志是重复的。这是第一个命令中的重复:

  • -O3重复4次。
  • -fno-plt重复3次。
  • -fstack-protector-strong重复3次。
  • -march=x86-64重复3次。
  • -mtune=generic重复3次。
  • -pipe重复3次。

除了-Wl,...传递给链接器的标志之外,这些标志的重复和排序还有什么意义吗?

Mik*_*han 5

在 GCC 命令行中看到重复的选项并不罕见,这些选项是由某些工具堆栈(通常是 IDE)生成的,并且人工输入位于“顶部”。

您发现的任何重复都不会影响命令行的含义。通常这种重复只是无害的冗余,而且它们可以有合理的动机。向 GCC 命令行增量添加某些内容的工具可能希望确保某个选项在此时处于启用状态,即使它可能已被自上次启用它以来附加的选项以某种方式禁用。冗余地重复该选项可能比检查它是否冗余更便宜。

但重复并不一定是无害的......

如果选项OPT出现在命令行中的某个位置:

 ... OPT ...
Run Code Online (Sandbox Code Playgroud)

那么用 2 次或更多次替换该出现的情况不会产生任何影响。

但是,如果命令行的形式为:

 ... OPT1 ... OPT2 ...
Run Code Online (Sandbox Code Playgroud)

然后OPT1在任何地方添加另一个出现的地方OPT2很可能会产生影响。OPT2同样在 之前的任何地方添加另一个出现的位置OPT1

这是因为选项出现的顺序常常会产生影响。

选项通常由标志组成,例如

 -O3             -> Flag = -O, value = 3
 -I./inc         -> Flag = -I, value = ../inc
Run Code Online (Sandbox Code Playgroud)

有些标志,例如-O可以采用一组互斥值中的任何一个。简称为互斥标志。当互斥标志与抵消值重复出现时,以命令行中的最后一个为准:

 -O1 -O2 -O3 = -O3
 -O3 -O2 -O1 = -O1
Run Code Online (Sandbox Code Playgroud)

其他标志(如-I)可以连续采用任意非独占值,这些值按其出现顺序累积,以形成作为编译或链接参数之一的序列。例如

 -I./foo -I./bar
Run Code Online (Sandbox Code Playgroud)

将 附加./foo./bar用户指定的包含目录搜索顺序以进行编译。称这些累积标志为。

其他标志是布尔值,并且具有启用形式和禁用形式,例如-fstack-protector-fno-stack-protector这些可以等同于具有独占可能值 True 和 False 的互斥选项。

还有另一种标志,例如,连续接受-l累积的任意非独占值,但每个值都成为命令行中该点的标志值 。据我所知,这是唯一的这种类型的标志,这是一种异常类型:与其说它实际上是一个选项,不如说是一个位置参数 ,标志附加了一种解释方法。它表示 此时将输入一个文件到链接,链接器将通过算法(参考选项)发现其绝对路径名。我们将此类标志称为位置标志-l-lfoolibfoo.{so|a}-L

对于互斥标志,如果稍后重复某处出现的选项,则可以更改命令行的含义。例如

 -fno-stack-protector -O1 -O3 -fstack-protector
Run Code Online (Sandbox Code Playgroud)

看起来已经有太多厨师破坏了汤汁,相当于:

 -O3 -fstack-protector
Run Code Online (Sandbox Code Playgroud)

但如果我们添加一些重复:

 -fno-stack-protector -O1 -O3 -fstack-protector -fno-stack-protector -O1
Run Code Online (Sandbox Code Playgroud)

它变得等同于:

 -O1 -fno-stack-protector
Run Code Online (Sandbox Code Playgroud)

对于累积标志,通过在某个事件发生之前重复一个选项比在事件发生之后重复一个选项更容易混淆命令行的含义:

 -I./foo -I./bar
Run Code Online (Sandbox Code Playgroud)

意思就是它所说的。然而

 -I./bar -I./foo -I./bar
Run Code Online (Sandbox Code Playgroud)

意思与以下相同:

 -I./bar -I./foo
Run Code Online (Sandbox Code Playgroud)

但这种混乱在实践中几乎不会发生,因为选项的重复几乎总是通过在增量构建期间 重复附加到命令行来生成。

根据定义,位置标志对order敏感,无论是它们之间还是与其他选项和位置参数的关系。的每一个排列

 ... -lfoo -lbar main.o ...
Run Code Online (Sandbox Code Playgroud)

产生不同的联系。重复带有位置标志的选项也可以轻松产生影响。众所周知,

... -lfoo main.o ... 
Run Code Online (Sandbox Code Playgroud)

很可能会导致链接失败,这

    ... -lfoo main.o -lfoo
Run Code Online (Sandbox Code Playgroud)

会解决的。

所以强调一下,是的,标志的重复和排序可能很重要。