【问题标题】:cmake: Link order of external (generated) and compiled objects, and libscmake:外部(生成的)和编译的对象和库的链接顺序
【发布时间】:2019-06-10 23:27:07
【问题描述】:

我正在使用裸机 x86,但在将我的构建从直接 makefile 移植到 cmake 时遇到了困难。

在我的 makefile 中,我的对象是这样定义的:

LINK_LIST=\
$(LDFLAGS) \
$(ARCHDIR)/crti.o \
$(ARCHDIR)/crtbegin.o \
$(KERNEL_OBJS) \
$(LIBS) \
$(ARCHDIR)/crtend.o \
$(ARCHDIR)/crtn.o \

crtbegin.o 和 crtend.o 是“生成的”,即由我的交叉编译器提供(-print-file-name 标志)。 $(LIBS) 是 -l 标志,如 -lgcc 等。由于这是直接传递给链接器的,因此顺序是指定的。

我的 cmake 目标定义如下:

ADD_EXECUTABLE(loader 
    "${INIT_SRC}"
    "${INIT_OBJ}"
    "${PLATFORM_SRCS}"
    "${ISA_SRCS}"
    "${GENERIC_SRCS}"
    "${FINI_OBJ}"
    "${FINI_SRC}")

INIT_OBJ 和 FINI_OBJ 在源文件属性中将 EXTERNAL_OBJECT 和 GENERATED 设置为 true。在运行生成的 makefile 时查看命令行,我看到所有源文件都按指定的顺序排列,但 init 和 fini 对象在列表中的最后。

这是生成的命令行(为简洁而编辑):

i686-elf-gcc -nostdlib -ffreestanding -nostdinc -T linker.ld -lgcc crti.s.obj boot.s.obj loader.c.obj crtn.s.obj crtbegin.o crtend.o -o loader

-lgcc 标志在我的 LINK_FLAGS 中是明确的,这也是我想更改的。

所以我对此有几个问题:

  1. 为什么 cmake 不对两个外部对象文件使用顺序,而是对编译后的文件使用它?

  2. 如何告诉 cmake 将这些对象与来自我的源的对象一样对待?

  3. 如何获得我在 Makefile 中的设置的完整克隆(在我的目标文件之间包含库标志)

我也检查了 CMAKE_C_LINK_EXECUTABLE,但它似乎没有足够的粒度/对链接器参数的控制来实现这一点。

我在 ubuntu 上使用 cmake 3.10.2。

还有一个关于 cmake 的(题外话)问题:

它不会将 .S 视为标准程序集文件扩展名。我尝试使用LIST(APPEND CMAKE_ASM-ATT_SOURCE_FILE_EXTENSIONS S) 添加它,它确实添加它就好了,但是除非我将其更改为.s,否则文件仍然没有被编译。有其他人遇到过这个问题吗?

谢谢!

【问题讨论】:

  • 至于附加问题,.S 扩展是指需要预处理的汇编代码。一些 C 编译器能够预处理该代码并编译它。但并非所有 ASM 编译器都能够预处理代码。在CMake wiki 中查看更多信息。请在问题帖子中提出一个单个问题 - 这就是 Stack Overflow 的工作原理。
  • 至于“主要”问题,在源文件/目标文件的具体顺序上有点意思。 libraries 应该按顺序排列。 CMake 有一个用于链接库的特殊命令 - target_link_libraries。传递给该命令的所有选项都将在命令行中 带有保证的目标文件之后出现。
  • 1.你是对的,题外话不属于这里。它不会再发生了。 2. 我知道 .S 文件是用来预处理的,但 cmake 不处理它们似乎很奇怪。感谢您的链接,我在搜索 .S 问题时没有遇到此页面。
  • 3.我正在关注 [osdev.org](osdev.org) 上的一堆文章/教程,特别是 thisthis,其中说目标文件必须按特定顺序链接。

标签: cmake


【解决方案1】:

对象crtbegin.ocrtend.o在链接命令中对位置有特殊要求,可以作为工具链的一部分。如果您决定这样做,那么您可以设置变量 CMAKE_C_LINK_EXECUTABLE 以反映这一具体情况:

SET(ARCHDIR "<...>")
# Object 'crtbegin.o' will be linked before all other objects and libraries.
# Object 'crtend.o' will be linked after all other objects and libraries.
SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> 
    <LINK_FLAGS>
    ${ARCHDIR}/crtbegin.o
    <OBJECTS> -o <TARGET> <LINK_LIBRARIES>
    ${ARCHDIR}/crtend.o")

此设置应在工具链文件中完成,该文件通过选项-DCMAKE_TOOLCHAIN=&lt;path/to/toolchain/file&gt; 传递给cmake

有了这样的工具链,在CMakeLists.txt你可以简单地写

ADD_EXECUTABLE(loader ${PLATFORM_SRCS} ${ISA_SRCS} ${GENERIC_SRCS})

使用CMAKE_C_LINK_EXECUTABLE 变量,您还可以定位选项,例如

-nostdlib -ffreestanding -nostdinc -T linker.ld -lgcc

它们也与工具链非常相关。

另请参阅此邮件:https://cmake.org/pipermail/cmake/2010-June/037641.html

【讨论】:

  • 谢谢,您建议的方式有效。剩下的一个问题是 INIT_SRC 应该在 INIT_OBJ 之前链接,而 FINI_SRC 在 FINI_OBJ 之后。我想这些也是特定于工具链的。我应该/可以在工具链文件中显式编译它们并将它们添加到 CMAKE_LINK_C_EXECUTABLE 中吗?
  • “我应该/我可以在工具链文件中显式编译它们并将它们添加到 CMAKE_LINK_C_EXECUTABLE 中吗?” - 看起来如此...至少,我不知道在库之后放置目标文件的其他方法。请注意,您不能在工具链中使用add_executable。所以你需要使用execute_processadd_custom_command 来编译init_srcfini_src
  • 谢谢,有机会我试试
猜你喜欢
  • 2021-10-18
  • 2021-04-19
  • 1970-01-01
  • 1970-01-01
  • 2021-09-17
相关资源
最近更新 更多