【问题标题】:CMake linker "undefined reference" when switching from gcc to g++ for cross compilation从 gcc 切换到 g++ 以进行交叉编译时,CMake 链接器“未定义引用”
【发布时间】:2017-05-11 21:59:23
【问题描述】:

我有一个编译成功的 C 项目。现在我想在同一个项目中使用C++代码,所以我将main.c重命名为main.cpp。该项目是针对嵌入式微控制器的,所以我使用arm-none-eabi 工具链进行交叉编译。

当我将主文件重命名为 .cpp 时,我收到以下错误:

Linking CXX executable discovery_simple_test.elf
/usr/lib/gcc/arm-none-eabi/<long_path>/fpu/libg.a(lib_a-abort.o): In function `abort':
/build/<long_path>/newlib/libc/stdlib/abort.c:63: undefined reference to `_exit'

这是因为某些标准库不适用于此“裸机”目标。 (见https://stackoverflow.com/a/13237079/507369

这已在我的链接器脚本中解决:

/* Remove information from the standard libraries */
/DISCARD/ :
{
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
}

链接器脚本由我的 CMake 工具链文件添加:

INCLUDE(CMakeForceCompiler)

SET(CMAKE_SYSTEM_NAME Generic)
SET(CMAKE_SYSTEM_VERSION 1)

# specify the cross compiler
CMAKE_FORCE_C_COMPILER(arm-none-eabi-gcc GNU)
CMAKE_FORCE_CXX_COMPILER(arm-none-eabi-g++ GNU)

SET(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/STM32F407VGTx_FLASH.ld)
SET(COMMON_FLAGS "-mcpu=cortex-m4 -mthumb -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 -ffunction-sections -fdata-sections -g -fno-common -fmessage-length=0")
UNSET(CMAKE_CXX_FLAGS CACHE)
UNSET(CMAKE_C_FLAGS CACHE)
UNSET(CMAKE_EXE_LINKER_FLAGS CACHE)
SET(CMAKE_CXX_FLAGS "${COMMON_FLAGS} -std=c++11" CACHE STRING "" FORCE)
SET(CMAKE_C_FLAGS "${COMMON_FLAGS} -std=gnu99" CACHE STRING "" FORCE)
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections -Wl,-T ${LINKER_SCRIPT}" CACHE STRING "" FORCE)

我的CMakeLists.txt 看起来像:

project(discovery_simple_test CXX C ASM)
add_definitions(-DSTM32F407xx)

file(GLOB_RECURSE USER_SOURCES "Src/*.c" "Src/*.cpp")
include_directories(Inc)
add_executable(${PROJECT_NAME}.elf ${USER_SOURCES}  ${LINKER_SCRIPT})

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Map=${PROJECT_SOURCE_DIR}/build/${PROJECT_NAME}.map")

当链接为 C 可执行文件时,这是可行的。当链接为 C++ 可执行文件时,我收到 undefined reference 错误。

更新

我查看了由 CMake 组成的确切链接器命令,它们是:

对于 GCC(成功):

/usr/bin/arm-none-eabi-gcc  -mcpu=cortex-m4 -mthumb -mthumb-interwork 
-mfloat-abi=hard -mfpu=fpv4-sp-d16 -ffunction-sections -fdata-sections 
-g -fno-common -fmessage-length=0 -std=gnu99  -Wl,-gc-sections 
-T /path/STM32F407VGTx_FLASH.ld -Wl,
-Map=/path/build/discovery_simple_test.map 
CMakeFiles/discovery_simple_test.elf.dir/Src/main.c.obj 
<list of obj files>  
-o discovery_simple_test.elf libCMSIS.a

对于 G++(错误):

/usr/bin/arm-none-eabi-g++   -mcpu=cortex-m4 -mthumb -mthumb-interwork 
-mfloat-abi=hard -mfpu=fpv4-sp-d16 -ffunction-sections -fdata-sections 
-g -fno-common -fmessage-length=0 -std=c++11  -Wl,-gc-sections 
-T /home/niels/Dev/stm32/discovery_simple_test/STM32F407VGTx_FLASH.ld 
-Wl
-Map=/path/discovery_simple_test/build/discovery_simple_test.map 
CMakeFiles/discovery_simple_test.elf.dir/Src/stm32f4xx_hal_msp.c.obj 
CMakeFiles/discovery_simple_test.elf.dir/Src/stm32f4xx_it.c.obj   
CMakeFiles/discovery_simple_test.elf.dir/Src/main.cpp.obj 
<List of obj files>
-o discovery_simple_test.elf libCMSIS.a 

所以至少传递给 g++ 的参数是我所期望的。我尝试删除 --gc-sections 并结合添加 -nostartfiles,但这没有帮助。

【问题讨论】:

  • 这个问题可能吗? stackoverflow.com/questions/18877437/…
  • 谢谢 πάντα ῥεῖ,我检查了 main.cpp 中包含的所有头文件,代码已经包含在“extern C”中。
  • 这真的是 CMake 问题还是与 C 和 C++ 有关?
  • @usr1234567 我不知道。最后它是一个 C(++) 链接器问题,但它可能需要在 CMake 级别修复。
  • @i.amniels 当然可以,但是您必须在没有 CMake 的情况下找出标志/包含,然后将它们添加到您的 CMake 文件中。但是您的问题不是由 CMake 引起的。

标签: c++ gcc linker cmake cross-compiling


【解决方案1】:

我不确定是否有更 CMakeish 的方式来执行此操作,但请尝试添加 -specs=nosys.specs 您的 CMake 工具链文件,如下所示:

SET(CMAKE_EXE_LINKER_FLAGS "-specs=nosys.specs, -Wl,--gc-sections -Wl,-T ${LINKER_SCRIPT}" CACHE STRING "" FORCE)

“nosys”是准系统的通用实现。

https://launchpadlibrarian.net/170926122/readme.txt

【讨论】:

    【解决方案2】:

    缺少的函数必须提供newlib和硬件或操作系统之间的接口,这些被称为system calls

    可以通过添加--specs=nosys.specs 命令行选项来解决链接问题,如用户 Cinder Biscuits 所述。此选项提供系统调用的大部分非功能性实现。

    但这只能解决链接问题,如果确实需要来自newlib的功能,则需要提供系统调用的实现。

    可以在here 找到开发系统调用的指南。

    对于 STM32 微控制器,ST 提供了一个文件 syscalls.c 作为其 STM32CubeF4 软件包的一部分。该文件可以在 Projects/STM32F4-Discovery/Examples/BSP/SW4STM32/ 的包中找到。通过将此文件添加到项目中,可以提供所有系统调用的实现,并且可以使用 newlib。

    对于像 STM32 这样的小型微控制器,应该使用 newlib nano,因为它要小得多。这可以通过添加--specs=nano.specs 命令行参数来实现。

    【讨论】:

      【解决方案3】:

      链接 CXX 可执行文件 discovery_simple_test.elf /usr/lib/gcc/arm-none-eabi//fpu/libg.a(lib_a-abort.o): 在函数abort': /build/<long_path>/newlib/libc/stdlib/abort.c:63: undefined reference to_exit'

      _exit 函数是 newlib 的一部分(检查 newlib/_exit.c )。尝试将以下标志添加到 CMAKE_EXE_LINKER_FLAGS--specs=nano.specs

      由于您使用的是独立系统,因此将 -ffreestanding 添加到 C 和 C++ 编译器标志也是有意义的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-11-11
        • 2015-07-12
        • 1970-01-01
        • 2021-09-07
        • 1970-01-01
        • 1970-01-01
        • 2022-07-04
        • 1970-01-01
        相关资源
        最近更新 更多