从GCC切换到g++进行交叉编译时,C使链接器未定义引用(&Q)
我有一个编译成功的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++的参数是我所期望的。我试着结合添加-nostartfile来删除--gc-sections,但无济于事。
解决方案
缺少的函数必须提供newlib与硬件或操作系统之间的接口,这称为system calls
。
链接问题可以通过添加--specs=nosys.specs
命令行选项来解决,如用户Cinder饼干所述。此选项主要提供系统调用的非函数实现。
但这只解决了链接问题,如果实际上需要来自newlib的功能,则需要提供系统调用的实现。
here可以找到开发系统调用的指南。对于STM32微控制器,ST提供了一个syscalls.c
文件作为其STM32CubeF4软件包的一部分。该文件可以在Projects/STM32F4-Discovery/Examples/BSP/SW4STM32/
的包中找到。通过将此文件添加到项目中,将提供所有syscall的实现并可以使用newlib。
对于像STM32这样的小型微控制器,应该使用newlib Nano,因为它要小得多。这可以通过添加--specs=nano.specs
命令行参数来实现。
相关文章