3

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.

Update

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.

Community
  • 1
  • 1
i.amniels
  • 1,781
  • 1
  • 25
  • 37
  • 1
    This problem perhaps? http://stackoverflow.com/questions/18877437/undefined-reference-to-errors-when-linking-static-c-library-with-c-code/18879053#18879053 – πάντα ῥεῖ Dec 27 '16 at 15:51
  • Thank you πάντα ῥεῖ, I checked but all header files which are included in main.cpp, already have the code wrapped in "extern C". – i.amniels Dec 27 '16 at 16:03
  • Is this really a CMake problem or is it related to C and C++? – usr1234567 Dec 27 '16 at 20:12
  • @usr1234567 I don't know. In the end it is a C(++) linker problem, but it probably needs to be fixed at CMake level. – i.amniels Dec 27 '16 at 20:39
  • @i.amniels Sure, but you have to figure out the flags/includes without CMake and then add them to your CMake files. But your issue is not caused by CMake. – usr1234567 Dec 27 '16 at 20:57

3 Answers3

2

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.

i.amniels
  • 1,781
  • 1
  • 25
  • 37
1

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

Cinder Biscuits
  • 4,880
  • 31
  • 51
0

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.

ollo
  • 24,797
  • 14
  • 106
  • 155