提问人:One_Cable5781 提问时间:11/12/2023 最后编辑:One_Cable5781 更新时间:11/13/2023 访问量:75
通过 makefile 启用链接时间优化
Enabling link time optimization via makefile
问:
在尝试遵循官方 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 的交叉帖子,因为我无法在那里获得任何响应。
答:
官方文档,这里建议在链接中包括编译中使用的所有标志。
不,它没有。它说:
-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
评论
CXXFLAGS
是将 C++ 编译为目标文件的公共变量。 和 是链接的常见变量。并非所有 C++(或 C)编译器选项都对墨迹书写有意义,最好将它们分开,即使这意味着一些重复编写。LDFLAGS
LDLIBS
CXXFLAGS
CXXFLAGS
是 C++ 编译器标志变量的通用名称。事实上,它是隐式规则用于生成目标文件的变量。与 C 源文件到目标文件编译、链接器标志和库相同。make
CFLAGS
LDFLAGS
LDLIBS
CXXFLAGS
LDFLAGS