通过 makefile 启用链接时间优化

Enabling link time optimization via makefile

提问人:One_Cable5781 提问时间:11/12/2023 最后编辑:One_Cable5781 更新时间:11/13/2023 访问量:75

问:

在尝试遵循官方 GNU 文档为我的一些 C 和 C++ 代码启用链接时间优化时,我遇到了一些困惑。

官方文档,这里建议在链接中包括编译中使用的所有标志。他们提供的示例相当简单。在我的makefile中,编译选项非常大且详细,如下所示:

CXXFLAGS=-m64 -fno-common -fPIC -fno-strict-aliasing -fexceptions -fopenmp -Wall -Wextra -DVSCODE

用于从单个源文件构建目标的实际编译命令如下所示:

$(COMPILE.cc) -O2 -DNDEBUG -DBOOST_DISABLE_ASSERTS -flto -std=c++17 -MMD -MP -MF "[email protected]" -o ${OBJECTDIR}/_ext/0/main.o ../code/main.cpp

那么,按照文档,我是否应该在链接时再次包含上述所有标志?

目前,我的链接命令简洁明了:

${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/linux ${OBJECTFILES} ${LDLIBSOPTIONS} -lm -lpthread -ldl -lboost_timer

我现在是否应该将其修改为相当长的内容:

${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/linux -flto -O2 -DNDEBUG -DBOOST_DISABLE_ASSERTS -std=c++17 -MMD -MP -MF "[email protected]" ${CXXFLAGS} ${OBJECTFILES} ${LDLIBSOPTIONS} -lm -lpthread -ldl -lboost_timer

从而在链接命令中重复所有编译命令标志?这似乎相当复杂且容易出错(如果我忘记更新链接器命令但为编译器添加一些标志),因此在此线程中进行查询。上面没有指定,我的编译标志还包含一些通过 .它们是否也应该放在链接器命令中?-I /path/to/header

是否可以将所有编译标志也作为链接器标志?某些标志在链接器和编译器之间是通用的,而其他标志是专门用于编译器的,还有一些是专门用于链接器的标志?

这是来自 /r/cpp_questions 交叉帖子,因为我无法在那里获得任何响应。

C++ C 生成文件

评论

0赞 Some programmer dude 11/12/2023
CXXFLAGS是将 C++ 编译为目标文件的公共变量。 和 是链接的常见变量。并非所有 C++(或 C)编译器选项都对墨迹书写有意义,最好将它们分开,即使这意味着一些重复编写。LDFLAGSLDLIBS
0赞 One_Cable5781 11/12/2023
@Someprogrammerdude 为了让我理解得更清楚,我的经验是,它实际上被放入编译器命令和链接器命令中。这就是你说的“普通”吗?或者说,您的意思是如果我有多个源文件,则对于每个源文件,“CXXFLAGS”将通用应用?CXXFLAGS
1赞 Some programmer dude 11/12/2023
CXXFLAGS是 C++ 编译器标志变量的通用名称。事实上,它是隐式规则用于生成目标文件的变量。与 C 源文件到目标文件编译、链接器标志和库相同。makeCFLAGSLDFLAGSLDLIBS
0赞 John Bollinger 11/12/2023
@One_Cable5781,您的体验反映了一个共同的惯例。构建系统(例如基于 Autotools 的系统)会生成链接规则,这些规则包括编译阶段标志(例如,from )和特定于链接的标志 from 。许多手写的 makefile 也这样做。这很少是有害的,有时是有用的。CXXFLAGSLDFLAGS

答:

2赞 John Bollinger 11/13/2023 #1

官方文档,这里建议在链接中包括编译中使用的所有标志。

不,它没有。它说:

-flto优化选项应在编译时和最终链接期间指定。

(强调是后加的。这就是下一句话的上下文,......

建议您使用相同的选项编译参与同一链接的所有文件,并在链接时指定这些选项。

...应该被理解。出于 LTO 目的,只有优化选项(包括 )需要统一用于链接和所有贡献编译。-flto

您提供的唯一优化选项是 。您的单源编译命令包括 ,这也是优化选项,当然也是您首先询问的特定选项。在各个位置显示的选项中,只有这三个选项需要在编译时和链接时使用,以支持链接时优化。(由于不同的原因,这两个地方可能需要其他选项。CXXFLAGS-fno-strict-aliasing-O2 -flto-flto


旁注:由于您提出了单源构建规则,因此我不得不观察到链接时优化在单源构建中没有任何好处。


目前,我的链接命令很简洁,只是 [似乎没有提供可配置的非库链接选项]。

我现在是否应该将其修改为相当长的 [...] 从而在链接命令中重复所有编译命令标志?这似乎相当复杂且容易出错

我建议分解优化标志:

OPT_FLAGS = -O2 -fno-strict-aliasing -flto

CXXFLAGS = $(OPT_FLAGS) ...
LDFLAGS = $(OPT_FLAGS) ...

...并展开到链接命令中:LDFLAGS

${LINK.cc} $(LDFLAGS) -o ...

然后,在决定向哪个变量添加特定选项时,您必须保持一定的纪律,但您不需要复制任何变量,并且您不会面临编译和链接阶段之间出现优化标志不一致的风险。

我的编译标志还包含一些用于头文件的包含目录。它们是否也应该放在链接器命令中?-I /path/to/header

不。这不是一个优化选项。严格来说,它甚至不是一个编译选项,而是一个预处理器选项,尽管它将在编译过程中使用。

是否可以将所有编译标志也作为链接器标志?

这取决于编译器、链接器以及调用它们的方式。在 GCC 系统中,通常通过前端调用 C++ 编译器和链接器。此前端可以识别所有阶段的所有选项,并且会根据需要仅将相关选项传递给编译器和链接器后端。g++

某些标志在链接器和编译器之间是通用的,而其他标志是专门用于编译器的,还有一些是专门用于链接器的标志?

编译器和链接器执行不同的工作,尽管 LTO 模糊了其中的界限。它们都有自己的选择,重叠相对较少,尽管当通过公共前端访问它们时,这些重叠就会被掩盖。

值得注意的是,尽管 和 前端公开了许多链接器选项,但它们并不直接公开所有链接器选项。因此,它们提供了将任意选项直接传递给链接器 (, ) 的方法。g++gcc-Xlinker-Wl