Reputation: 1841
I have a C project which compiles successfully. Now I want to use C++ code in the same project, so I renamed main.c
to main.cpp
. The project is for an embedded microcontroller, so I'm cross compiling with the arm-none-eabi
toolchain.
When I have renamed the main file to .cpp, I get the following error:
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'
This is because some standard libraries are not available for this "bare metal" target. (see https://stackoverflow.com/a/13237079/507369)
This is solved in my linker script:
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
The linker script is added by my CMake toolchain file:
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)
My CMakeLists.txt
looks like:
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")
When linking as a C executable, this works. When linking as a C++ executable I get the undefined reference
error.
I looked at the exact linker commands composed by CMake and those are:
For GCC (successful):
/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
For G++ (Error):
/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
So at least the parameters passed to g++ are the ones I expected. I tried removing --gc-sections in combination with adding -nostartfiles, but this didn't help.
Upvotes: 3
Views: 3251
Reputation: 1841
The missing functions have to provide the interface between newlib and the hardware or the OS, these are called the system calls
.
The linking issue can be solved by adding the --specs=nosys.specs
command line option as stated by user Cinder Biscuits. This option provides mostly non-functional implementations of the system calls.
But this only solves the linking issue, if functionality from newlib is actually required, an implementation of the system calls needs to be provided.
A guide for developing the system calls can be found here.
For the STM32 microcontrollers, ST provides a file syscalls.c
as part of their STM32CubeF4 software package. The file can be found in the package at Projects/STM32F4-Discovery/Examples/BSP/SW4STM32/
. By adding this file to the project, implementations for all the syscalls are provided and newlib can be used.
For a small microcontroller like the STM32, newlib nano should be used as it is much smaller. This can be achieved by adding the --specs=nano.specs
command line parameter.
Upvotes: 2
Reputation: 25380
Linking CXX executable discovery_simple_test.elf /usr/lib/gcc/arm-none-eabi//fpu/libg.a(lib_a-abort.o): In function
abort': /build/<long_path>/newlib/libc/stdlib/abort.c:63: undefined reference to
_exit'
The _exit
function is part of newlib (check newlib/_exit.c
). Try adding following flag to the CMAKE_EXE_LINKER_FLAGS
: --specs=nano.specs
As you are on a freestanding system it makes also sense to add -ffreestanding
to both – C and C++ – compiler flags.
Upvotes: 0
Reputation: 5259
I'm not sure if there's a more CMakeish way to do this, but try adding -specs=nosys.specs
your CMake toolchain file like so:
SET(CMAKE_EXE_LINKER_FLAGS "-specs=nosys.specs, -Wl,--gc-sections -Wl,-T ${LINKER_SCRIPT}" CACHE STRING "" FORCE)
"nosys" is generic implementation for barebone systems.
https://launchpadlibrarian.net/170926122/readme.txt
Upvotes: 1