STMicroelectronics Arm Clang Toolchain for STM32

ST Arm Clang is a new C/C++ toolchain offering for STM32 development built on the modern LLVM compiler infrastructure and the Arm Toolchain for Embedded toolchain from Arm.

This new LLVM-based toolchain provides developers with a more efficient, flexible, and future-proof development environment while maintaining compatibility with existing projects.

ST Arm Clang is designed as a drop-in replacement for the GNU Tools for STM32, minimizing disruption for developers transitioning to it. However, some minor incompatibilities or divergent features may exist due to differences in the underlying infrastructure. To ease this transition, two flavors of the toolchain are provided:

  • Hybrid toolchain : only the C/C++ LLVM Clang compiler and integrated assembler are used to compile the code into object files (local applications, HAL, etc.). The final binary is built using the tools and libraries from the existing GNU Tools for STM32 (GNU Binutils linker, C/C++ libraries, and runtime). This use case is ideal for developers looking to test or leverage Clang’s compilation benefits while retaining the familiar GNU linking and runtime environment. Both toolchains (Clang and GCC) should be installed on your system, and link-time optimization (LTO) is not available in this mode.

  • Full LLVM toolchain : this version offers the complete long-term LLVM-based solution (Clang compiler, LLVM linker and runtime) with up-to-date libraries, such as Picolibc or LLVM libc++. It benefits from the combined effort from the LLVM community, Arm, and ST research and development teams to reach optimal support, performance, and code-size on STM32 devices. The toolchain offers two distinct C library implementations, allowing developers to choose based on their project priorities or device resources: Newlib for performance and Picolibc for code size.

Toolchains components overview

Component

GNU Tools for STM32 ( arm-none-eabi-)

Hybrid Toolchain

Full LLVM Toolchain

C, C++ compiler

gcc, g++

starm-clang, starm-clang++

starm-clang, starm-clang++

Assembler

as

starm-clang (integrated assembler)

starm-clang (integrated assembler)

Linker

ld

ld

starm-lld

Binutils

objdump, readelf, …

starm-objdump, starm-readelf, …

starm-objdump, starm-readelf, …

Compiler runtime library

libgcc

libgcc

libclang_rt

Unwinder

libgcc

libgcc

libunwind

C standard library

newlib, newlib-nano

newlib, newlib-nano

newlib, picolibc

C++ ABI library

libsupc++

libsupc++

libc++abi

C++ standard library

libstdc++

libstdc++

libc++

Hybrid toolchain

The Hybrid toolchain mode leverages the Clang compiler and integrated assembler for compiling source code, while relying on the GNU Tools for STM32 for linking and runtime libraries. This approach allows developers to benefit from Clang’s modern compilation capabilities without fully migrating their build environment. It is particularly useful for incremental migration or testing purposes.

In this mode, the toolchain requires both the ST Arm Clang and GNU toolchains to be installed on the system. Link-time optimization (LTO) is not supported due to the mixed toolchain components. The hybrid flavor maintains compatibility with existing GNU linker scripts, libraries, and runtime behaviors, minimizing integration effort.

Integration in STM32CubeMX CMake projects:

set(STARM_TOOLCHAIN_CONFIG "STARM_HYBRID")

Command-line flags:

--gcc-toolchain=<PATH_TO_GCC_TOOLCHAIN_ROOT_DIR> --multi-lib-config=<PATH_TO_STARM_CLANG_ROOT_DIR>/multilib.gnu_tools_for_stm32.yaml

C Standard Libraries

GNU tools for STM32 toolchain provides two versions of the C standard library Newlib (used by default) and Newlib nano (selected with starm-clang GCC spec files emulation: --gcc-specs=nano.specs).

Full LLVM toolchain

The full LLVM toolchain is a complete, standalone solution built entirely on the LLVM infrastructure, including the Clang compiler ( starm-clang), LLVM linker ( starm-lld), and modern runtime libraries such as Picolibc and libc++ . This flavor is designed for long-term use and continuous improvement, providing enhanced performance, and reduced code size.

It supports advanced features like link-time optimization (LTO) and offers two C standard library options — Newlib for performance-oriented applications and Picolibc for minimal code size. The full LLVM toolchain enables developers to fully leverage the benefits of the LLVM toolchain on STM32 devices, with ongoing support and optimizations contributed by ST, Arm, and the LLVM community.

Linker

starm-lld is designed as a drop in replacement for GNU ld, however there are some known differences to take into account, see:

C Standard Libraries

Newlib

Newlib is a complete C library implementation specifically designed for embedded systems. This full Newlib variant supports nearly all standard C library features and is optimized to deliver high performance in resource-constrained environments. For detailed information, refer to the Newlib Documentation

Integration in STM32CubeMX CMake projects:

To select Newlib in your STM32CubeMX-generated CMake project, set:

set(STARM_TOOLCHAIN_CONFIG "STARM_NEWLIB")

Command-line flags:

When building from the command line, use the configuration flag:

--config=newlib.cfg

Picolibc

Picolibc is a modern complete C library implementation targeting the embedded systems with a focus on minimal code size, making it suitable for applications where footprint reduction is critical. More details can be found in Picolibc Documentation

Integration in STM32CubeMX CMake projects:

To select Picolibc in your STM32CubeMX-generated CMake project, set:

set(STARM_TOOLCHAIN_CONFIG "STARM_PICOLIBC")

Command-line flags:

Picolibc is the default mode and requires no additional command-line flag.

C++ support

C++ is partially supported with the use of libc++ and libc++abi from LLVM. Features that are not supported include:

  • Multithreading

ST Arm Clang uses the unstable libc++ ABI version. This ABI benefits from all the latest libc++ improvements and bug fixes, but may result in link errors when linking against objects compiled against older versions of the ABI. For more information, see https://libcxx.llvm.org/DesignDocs/ABIVersioning.html .

Supported architectures

  • Armv6-M (Cortex-M0/M0+/M1)

  • Armv7-M (Cortex-M3)

  • Armv7E-M (Cortex-M4/M7)

  • Armv8-M Mainline and Baseline (Cortex-M23/M33/M35P)

  • Armv8.1-M Mainline and Baseline (Cortex-M52/M55/M85)

See STM32 MCU products list for CPU/product correspondence.

Migrating from GNU Tools for STM32

Toolchain identification

ST Arm Clang is identified by the __starm__ macro.

Toolchain version macros:

Version number

GNU macro

LLVM macro

Major

__GNUC__

__clang_major__

Minor

__GNUC_MINOR__

__clang_minor__

Patch level

__GNUC_PATCHLEVEL__

__clang_patchlevel__

Note that starm-clang defines GNU macros for compatibility too: __GNUC__ equal to 4, __GNUC_MINOR__ equal to 2, and __GNUC_PATCHLEVEL__ equal to 1.

Architecture identification

Both compilers define the same macros to identify Arm® architectures, except for Armv8.1-M Mainline: GCC defines the __ARM_ARCH_8M_MAIN__ macro, whereas Clang defines __ARM_ARCH_8_1M_MAIN__.

C and C++ language extensions

ST Arm Clang supports the majority of GNU C and C++ extensions as described in Clang Language Extensions .

The following feature checking macros can be used to test whether a particular feature is supported:

Assembly language

starm-clang should be used instead of arm-none-eabi-as to compile assembly ( .s and .S) files.

There are minor differences in the assembly syntax between GNU and LLVM compilers. However, most of the time, it is possible to write code that both accept.

For example, GNU and LLVM compilers differ in:

  • The use of .N and .W suffixes for Thumb instructions.

  • The use of S suffix for flag setting instructions.

Optimization flags

For better code size optimization, consider using -Oz or --config=Osize.cfg instead of -Os.

Note: In previous ST Arm Clang releases, Osize.cfg was named Omin.cfg.

Focus on C standard formatted I/O

Functions of the printf and scanf families can account for a significant portion of an embedded application’s code size. This is primarily due to the expensive logic required to support the formatting of long long, float, and double types, even though these formats are not always used.

To reduce the cost associated with these functions, some configurations of ST Arm Clang provide mechanisms to select reduced versions of printf and scanf that only support formats used in your application.

Hybrid toolchain

Newlib

This library provides a single implementation of the printf and scanf functions. It supports all formats but the code size of these functions is maximal.

Newlib nano

This library provides two implementations of the printf and scanf functions: (1) the default one only supports formatting of characters, strings, pointers, and integer types up to 32 bits (2) the other one adds support for floating-point types. Specify -u _printf_float or -u _scanf_float linker flags to select the second version. Note that neither version supports the formatting of 64-bit wide integers, contrary to the single implementation in Newlib .

Full LLVM toolchain

Newlib

This library provides a single implementation of the printf and scanf functions. It supports all formats but the code size of these functions is maximal. Note that this library is compiled for optimal execution speed rather than lowest code size.

Picolibc

This library offers five implementations of the printf and scanf functions. Read the Picolibc documentation for details on the formats supported by each version. If the format strings can be analyzed at compile time, the ST Arm Clang toolchain will automatically link the minimal version of printf and scanf functions that supports all the formats used by your application. This mechanism can be disabled using --no-auto-printf-variant-selection or --no-auto-scanf-variant-selection linker flags, allowing the selection of a specific version.

NOTE: When optimizations are disabled ( -O0), the --gc-sections linker flag is needed to remove unused printf and scanf versions from the final binary. This flag is already set in CMake projects generated by STM32CubeMX.

Thread local storage

ST Arm Clang with Picolibc supports thread local storage (TLS).

You can declare a thread-local variable in your code by using the __thread specifier or the _Thread_local keyword (or thread_local in C++). Such variables are manipulated like any regular (non-thread-local) variable in the source code. The toolchain automatically insert the necessary code to ensure each thread accesses its own copy. Picolibc itself uses TLS for thread-specific library data, such as errno , I/O buffers, and other internal states.

For STM32Cube CMake projects generated for ST Arm Clang, all necessary TLS setup for the first thread is included by default. The linker script and startup code are configured according to the Thread Local Storage in Picolibc documentation , with one exception: instead of calling _set_tls(__tls_base) directly in the startup code to set the TLS pointer for the first thread, a .preinit_array section references _initial_set_tls(), which serves the same purpose. This section and the function are only linked in the application if TLS data is used, in which case the function is automatically called by __libc_init_array() in the startup code.

As a result, TLS works out of the box for single-threaded STM32Cube CMake projects. For multi-threaded projects, refer to the Creating more TLS blocks section of the aforementioned Picolibc documentation to initialize TLS for subsequent threads.

Note: TLS for the first thread is only guaranteed to be initialized after __libc_init_array() has executed all functions registered in the .preinit_array section. Therefore, it is safe to use TLS data after __libc_init_array(), or in functions registered in the .init_array section.

Components

ST Arm Clang toolchain relies on the following upstream components

Host platforms

ST Arm Clang toolchain is built and tested on:

  • RHEL 8 x86_64

  • MacOS 15.5 Apple Silicon and X86_64

  • Windows 10 x86_64

External documentation resources