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
(
|
Hybrid Toolchain |
Full LLVM Toolchain |
|---|---|---|---|
|
C, C++ compiler |
|
|
|
|
Assembler |
|
|
|
|
Linker |
|
|
|
|
Binutils |
|
|
|
|
Compiler runtime library |
|
|
|
|
Unwinder |
|
|
|
|
C standard library |
|
|
|
|
C++ ABI library |
|
|
|
|
C++ standard library |
|
|
|
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:
Linker Script implementation notes and policy in the LLD documentation.
The LLD and GNU linker incompatibilities blog post.
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 |
|
|
|
Minor |
|
|
|
Patch level |
|
|
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
.Nand.Wsuffixes for Thumb instructions.The use of
Ssuffix 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
|
Component |
Link |
Version |
|---|---|---|
|
LLVM |
21.1.1 |
|
|
Picolibc |
1.8.10 |
|
|
Newlib |
4.5.0 |
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