CMake-按正确顺序将项目与C运行时对象文件链接

CMake - Link project with C runtime object files in correct order

本文关键字:运行时 对象 文件 链接 项目 顺序 CMake-      更新时间:2023-10-16

有C运行时/启动文件:crt0.ocrti.ocrtbegin.ocrtend.ocrtn.o

  • crtbegin.ocrtend.o由工具链(GCC(提供
  • crt0.ocrti.ocrtn.o是我自己在项目范围

该项目是关于在没有操作系统的i686裸机上运行可执行文件。

问题在于最终可执行文件的链接-项目对象文件与上述所有C运行时文件的链接顺序很重要

我的构建系统是CMake,其中我使用target_sources命令来定义可执行文件使用的源文件(编译后链接在一起(:

set( BARE_METAL app.bin )
add_executable( ${BARE_METAL} "" )
target_sources( ${BARE_METAL}
PRIVATE
boot.s  # contains symbols analogical to crt0.s
crti.s
crtn.s
a.cpp
b.cpp
# … other files go here
)
target_link_options( ${BARE_METAL}
PUBLIC
-t linker.ld
-nostdlib
-nostartfiles
)
target_link_libraries( ${BARE_METAL}
PUBLIC
support
)

问题是GCC没有与crtbegin.ocrtend.o链接,尽管它可以在我的工具链中找到:

  • toolchain/i686-elf/lib/gcc/i686-elf/10.0.1/crtbegin.o
  • toolchain/i686-elf/lib/gcc/i686-elf/10.0.1/crtend.o

你能告诉我如何从CMake中以正确的顺序调用带有所有必需参数的链接器吗?我希望有一个类似的链接命令

./i686-elf-ld -t linker.ld -nostdlib -nostartfiles boot.o crti.o crtbegin.o a.o b.o -libsupport.a crtend.o crtn.o

请注意C运行时文件的顺序。我已经简化了所有文件的目录结构,但关键的一点应该在这里强调

非常感谢任何愿意帮助我的人…Martin

更新:

我试图在等待任何建议的同时进行更多的研究,而有希望的方法似乎是使用CMAKE_CXX_LINK_EXECUTABLE来定义用于链接的特定于项目的构建规则。

我的项目使用在root/main project((语句之前设置的工具链文件。在子项目中,我设置了CMAKE_CXX_LINK_EXECUTABLE,它似乎对其他子项目没有影响。这就是为什么我称之为承诺,尽管整个事情还没有奏效。

我的计划是用三个特定于项目的C运行时文件crt0.ocrti.ocrtn.o创建一个对象库,将它们从<OBJECTS>中删除,使项目依赖于这个对象库,但在链接构建规则中手动管理运行时文件。

你认为这种方式会成功结束吗一旦我有了结果,我就会发布。。。

感谢@KamilCuk,我成功地让它运行起来。以下是我制作的解决方案(供任何试图解决相同问题的人使用(

project( Bare_Metal LANGUAGES CXX C ASM )
set( BARE_METAL app.bin )
set( BARE_METAL_CRTS app-crts )
add_library( ${BARE_METAL_CRTS} OBJECT
boot.s  # contains symbols analogical to crt0.s
crti.s
crtn.s
)
add_executable( ${BARE_METAL} "" )
target_sources( ${BARE_METAL}
PRIVATE
a.cpp
b.cpp
# … other files go here
)
target_link_options( ${BARE_METAL}
PUBLIC
-t linker.ld
-nostdlib
-nostartfiles
)
target_link_libraries( ${BARE_METAL}
PUBLIC
support
)
# This ensures the boot.o crti.o, crtn.o to be build prior to BARE_METAL target
add_dependencies( ${BARE_METAL} ${BARE_METAL_CRTS} )
# Ask GCC to get the full path name of crtbegin. and crtend.o
execute_process( COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=crtbegin.o OUTPUT_VARIABLE CRTBEGIN_O OUTPUT_STRIP_TRAILING_WHITESPACE )
execute_process( COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=crtend.o OUTPUT_VARIABLE CRTEND_O OUTPUT_STRIP_TRAILING_WHITESPACE)
# Set linker executable to be used - navigate to the toolchain used (might be setup in toolchain file)
set( BARE_METAL_LINKER ${BARE_METAL_TOOLCHAIN_ROOT}/bin/${CMAKE_TARGET_PROCESSOR}-elf-ld )
set( CMAKE_CXX_LINK_EXECUTABLE "${BARE_METAL_LINKER} <CMAKE_C_LINK_FLAGS> <FLAGS> <LINK_FLAGS> boot.obj crti.obj ${REVOLTA_CRTBEGIN} <OBJECTS> -o <TARGET> <LINK_LIBRARIES> ${REVOLTA_CRTEND} crtn.obj" )

请记住,上面的代码不是复制粘贴解决方案,而是完整的,可以作为指导/灵感来做这样的事情:(