链接对象 ST 的 CubeIDE 发出如下命令:
arm-none-eabi-g++ -mcpu=cortex-m33 --specs=nosys.specs -Wl,-Map=mymap.map -Wl,--gc-sections -static --specs=nano.specs -mfpu=fpv5-sp-d16 -mfloat-abi=hard -mthumb -Wl,--start-group -lc -lm -lstdc++ -lsupc++ -Wl,--end-group -Tmyldscript.ld @myobjects.txt -o myelf.elf
我试图理解为什么他们多次使用
-Wl
和--start-group
/--end-group
。
这有正当理由吗?这个命令可以简化一下吗?
-Wl
-Wl
被多次使用,因为每次都需要 g++
必须被告知
它应该将链接器选项直接传递给链接器,ld
,而不是
尝试解析选项本身(并可能给出未知选项错误)。
-Wl,<linker-option>[,<linker-option>...]
是一个 GCC 选项,意味着 pass
<linker-option> [<linker-option>...]
到链接器。请参阅 GCC 手册:3.15 链接选项。
--开始组/--结束组
用于:
--start-group -liba [liba...] --end-group
是配对的链接器选项。默认情况下,链接器会将静态库视为候选库 用于解决迄今为止仅当静态库时才产生链接的未定义符号引用 是第一次输入,不再输入(除非再次输入库)。
--start-group/--end-group
选项
告诉链接器暂停其对所包含的静态库序列的默认策略 -liba [liba...]
而是循环地考虑和重新考虑它们,解决未定义的引用并积累新的引用,
直到没有新的产生为止。请参阅 GNU ld 手册:2.1 命令行选项
当封闭的静态之间存在循环依赖时,--start-group/--end-group
是必要的
库-liba [liba...]
,这意味着链接器不可能解析所有未定义的
如果每个库在第一次看到时只被考虑一次,则由它们的链接产生的引用。
当之间不存在任何循环依赖性时,--start-group/--end-group
很有用,但不是必需的。
-liba [liba...]
但是组成链接命令行的人或构建系统确实知道这一点并且不知道
知道在默认策略下输入库的成功顺序。
如果使用
--start-group/--end-group
“强力”成功链接本来可以按依赖顺序输入的无序库
使用链接器的默认策略会导致效率低下:链接器必须重新访问它会访问的库
如果输入顺序正确,则无需重新访问。
一般来说,仅通过查看链接命令行无法判断是否使用了
--start-group/--end-group
是必要的,因为仅仅通过查看所包含的-liba [liba...]
是不可能判断出是否包含
循环依赖。构建自动化系统,例如 CMake、Meson 等,可能会强加自己的 --start-group/--end-group
链接中序列库的默认策略,以便暴力破解静态库的成功链接
构建系统不知道如何排列依赖顺序。
--start-group -liba [liba...] --end-group
对共享的封闭库没有影响,而不是静态库,
但无论如何,构建系统都可能将它们包含在内,因为即使所有库都是无害的,这也是无害的
共享库。对于您的情况,所有库选项:
-lc -lm -lstdc++ -lsupc++
必须解析为静态库,因为选项
-static
已预先指定。
这个命令可以简化吗?
片段:
-Wl,--start-group -lc -lm -lstdc++ -lsupc++ -Wl,--end-group
可以重写为:
-Wl,--start-group,-lc,-lm,-lstdc++,-lsupc++,--end-group
少用一个
-Wl
。这是因为选项 -l lib
是 GCC 和链接器的选项,并且对于两者具有相同的含义。 (这是
事实上,这是一个非常常用的链接器选项,GCC 会将其传递给链接器,而不需要 -Wl
。其他此类链接器选项
是 -L dir
和 -static
)。然而,传统做法是仅将 -Wl
应用于 GCC 不 识别自身的链接器选项。
在链接中使用
--start-group/--end-group
是一种强制使用。没有它,库可以链接
按依赖顺序:
lstdc++ -lsupc++ -lm -lc