【问题标题】:CMake cross-compile with specific linker doesn't pass arguments to armlink使用特定链接器进行交叉编译的 CMake 不会将参数传递给 armlink
【发布时间】:2015-07-30 13:24:42
【问题描述】:

我正在尝试为嵌入式 ARM Cortex 构建交叉编译项目,但无法使链接器正常工作。我想使用 armlink,但没有文件传递给 armlink,因此没有生成 .elf 文件。

我的 CMakeLists.txt 非常简单,如下所示。失败后显示,表明生成文件调用了armlink,没有任何参数。

任何指针都会有所帮助 - 我搜索并阅读了许多帖子,但它们似乎都有更多涉及的要求。

cmake_minimum_required(VERSION 2.8)

project(test_arm)
enable_language(C ASM)

# Cross-compilation for ARM
SET(CMAKE_C_COMPILER armcc)
SET(CMAKE_LINKER armlink)
SET(CMAKE_C_LINK_EXECUTABLE armlink)

SET(CMAKE_C_FLAGS "--cpu=Cortex-M3")
SET(LINK_FLAGS "--map --ro-base=0x0 --rw-base=0x0008000 --first='boot.o(RESET)' --datacompressor=off")
SET(CMAKE_EXE_LINKER_FLAGS "--map --ro-base=0x0 --rw-base=0x0008000 --first='boot.o(RESET)' --datacompressor=off")

include_directories(../include)

add_executable(blinky blinky.c)
set_target_properties(blinky PROPERTIES LINKER_LANGUAGE C)

失败如下,但我想这对某人来说是显而易见的,因为我的 CMakeLists 中有一些愚蠢的问题:

$ make VERBOSE=1
[100%] Building C object CMakeFiles/blinky.dir/blinky.c.o
/usr/bin/cmake -E cmake_link_script CMakeFiles/blinky.dir/link.txt --verbose=1
armlink
Linking C executable blinky
Product: DS-5 Professional 5.21.0 [5210017]
Component: ARM Compiler 5.05 update 1 (build 106)
Tool: armlink [4d0efa]
For support see http://www.arm.com/support/
Software supplied by: ARM Limited
Usage: armlink option-list input-file-list
where
....

我期待 CMake 生成的 Makefile 调用 armlink,如下所示:

armlink --map --ro-base=0x0 --rw-base=0x0008000 \
  --first='boot.o(RESET)' --datacompressor=off \
  CMakeFiles/blinky.dir/blinky.c.o -o blinky.elf

【问题讨论】:

    标签: c linker cmake cross-compiling


    【解决方案1】:

    CMake v3.5 开始,您不再需要 Keil ARM C/C++ 编译工具的工具链:

    添加了对编译器 ID 为 ARMCC 的 ARM 编译器 (arm.com) 的支持。

    只需相应地设置您的 C/CXX 编译器变量

    cmake -DCMAKE_C_COMPILER:PATH="C:\Program Files (x86)\DS-5\bin\armcc.exe"
          -DCMAKE_CXX_COMPILER:PATH="C:\Program Files (x86)\DS-5\bin\armcc.exe"
          ...
    

    参考文献

    【讨论】:

      【解决方案2】:

      根据我的经验,您不能在 CMakeLists.txt 文件中设置 CMAKE_EXE_LINKER_FLAGS。在构建目录中第一次调用 CMake 时,它​​必须通过 CMAKE_TOOLCHAIN_FILE 传递。

      我没有找到任何关于这个问题的文档,但是如果你进行交叉编译,你应该使用 cross-compilation with CMake 页面。

      首先,只需将您的 set-calls 放入工具链文件并运行

      cmake -DCMAKE_TOOLCHAIN_FILE=<yourfile.toolchain>
      

      在干净的构建目录中。

      【讨论】:

      • 谢谢帕特里克。我试过这个,但没有取得进展。我浏览了该页面并创建了一个工具链文件并按照您在上面写的那样在命令行上传递。我仍然无法让链接器工作。我确实从一个干净的构建目录开始。还有什么想法吗?
      【解决方案3】:

      工具链文件可能是个好主意。这是我上次尝试使用 DS-5 工具链的 CMake 2.8.10 时提出的(它仍然可以优化,但它应该给你一个起点):

      INCLUDE(CMakeForceCompiler)
      
      # This one is important
      SET(CMAKE_SYSTEM_NAME Generic)
      SET(CMAKE_SYSTEM_PROCESSOR arm)
      
      # Specify the cross compiler
      SET(CMAKE_C_COMPILER "C:/Program Files (x86)/DS-5/bin/armcc.exe")
      SET(CMAKE_CXX_COMPILER "C:/Program Files (x86)/DS-5/bin/armcc.exe")
      SET(CMAKE_AR "C:/Program Files (x86)/DS-5/bin/armar.exe" CACHE FILEPATH "Archiver")
      
      #CMAKE_FORCE_C_COMPILER("C:/Program Files (x86)/DS-5/sw/gcc/bin/arm-linux-gnueabihf-gcc.exe" GNU)
      #CMAKE_FORCE_CXX_COMPILER("C:/Program Files (x86)/DS-5/sw/gcc/bin/arm-linux-gnueabihf-g++.exe" GNU)
      
      UNSET(CMAKE_C_FLAGS CACHE)
      SET(CMAKE_C_FLAGS "--cpu=Cortex-A9 --thumb -Ospace" CACHE STRING "" FORCE)
      UNSET(CMAKE_CXX_FLAGS CACHE)
      SET(CMAKE_CXX_FLAGS ${CMAKE_C_FLAGS} CACHE STRING "" FORCE)
      UNSET(CMAKE_EXE_LINKER_FLAGS CACHE)
      SET(CMAKE_EXE_LINKER_FLAGS "" CACHE STRING "" FORCE)
      UNSET(CMAKE_AR_FLAGS CACHE)
      SET(CMAKE_AR_FLAGS "-p -armcc,-Ospace" CACHE STRING "" FORCE)
      
      # set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> cr <TARGET> <LINK_FLAGS> <OBJECTS>")
      SET(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> ${CMAKE_AR_FLAGS} -o <TARGET> <OBJECTS>" CACHE STRING "C Archive Create")
      # set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> cr <TARGET> <LINK_FLAGS> <OBJECTS>")
      SET(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> ${CMAKE_AR_FLAGS} -o <TARGET> <OBJECTS>" CACHE STRING "CXX Archive Create")
      
      include_directories("C:/Program Files (x86)/DS-5/include")
      #include_directories("C:/Program Files (x86)/DS-5/sw/gcc/arm-linux-gnueabihf/libc/usr/include/arm-linux-gnueabi")
      
      # Where is the target environment
      SET(CMAKE_FIND_ROOT_PATH "C:/Program Files (x86)/DS-5")
      
      # Search for programs in the build host directories
      SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
      
      # For libraries and headers in the target directories
      SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
      SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
      

      关于您的问题

      一些故障分析

      您尝试过的应该可以工作(另请参阅例如 How do I add a linker or compile flag in a CMake file?)。但是在配置步骤中似乎出了点问题。

      我不知道您对 CMake 的配置/生成步骤的命令行调用,所以一些一般提示可以找到根本原因:

      你可以试试打电话

      cmake.exe --trace ...
      

      查看您的 CMAKE_EXE_LINKER_FLAGS 变量出了什么问题。这会产生大量的输出,所以这里有一些关于 CMake 的基础知识:

      • project() 命令将触发编译器评估
      • 这会将CMAKE_EXE_LINKER_FLAGS 写入您的CMakeCache.txt
      • 您正在用局部变量覆盖它(请参阅变量范围文档here

      如果你查看share\cmake-2.8\Modules\CMakeCommonLanguageInclude.cmake

      set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS_INIT} $ENV{LDFLAGS}"
           CACHE STRING "Flags used by the linker.")
      

      您可以使用CMAKE_EXE_LINKER_FLAGS_INIT,但您必须在project() 命令之前或在工具链文件中设置它。

      因为您将链接语言设置为C,请查看share\cmake-2.8\Modules\CMakeCInformation.cmake

      if(NOT CMAKE_C_LINK_EXECUTABLE)
        set(CMAKE_C_LINK_EXECUTABLE
          "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
      endif()
      

      因此您可以使用CMAKE_C_LINK_EXECUTABLE 覆盖完整的链接器调用,或者您可以使用CMAKE_C_LINK_FLAGS 设置其他标志。

      “官方”方式

      设置target's linker and compiler flags 的官方方法是(在 CMake 2.8.12 之前):

      set_property(TARGET blinky APPEND_STRING PROPERTY COMPILE_FLAGS "--cpu=Cortex-M3")
      set_property(TARGET blinky APPEND_STRING PROPERTIES LINK_FLAGS "--map --ro-base=0x0 --rw-base=0x0008000 --first='boot.o(RESET)' --datacompressor=off")
      

      从 CMake 2.8.12 开始,它会是这样的:

      add_compile_options("--cpu=Cortex-M3")
      

      【讨论】:

      • 感谢 Florian 的详细回复。我在这上面花了几个小时,但还没有进展。我什至无法让 armcc 工作。抱怨它甚至无法编译一个简单的程序。我开始使用工具链文件并添加了 SET(CMAKE_C_LINK_EXECUTABLE=" ${CMAKE_C_LINK_FLAGS} -o ") 但这没有帮助。
      • 好的,还有一个问题。我意识到我需要构建我的 SET(CMAKE_C_COMPILE_OBJECT " ${....) 才能使用强制编译器进行编译。但是如何让它利用 include_directories??
      • 很遗憾听到它不起作用。但我相信我们可以找到可行的解决方案。
      • 如果您遇到“无法编译简单程序”错误的问题,您应该在您的 cmake.exe 命令行选项中添加--debug-trycompile。这将保留 CMakeFiles\CMakeTmp 目录以检查编译器运行输出(包括日志文件)。我使用Ninja 作为 ARM 的替代品,因为它提供了它所尝试的详细输出(完整的命令行调用,我可以在命令行上复制/粘贴以进行测试;非常有帮助;还要检查它的 @ 987654343@ 文件)。请添加更多关于您遇到的错误的详细信息。
      • 对于您的第一个测试 - 不推荐作为最终解决方案 - 您可以将以下两行添加到您的工具链文件中以绕过 CMake 自己的编译器测试:SET(CMAKE_C_COMPILER_WORKS 1 CACHE INTERNAL "")SET(CMAKE_CXX_COMPILER_WORKS 1 CACHE INTERNAL "")。此外 - 为确保工具链文件中设置的变量是您在编译器调用中的最终结果 - 您可以/应该将 CACHE ... FORCE 添加到 set() 命令。更多详情见stackoverflow.com/questions/11423313/…
      猜你喜欢
      • 2020-11-11
      • 2018-09-12
      • 2023-04-08
      • 1970-01-01
      • 2021-12-30
      • 1970-01-01
      • 1970-01-01
      • 2021-09-07
      • 1970-01-01
      相关资源
      最近更新 更多