C语言 通过makefile启用链接时间优化

e5njpo68  于 2023-11-16  发布在  其他
关注(0)|答案(1)|浏览(131)

在尝试遵循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 here的交叉发布,因为我无法在那里获得任何响应。

edqdpe6u

edqdpe6u1#

官方文档,这里建议在链接中也包括编译中使用的所有标志。
不,它没有。它说:
-flto优化选项应在编译时和最终链接期间指定。
(着重号是加上去的)这就是下一句话的上下文,.
建议您使用相同的选项编译参与同一链接的所有文件,并在链接时指定这些选项。
对于LTO目的,只有optimization options,包括-flto,需要统一用于链接和所有贡献编译。
您提供的CXXFLAGS中唯一的优化选项是-fno-strict-aliasing。您的单源编译命令包括-O2 -flto,这也是优化选项,当然-flto是您首先询问的特定选项。在您在各个地方显示的选项中,在编译时和链接时都需要单独使用这三个选项来支持链接时优化。(出于不同的原因,在这两个地方可能都需要其他选项。)
旁注:由于您提出了一个单源构建规则,我不得不注意到,在单源构建中,链接时优化不会给您带来任何好处。
目前,我的链接命令是简洁的,只是[似乎没有提供可配置的非库链接选项]。
我现在是否应该将其修改为较长的[...],从而在链接命令中重复所有编译命令标志?
我建议分解出优化标志:

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

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

字符串
.并将LDFLAGS扩展到link命令中:

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


然后,在决定向哪个变量添加特定选项时,您必须保持一定的纪律,但您不需要复制任何选项,并且您不会面临编译和链接阶段之间优化标志不一致的风险。
我的编译标志也包含一些通过-I /path/to/header的头文件的包含目录。2它们也应该放在链接器命令中吗?
不。这不是一个优化选项。严格地说,它甚至不是一个编译选项,而是一个预处理器选项,尽管它将在编译期间使用。
所有的编译标志也可以作为链接器标志吗?
这取决于你的编译器,你的链接器,以及你如何调用它们。在GCC系统中,通常通过g++前端调用C++编译器和链接器。这个前端确实识别所有阶段的所有选项,它只会适当地将相关的选项传递给编译器和链接器后端。
是否有些标志在链接器和编译器之间是通用的,而有些是编译器专用的,还有一些是链接器专用的?
编译器和链接器做不同的工作,尽管LTO模糊了那里的行。它们各自有自己的选项,相对来说重叠很少,尽管当它们通过公共前端访问时会被模糊。
值得注意的是,尽管g++gcc前端公开了链接器的许多选项,但它们并没有直接公开 * 所有 * 链接器选项。因此,它们提供了means to pass arbitrary options directly through to the linker-Xlinker-Wl)。

相关问题