2026-01-08 1:31 AM
Hello,
I have observed this issue in version 6.16.1 across several MCU series (F3, F4, H5, H7), though it appears likely that all earlier versions are affected.
The generated .cmake toolchain files incorrectly treat the --specs=nano.specs option as linker-only. This option should be applied globally, as it also affects the system include paths used during compilation. Specifically, it causes the compiler to include arm-none-eabi/include/newlib-nano/newlib.h instead of the standard arm-none-eabi/include/newlib.h.
While this mismatch probably does not break ABI compatibility—since the structures provided from the standard headers are larger than those used in the compiled newlib-nano library—it does negate the RAM usage benefits of newlib-nano. This is particularly problematic when using the USE_NEWLIB_REENTRANT FreeRTOS option.
Regards,
Peter
Solved! Go to Solution.
2026-01-09 7:33 AM - edited 2026-01-09 7:44 AM
Ah, I think this is caused by some funny logic in CMake's own compiler/ABI detection process (not necessarily a bug). Normally this compilation step should always be "skipped", but it is skipped because another compilation step before runs successfully. But because of the misconfigured flags this first step fails.
Anyhow, the issue with the flags is that the toolchain file is supposed to set CMAKE_<LANG>_FLAGS_INIT , not CMAKE_C_FLAGS. Similarly the toolchain file should also use CMAKE_C_FLAGS_RELEASE_INIT instead of CMAKE_C_FLAGS_RELEASE, but that doesn't work, because if we don't override the latter, CMake will initialize it with "-O3 -DNDEBUG", and we don't want "-O3".
So try it with:
# MCU specific flags
set(TARGET_FLAGS "-mcpu=cortex-m0plus --specs=nano.specs")
set(CMAKE_C_FLAGS_INIT "${TARGET_FLAGS}")
set(CMAKE_ASM_FLAGS_INIT "${CMAKE_C_FLAGS_INIT} -x assembler-with-cpp -MMD -MP")
string(APPEND CMAKE_C_FLAGS_INIT " -Wall -fdata-sections -ffunction-sections")
set(CMAKE_ASM_FLAGS_DEBUG "-O0 -g3")
set(CMAKE_ASM_FLAGS_RELEASE "-Os -g3")
set(CMAKE_C_FLAGS_DEBUG "-O0 -g3")
set(CMAKE_C_FLAGS_RELEASE "-Os -g3")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3")
set(CMAKE_CXX_FLAGS_RELEASE "-Os -g3")
set(CMAKE_CXX_FLAGS_INIT "${CMAKE_C_FLAGS_INIT} -fno-rtti -fno-exceptions -fno-threadsafe-statics")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-T \"${CMAKE_SOURCE_DIR}/STM32U083xx_FLASH.ld\"")
string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " -Wl,-Map=${CMAKE_PROJECT_NAME}.map -Wl,--gc-sections")
string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " -Wl,--print-memory-usage")
set(TOOLCHAIN_LINK_LIBRARIES "-lm")
2026-01-08 1:52 AM
Hello @peterdonchev
Thank you for highlighting this issue.!
I will check this internally with the dedicated team and get back to you ASAP.
KR, Souhaib
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2026-01-09 3:34 AM
There's another little issue related to this:
The gcc-arm-none-eabi.cmake file passes TARGET_FLAGS to CMAKE_EXE_LINKER_FLAGS . But this is pointless, as TARGET_FLAGS is already included in CMAKE_C_FLAGS (and thereby also CMAKE_CXX_FLAGS) which gets passed to the linker automatically anyways by CMake. This results in the TARGET_FLAGS being passed to the linker twice. Apparently in the case of the --specs=nano.specs flag, this can cause linker errors.
So I think the --specs=nano.specs flag should be moved to TARGET_FLAGS (instead of CMAKE_EXE_LINKER_FLAGS), and TARGET_FLAGS should not be passed to CMAKE_EXE_LINKER_FLAGS.
For example (including my previous suggestions:(
# MCU specific flags
set(TARGET_FLAGS "-mcpu=cortex-m0plus --specs=nano.specs")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${TARGET_FLAGS}")
set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp -MMD -MP")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fdata-sections -ffunction-sections")
set(CMAKE_C_FLAGS_DEBUG "-O0 -g3")
set(CMAKE_C_FLAGS_RELEASE "-Os -g3")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3")
set(CMAKE_CXX_FLAGS_RELEASE "-Os -g3")
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fno-rtti -fno-exceptions -fno-threadsafe-statics")
set(CMAKE_EXE_LINKER_FLAGS "-T \"${CMAKE_SOURCE_DIR}/STM32U083xx_FLASH.ld\"")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Map=${CMAKE_PROJECT_NAME}.map -Wl,--gc-sections")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--print-memory-usage")
set(TOOLCHAIN_LINK_LIBRARIES "-lm")
2026-01-09 4:02 AM
Hi @Erlkoenig ,
I ran into the same issue with parameters being passed twice. I'm not sure which extension or tool is causing it, but I found a workaround.
1. Split the toolchain file:
First, I copied the original gcc-arm-none-eabi.cmake to a new file named gcc-arm-none-eabi_include.cmake.
Then, I include this file in the main CMakeLists.txt before the project() definition (this part is crucial):
# Enable compile command to ease indexing with e.g. clangd
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
include("cmake/gcc-arm-none-eabi_include.cmake")
# Core project settings
project(${CMAKE_PROJECT_NAME})
message("Build type: " ${CMAKE_BUILD_TYPE})
2. Strip all flags from the original toolchain file
From the original gcc-arm-none-eabi.cmake, I removed (or commented out) all compiler and linker flags. The file now contains only the toolchain definitions:
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER_ID GNU)
set(CMAKE_CXX_COMPILER_ID GNU)
# Some default GCC settings
# arm-none-eabi- must be part of path environment
set(TOOLCHAIN_PREFIX arm-none-eabi-)
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc)
set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER})
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++)
set(CMAKE_LINKER ${TOOLCHAIN_PREFIX}g++)
set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy)
set(CMAKE_SIZE ${TOOLCHAIN_PREFIX}size)
set(CMAKE_EXECUTABLE_SUFFIX_ASM ".elf")
set(CMAKE_EXECUTABLE_SUFFIX_C ".elf")
set(CMAKE_EXECUTABLE_SUFFIX_CXX ".elf")
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
3. Put all actual flags into gcc-arm-none-eabi_include.cmake
This file contains the original contents plus the modifications for --specs=nano.specs:
# MCU specific flags
set(TARGET_FLAGS "-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard --specs=nano.specs ")
#set(TARGET_FLAGS "-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard ")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${TARGET_FLAGS} ")
set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp -MMD -MP ")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fdata-sections -ffunction-sections ")
set(CMAKE_C_FLAGS_DEBUG "-Og -g3")
set(CMAKE_C_FLAGS_RELEASE "-O2 -g3")
set(CMAKE_CXX_FLAGS_DEBUG "-Og -g3")
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -g3")
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fno-rtti -fno-exceptions -fno-threadsafe-statics")
#set(CMAKE_EXE_LINKER_FLAGS "${TARGET_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -T \"${CMAKE_SOURCE_DIR}/MY_PROJECT.ld\"")
#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --specs=nano.specs")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Map=${CMAKE_PROJECT_NAME}.map -Wl,--gc-sections")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--print-memory-usage")
set(TOOLCHAIN_LINK_LIBRARIES "m")
With this setup, I'm able to configure and compile the project successfully.
Regards,
Peter
2026-01-09 4:06 AM
Hmm, but when you're manually modifying the gcc-arm-none-eabi.cmake file anyways, you can just put the fixed flags in there, no need to use an additional gcc-arm-none-eabi_include.cmake file.
The issue is that the gcc-arm-none-eabi.cmake file will be overwritten when re-running STM32CubeMX (not always though...?). A hack to solve this is to have a "fixer" script (e.g. in python) that is run as a "After Code Generation" step from STM32CubeMX, which automatically repairs the flags in gcc-arm-none-eabi.cmake as needed...
2026-01-09 4:29 AM
Fortunately, the CMake files are generated only once and are not overwritten when STM32CubeMX is re-run. However, even after modifying the flags (removing TARGET_FLAGS from CMAKE_EXE_LINKER_FLAGS), the parameters are still passed twice whenever I use “Clean Reconfigure All Projects” from the context menu. That’s the reason I moved the flags into the main CMakeLists.txt instead.
2026-01-09 4:42 AM
Here is a test project with the flags configured as you suggested.
When I select “Clean Reconfigure All Projects” from the context menu on the main CMakeLists.txt, the process ends with the following error:
[cmake] arm-none-eabi-gcc.exe: fatal error: C:/ST/STM32CubeCLT_1.17.0/GNU-tools-for-STM32/bin/../lib/gcc/arm-none-eabi/12.3.1/../../../../arm-none-eabi/lib/nano.specs: attempt to rename spec 'link' to already defined spec 'nano_link'
However, if I simply open the main CMakeLists.txt and save it—triggering a reconfigure—it completes without any issues.
Very strange!
2026-01-09 4:49 AM
Oh, I just stumbled about this as well... Deleting the "build" folder and saving the CMakeLists.txt also triggers this. I think when CMake is re-configuring instead of fresh-configuring, it skips the compiler check:
[cmake] -- Check for working C compiler: .../AppData/Local/stm32cube/bundles/gnu-tools-for-stm32/14.3.1+st.2/bin/arm-none-eabi-gcc.exe - skippedApparently this compiler check uses the CMAKE_C_FLAGS twice, strange!
2026-01-09 5:10 AM
Yeah, even on a fresh open of the project, the CMake configuration passes again—probably because the compiler check is skipped—and the project builds successfully. But “Clean Reconfigure All Projects” still fails consistently. I’ve been dealing with this issue for quite a while, but I’m not sure which tool is responsible, so I haven’t reported it yet.
Hopefully someone from ST can take a look and help narrow it down.
P.S.: I also tried forcing the compiler check to be skipped. The CMake configuration then passes, but the project still won’t build because the flags are passed twice.
The only workable solution known to me for now is to move the flags into the main CMakeLists.txt, as I described earlier (by splitting the CMake file).
2026-01-09 7:33 AM - edited 2026-01-09 7:44 AM
Ah, I think this is caused by some funny logic in CMake's own compiler/ABI detection process (not necessarily a bug). Normally this compilation step should always be "skipped", but it is skipped because another compilation step before runs successfully. But because of the misconfigured flags this first step fails.
Anyhow, the issue with the flags is that the toolchain file is supposed to set CMAKE_<LANG>_FLAGS_INIT , not CMAKE_C_FLAGS. Similarly the toolchain file should also use CMAKE_C_FLAGS_RELEASE_INIT instead of CMAKE_C_FLAGS_RELEASE, but that doesn't work, because if we don't override the latter, CMake will initialize it with "-O3 -DNDEBUG", and we don't want "-O3".
So try it with:
# MCU specific flags
set(TARGET_FLAGS "-mcpu=cortex-m0plus --specs=nano.specs")
set(CMAKE_C_FLAGS_INIT "${TARGET_FLAGS}")
set(CMAKE_ASM_FLAGS_INIT "${CMAKE_C_FLAGS_INIT} -x assembler-with-cpp -MMD -MP")
string(APPEND CMAKE_C_FLAGS_INIT " -Wall -fdata-sections -ffunction-sections")
set(CMAKE_ASM_FLAGS_DEBUG "-O0 -g3")
set(CMAKE_ASM_FLAGS_RELEASE "-Os -g3")
set(CMAKE_C_FLAGS_DEBUG "-O0 -g3")
set(CMAKE_C_FLAGS_RELEASE "-Os -g3")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3")
set(CMAKE_CXX_FLAGS_RELEASE "-Os -g3")
set(CMAKE_CXX_FLAGS_INIT "${CMAKE_C_FLAGS_INIT} -fno-rtti -fno-exceptions -fno-threadsafe-statics")
set(CMAKE_EXE_LINKER_FLAGS_INIT "-T \"${CMAKE_SOURCE_DIR}/STM32U083xx_FLASH.ld\"")
string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " -Wl,-Map=${CMAKE_PROJECT_NAME}.map -Wl,--gc-sections")
string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " -Wl,--print-memory-usage")
set(TOOLCHAIN_LINK_LIBRARIES "-lm")