Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
28aabfa
enhanced sysroot handling, sysroot did not took selected clib into ac…
rgrr Oct 15, 2025
9d82a92
Merge remote-tracking branch 'origin/develop' into clang-corrections
rgrr Oct 15, 2025
6feb9b9
make it compile with clang21.1.1: cmake changes for newlib/llvm_libc
rgrr Oct 15, 2025
571d2ed
make it compile with clang21.1.1: llvm_libc_interface changes
rgrr Oct 15, 2025
4a775ee
finetuning: now it is working also with picolibc
rgrr Oct 15, 2025
9dd3ce5
correct bazel config
rgrr Oct 15, 2025
bf670a8
pico needs also some support
rgrr Oct 15, 2025
d13a84f
make newlib the default
rgrr Oct 15, 2025
f7255e7
code review I
rgrr Oct 15, 2025
465dff2
use the same runtime_init() as for newlib -> picolibc now working for…
rgrr Oct 16, 2025
fe941af
catch the case that PICO_CLIB is not set
rgrr Oct 17, 2025
9624ce6
now using multilib concept which makes everything much cleaner and cl…
rgrr Oct 30, 2025
33fbf86
Merge remote-tracking branch 'origin/develop' into clang-corrections
rgrr Feb 2, 2026
d980230
Merge remote-tracking branch 'origin/develop' into clang-corrections
rgrr Feb 8, 2026
b32df07
must use ld for clang build. lld optimizes at least for rp2040 too m…
rgrr Feb 11, 2026
8aac9d5
Merge remote-tracking branch 'origin/develop' into clang-corrections
rgrr Mar 9, 2026
d02f9f8
Merge remote-tracking branch 'origin/develop' into clang-corrections
rgrr Apr 6, 2026
79dcbc9
Merge branch 'develop' into clang-corrections
rgrr May 11, 2026
152dc85
use lld for clang (again)
rgrr May 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions cmake/preload/toolchains/pico_arm_cortex_m0plus_clang.cmake
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
set(CMAKE_SYSTEM_PROCESSOR cortex-m0plus)

# these are all the directories under LLVM embedded toolchain for ARM (newlib or pibolibc) and under llvm_libc
set(PICO_CLANG_RUNTIMES armv6m_soft_nofp armv6m-unknown-none-eabi)

set(PICO_COMMON_LANG_FLAGS "--target=armv6m-none-eabi -mfloat-abi=soft -march=armv6m")
set(PICO_COMMON_LANG_FLAGS "--target=arm-none-eabi -mcpu=cortex-m0plus -mfloat-abi=softfp")

include(${CMAKE_CURRENT_LIST_DIR}/util/pico_arm_clang_common.cmake)
7 changes: 1 addition & 6 deletions cmake/preload/toolchains/pico_arm_cortex_m33_clang.cmake
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
set(CMAKE_SYSTEM_PROCESSOR cortex-m33)

set(PICO_COMMON_LANG_FLAGS "-mcpu=cortex-m33 --target=armv8m.main-none-eabi -march=armv8m.main+fp+dsp")
set(PICO_COMMON_LANG_FLAGS "--target=arm-none-eabi -mfloat-abi=hard -march=armv8m.main+fp+dsp")

set(PICO_DISASM_OBJDUMP_ARGS --mcpu=cortex-m33 --arch=armv8m.main+fp+dsp)

if (PICO_HARD_FLOAT_ABI)
set(PICO_COMMON_LANG_FLAGS "${PICO_COMMON_LANG_FLAGS} -mfloat-abi=hard")
# todo - doesn't seem to be a hard_fp variant for google atm?
# these are all the directories under LLVM embedded toolchain for ARM (newlib or pibolibc)
set(PICO_CLANG_RUNTIMES armv8m.main_hard_fp armv8m.main_hard_fp_unaligned)
else()
set(PICO_COMMON_LANG_FLAGS "${PICO_COMMON_LANG_FLAGS} -mfloat-abi=softfp")
# these are all the directories under LLVM embedded toolchain for ARM (newlib or pibolibc) and under llvm_libc
set(PICO_CLANG_RUNTIMES armv8m.main_soft_nofp armv8m.main_soft_nofp_unaligned armv8m.main-unknown-none-eabi)
endif()

include(${CMAKE_CURRENT_LIST_DIR}/util/pico_arm_clang_common.cmake)
78 changes: 37 additions & 41 deletions cmake/preload/toolchains/util/pico_arm_clang_common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pico_find_compiler(PICO_OBJCOPY llvm-objcopy)
pico_find_compiler(PICO_OBJDUMP llvm-objdump)

# Specify the cross compiler.
set(CMAKE_C_COMPILER ${PICO_COMPILER_CC} CACHE FILEPATH "C compiler")
set(CMAKE_C_COMPILER ${PICO_COMPILER_CC} CACHE FILEPATH "C compiler")
set(CMAKE_CXX_COMPILER ${PICO_COMPILER_CXX} CACHE FILEPATH "C++ compiler")
set(CMAKE_ASM_COMPILER ${PICO_COMPILER_ASM} CACHE FILEPATH "ASM compiler")

Expand Down Expand Up @@ -43,57 +43,53 @@ endforeach()

list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES PICO_CLIB)

foreach(PICO_CLANG_RUNTIME IN LISTS PICO_CLANG_RUNTIMES)
# LLVM embedded-toolchain for ARM style
find_path(PICO_COMPILER_SYSROOT NAMES include/stdio.h
HINTS
${PICO_COMPILER_DIR}/../lib/clang-runtimes/arm-none-eabi/${PICO_CLANG_RUNTIME}
${PICO_COMPILER_DIR}/../lib/clang-runtimes/${PICO_CLANG_RUNTIME}
)

if (PICO_COMPILER_SYSROOT)
if (NOT PICO_CLIB)
# this is a bit of a hack; to try to autodetect the C library used:
# `picolibc.h` seems to exist on the newer versions of LLVM embedded toolchain for ARM using picolibc whereas
# `newlib.h` appears in all versions, so isn't very useful
if (EXISTS "${PICO_COMPILER_SYSROOT}/include/picolibc.h")
message("Setting default C library to picolibc as LLVM appears to be using it")
set(PICO_CLIB "picolibc" CACHE INTERNAL "")
endif()
endif()
break()
set(_CLANG_RUNTIMES_DIR "${PICO_COMPILER_DIR}/../lib/clang-runtimes")
cmake_path(NORMAL_PATH _CLANG_RUNTIMES_DIR)
set(PICO_CLIB_ROOT "${_CLANG_RUNTIMES_DIR}")

if(NOT PICO_CLIB OR PICO_CLIB STREQUAL "")
# newlib is primary if no clib specified
if(EXISTS "${_CLANG_RUNTIMES_DIR}/newlib")
set(PICO_CLIB "newlib")
else()
set(PICO_CLIB "picolibc")
endif()
# llvm_libc style
find_path(PICO_COMPILER_SYSROOT NAMES stdio.h
HINTS
${PICO_COMPILER_DIR}/../include/${PICO_CLANG_RUNTIME}
)
if (PICO_COMPILER_SYSROOT)
if (NOT PICO_CLIB)
message("Setting default C library to llvm_libc as LLVM appears to be using it")
set(PICO_CLIB "llvm_libc" CACHE INTERNAL "")
endif()
break()
set(CACHE{PICO_CLIB} TYPE STRING FORCE VALUE ${PICO_CLIB})
endif()

if(PICO_CLIB STREQUAL "newlib")
if(EXISTS "${_CLANG_RUNTIMES_DIR}/newlib")
set(PICO_CLIB_ROOT "${_CLANG_RUNTIMES_DIR}/newlib")
endif()
endforeach()
elseif(PICO_CLIB STREQUAL "llvm_libc")
if(EXISTS "${_CLANG_RUNTIMES_DIR}/llvmlibc")
set(PICO_CLIB_ROOT "${_CLANG_RUNTIMES_DIR}/llvmlibc")
endif()
elseif(PICO_CLIB STREQUAL "picolibc")
if(EXISTS "${_CLANG_RUNTIMES_DIR}/picolibc")
set(PICO_CLIB_ROOT "${_CLANG_RUNTIMES_DIR}/picolibc")
endif()
else()
message(FATAL_ERROR "PICO_CLIB must be one of newlib, picolib, llvm_libc or empty (but is '${PICO_CLIB}')")
endif()

# moving this here as a reminder from pico_standard_link; it was commented out theee, but if ever needed,
# it belongs here as part of LINKER_FLAGS_INIT
#target_link_options(pico_standard_link INTERFACE "LINKER:-fuse-ld=lld")
set(PICO_COMMON_LANG_FLAGS "${PICO_COMMON_LANG_FLAGS} --sysroot ${PICO_CLIB_ROOT}")

if (PICO_CLIB STREQUAL "llvm_libc")
# TODO: Remove -nostdlib++ once we include libc++ in the toolchain.
# TODO: Move -nostartfiles to the appropriate library.
foreach(TYPE IN ITEMS EXE SHARED MODULE)
# note --unwindlib=none is only needed on recent compiler/lib versions, however just produces a
# warning on earlier versions, so not attempting a version check for now
set(CMAKE_${TYPE}_LINKER_FLAGS_INIT "-nostdlib++ -nostartfiles --unwindlib=none")
endforeach()
else()
if (NOT PICO_COMPILER_SYSROOT)
message(FATAL_ERROR "Could not find an llvm runtime for '${PICO_CLANG_RUNTIME}'")
endif()
endif()

set(PICO_COMMON_LANG_FLAGS "${PICO_COMMON_LANG_FLAGS} --sysroot ${PICO_COMPILER_SYSROOT}")
# at least rp2040 does not work with lld. For rp2350 it seems to work with lld, but not really sure
set(CMAKE_EXE_LINKER_FLAGS_INIT "${CMAKE_EXE_LINKER_FLAGS_INIT} -fuse-ld=lld -Wl,-z,noexecstack")
if(CMAKE_INTERPROCEDURAL_OPTIMIZATION)
message(FATAL_ERROR "IPO is not supported with the current configuration of the Pico SDK")
endif()

message(STATUS "Taking '${PICO_CLIB}' from '${PICO_CLIB_ROOT}'")

include(${CMAKE_CURRENT_LIST_DIR}/set_flags.cmake)
12 changes: 9 additions & 3 deletions src/rp2_common/pico_clib_interface/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,16 @@ cc_library(
target_compatible_with = compatible_with_rp2(),
)

# For now, picolibc doesn't need to provide any headers.
alias(
cc_library(
name = "picolibc_interface",
actual = "//bazel:empty_cc_lib",
hdrs = [
"include/picolibc/sys/cdefs.h",
],
includes = ["include/picolibc"],
# It's hard to properly constrain compatibility since `auto` may select this,
# so just tag as manual.
tags = ["manual"],
target_compatible_with = compatible_with_rp2(),
)

cc_library(
Expand Down
4 changes: 4 additions & 0 deletions src/rp2_common/pico_clib_interface/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ if (NOT TARGET pico_clib_interface)
# PICO_STDIO_SHORT_CIRCUIT_CLIB_FUNCS=0
#)

target_include_directories(pico_picolibc_interface SYSTEM INTERFACE
${CMAKE_CURRENT_LIST_DIR}/include/picolibc
)

# ---- llvm_libc ----
pico_add_library(pico_llvm_libc_interface)

Expand Down
4 changes: 2 additions & 2 deletions src/rp2_common/pico_clib_interface/include/llvm_libc/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@

#include <__llvm-libc-common.h>

#include <llvm-libc-types/struct_timespec.h>
#include <llvm-libc-types/struct_tm.h>
#include <llvm-libc-types/time_t.h>

__BEGIN_C_DECLS

struct tm* localtime_r(const time_t* timer, struct tm* buf) __NOEXCEPT;
time_t mktime(struct tm *);

__END_C_DECLS

#include_next <time.h>

#endif // _PICO_LLVM_LIBC_TIME_H
32 changes: 32 additions & 0 deletions src/rp2_common/pico_clib_interface/include/picolibc/sys/cdefs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#ifndef __PICO_PICOLIBC_SYS_CDEFS_H
#define __PICO_PICOLIBC_SYS_CDEFS_H

#if defined(__STDC__) || defined(__cplusplus)

#define __CONCAT1(x,y) x ## y
#define __CONCAT(x,y) __CONCAT1(x,y)
#define __STRING(x) #x
#define __XSTRING(x) __STRING(x)

#endif

#define __unused __attribute__((__unused__))
#define __used __attribute__((__used__))
#define __packed __attribute__((__packed__))
#define __aligned(x) __attribute__((__aligned__(x)))

#define __always_inline __inline__ __attribute__((__always_inline__))
#define __noinline __attribute__((__noinline__))

#define __printflike(fmtarg, firstvararg) \
__attribute__((__format__ (__printf__, fmtarg, firstvararg)))

#include_next <sys/cdefs.h>

#endif
6 changes: 3 additions & 3 deletions src/rp2_common/pico_clib_interface/llvm_libc_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <sys/time.h>
#include <time.h>

#include <llvm-libc-types/ssize_t.h>

#include "include/llvm_libc/time.h"
#include "include/llvm_libc/sys/time.h"

#include "pico/runtime_init.h"
#include "pico/stdio.h"
#include "pico/time.h"
Expand Down
18 changes: 14 additions & 4 deletions src/rp2_common/pico_clib_interface/picolibc_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,19 @@ void runtime_init(void) {
runtime_init_per_core_install_stack_guard(&__StackBottom);
#endif

// piolibc __libc_init_array does __preint_array and __init_array
extern void __libc_init_array(void);
__libc_init_array();
// todo maybe we want to do this in the future, but it does stuff like register_tm_clones
// which we didn't do in previous SDKs
//extern void __libc_init_array(void);
//__libc_init_array();

// ... so instead just do the __preinit_array
runtime_run_initializers();
// ... and the __init_array
extern void (*__init_array_start)(void);
extern void (*__init_array_end)(void);
for (void (**p)(void) = &__init_array_start; p < &__init_array_end; ++p) {
(*p)();
}
}

#if !PICO_RUNTIME_NO_INIT_PER_CORE_TLS_SETUP
Expand All @@ -157,4 +167,4 @@ PICO_RUNTIME_INIT_FUNC_PER_CORE(runtime_init_pre_core_tls_setup, PICO_RUNTIME_IN
// "ldr r0, =__tls_base\n"
// "bx lr\n"
// );
//}
//}