From b1f16ac78948ef4b94faba1d0d3c59dc1b1ec291 Mon Sep 17 00:00:00 2001 From: Steven Cooreman Date: Thu, 23 Jan 2025 19:51:55 +0100 Subject: [PATCH 1/3] Implement and add newlib-nano as C standard library overlay This is meant to reflect what ARM GCC provides when compiling with --specs=nano.specs --- arm-software/embedded/CMakeLists.txt | 14 ++-- .../embedded/arm-multilib/CMakeLists.txt | 4 +- .../embedded/arm-runtimes/CMakeLists.txt | 66 ++++++++++++++----- .../embedded/cmake/generate_version_txt.cmake | 8 ++- arm-software/embedded/newlib-nano.cfg | 1 + 5 files changed, 67 insertions(+), 26 deletions(-) create mode 100644 arm-software/embedded/newlib-nano.cfg diff --git a/arm-software/embedded/CMakeLists.txt b/arm-software/embedded/CMakeLists.txt index 858e0d0733f2..881837c86a66 100644 --- a/arm-software/embedded/CMakeLists.txt +++ b/arm-software/embedded/CMakeLists.txt @@ -170,7 +170,7 @@ set(LLVM_TOOLCHAIN_C_LIBRARY "Which C library to use." ) set_property(CACHE LLVM_TOOLCHAIN_C_LIBRARY - PROPERTY STRINGS picolibc newlib llvmlibc) + PROPERTY STRINGS picolibc newlib newlib-nano llvmlibc) option( SHORT_BUILD_PATHS @@ -286,7 +286,7 @@ include(ProcessorCount) if(LLVM_TOOLCHAIN_C_LIBRARY STREQUAL picolibc) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/fetch_picolibc.cmake) endif() -if(LLVM_TOOLCHAIN_C_LIBRARY STREQUAL newlib) +if(LLVM_TOOLCHAIN_C_LIBRARY MATCHES "^newlib") include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/fetch_newlib.cmake) endif() @@ -309,18 +309,18 @@ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) endif() ################################################################################################## -if(LLVM_TOOLCHAIN_C_LIBRARY STREQUAL newlib) +if(LLVM_TOOLCHAIN_C_LIBRARY MATCHES "^newlib") install( FILES - ${CMAKE_CURRENT_SOURCE_DIR}/newlib.cfg + ${CMAKE_CURRENT_SOURCE_DIR}/${LLVM_TOOLCHAIN_C_LIBRARY}.cfg DESTINATION bin - COMPONENT llvm-toolchain-newlib-configs + COMPONENT llvm-toolchain-${LLVM_TOOLCHAIN_C_LIBRARY}-configs ) install( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/newlib-samples/ DESTINATION samples - COMPONENT llvm-toolchain-newlib-configs + COMPONENT llvm-toolchain-${LLVM_TOOLCHAIN_C_LIBRARY}-configs ) endif() @@ -731,7 +731,7 @@ if(LLVM_TOOLCHAIN_C_LIBRARY STREQUAL picolibc) ${picolibc_SOURCE_DIR}/COPYING.picolibc COPYING.picolibc ) endif() -if(LLVM_TOOLCHAIN_C_LIBRARY STREQUAL newlib) +if(LLVM_TOOLCHAIN_C_LIBRARY MATCHES "^newlib") list(APPEND third_party_license_files ${newlib_SOURCE_DIR}/COPYING.NEWLIB COPYING.NEWLIB ${newlib_SOURCE_DIR}/COPYING.LIBGLOSS COPYING.LIBGLOSS diff --git a/arm-software/embedded/arm-multilib/CMakeLists.txt b/arm-software/embedded/arm-multilib/CMakeLists.txt index 00d374b737d9..041ddc30d802 100644 --- a/arm-software/embedded/arm-multilib/CMakeLists.txt +++ b/arm-software/embedded/arm-multilib/CMakeLists.txt @@ -23,7 +23,7 @@ set(llvmproject_src_dir ${TOOLCHAIN_SOURCE_DIR}/../..) set(MULTILIB_JSON "" CACHE STRING "JSON file to load library definitions from.") set(ENABLE_VARIANTS "all" CACHE STRING "Semicolon separated list of variants to build, or \"all\". Must match entries in the json.") set(C_LIBRARY "picolibc" CACHE STRING "Which C library to use.") -set_property(CACHE C_LIBRARY PROPERTY STRINGS picolibc newlib llvmlibc) +set_property(CACHE C_LIBRARY PROPERTY STRINGS picolibc newlib newlib-nano llvmlibc) set(PROJECT_PREFIX "${CMAKE_BINARY_DIR}/lib-builds" CACHE STRING "Directory to build subprojects in.") option( NUMERICAL_BUILD_NAMES @@ -95,7 +95,7 @@ include(ExternalProject) if(C_LIBRARY STREQUAL picolibc) include(${TOOLCHAIN_SOURCE_DIR}/cmake/fetch_picolibc.cmake) list(APPEND passthrough_dirs "-DFETCHCONTENT_SOURCE_DIR_PICOLIBC=${FETCHCONTENT_SOURCE_DIR_PICOLIBC}") -elseif(C_LIBRARY STREQUAL newlib) +elseif(C_LIBRARY MATCHES "^newlib") include(${TOOLCHAIN_SOURCE_DIR}/cmake/fetch_newlib.cmake) list(APPEND passthrough_dirs "-DFETCHCONTENT_SOURCE_DIR_NEWLIB=${FETCHCONTENT_SOURCE_DIR_NEWLIB}") endif() diff --git a/arm-software/embedded/arm-runtimes/CMakeLists.txt b/arm-software/embedded/arm-runtimes/CMakeLists.txt index 2f1d0af49b42..e569529c10cc 100644 --- a/arm-software/embedded/arm-runtimes/CMakeLists.txt +++ b/arm-software/embedded/arm-runtimes/CMakeLists.txt @@ -21,7 +21,7 @@ set(llvmproject_src_dir ${TOOLCHAIN_SOURCE_DIR}/../..) # CMake arguments are loaded from the JSON file depending on which C # library is used, so this must be set before the JSON is processed. set(C_LIBRARY "picolibc" CACHE STRING "Which C library to use.") -set_property(CACHE C_LIBRARY PROPERTY STRINGS picolibc newlib llvmlibc) +set_property(CACHE C_LIBRARY PROPERTY STRINGS picolibc newlib newlib-nano llvmlibc) set(VARIANT_JSON "" CACHE STRING "JSON file to load args from.") if(VARIANT_JSON) @@ -37,7 +37,12 @@ if(VARIANT_JSON) set(${json_param}_def ${json_val}) endforeach() # Load arguments specific to the chosen library, overwriting any existing values. - string(JSON json_args GET ${variant_json_read} "args" ${C_LIBRARY}) + if(C_LIBRARY MATCHES "^newlib") + # Treat newlib variants as newlib for library compatibility + string(JSON json_args GET ${variant_json_read} "args" "newlib") + else() + string(JSON json_args GET ${variant_json_read} "args" ${C_LIBRARY}) + endif() string(JSON json_args_len LENGTH ${json_args}) math(EXPR json_args_len_dec "${json_args_len} - 1") foreach(json_idx RANGE ${json_args_len_dec}) @@ -85,7 +90,7 @@ set(PICOLIBC_BUILD_TYPE ${PICOLIBC_BUILD_TYPE_def} CACHE STRING "Picolibc config set_property(CACHE PICOLIBC_BUILD_TYPE PROPERTY STRINGS minsize release) set(ENABLE_CXX_LIBS ${ENABLE_CXX_LIBS_def} CACHE BOOL "Build CXX libs") -set(ENABLE_LIBC_TESTS ${ENABLE_LIBC_TESTS_def} CACHE BOOL "Enable libc tests (picolibc, newlib or llvm-libc).") +set(ENABLE_LIBC_TESTS ${ENABLE_LIBC_TESTS_def} CACHE BOOL "Enable libc tests (picolibc, newlib, newlib-nano or llvm-libc).") set(ENABLE_COMPILER_RT_TESTS ${ENABLE_COMPILER_RT_TESTS_def} CACHE BOOL "Enable compiler-rt tests.") set(ENABLE_LIBCXX_TESTS ${ENABLE_LIBCXX_TESTS_def} CACHE BOOL "Enable libcxx tests.") set(LLVM_BINARY_DIR "" CACHE PATH "Path to LLVM toolchain root to build libraries with") @@ -459,11 +464,44 @@ endif() # newlib ############################################################################### -if(C_LIBRARY STREQUAL newlib) +if(C_LIBRARY MATCHES "^newlib") if(ENABLE_LIBC_TESTS) message(FATAL_ERROR "Tests cannot yet be enabled using newlib libc.") endif() + if(C_LIBRARY STREQUAL newlib-nano) + # Taken from https://gitlab.arm.com/tooling/gnu-devtools-for-arm/-/blob/main/build-baremetal-toolchain.sh#L582 + set(newlib_flags + --disable-newlib-supplied-syscalls + --disable-nls + --enable-lite-exit + --disable-multilib + --enable-newlib-retargetable-locking + --enable-newlib-nano-malloc + --disable-newlib-unbuf-stream-opt + --enable-newlib-reent-small + --disable-newlib-fseek-optimization + --enable-newlib-nano-formatted-io + --disable-newlib-fvwrite-in-streamio + --disable-newlib-wide-orient + --enable-lite-exit + --enable-newlib-global-atexit) + set(newlib_optim_flags + "-g -Oz") + else() + set(newlib_flags + --enable-newlib-io-long-long + --enable-newlib-register-fini + --disable-newlib-supplied-syscalls + --enable-newlib-io-c99-formats + --disable-nls + --enable-lite-exit + --disable-multilib + --enable-newlib-retargetable-locking) + set(newlib_optim_flags + "-g -O2") + endif() + include(${TOOLCHAIN_SOURCE_DIR}/cmake/fetch_newlib.cmake) set(build_env "CC_FOR_TARGET=${LLVM_BINARY_DIR}/bin/clang -target ${target_triple} -ffreestanding" @@ -474,8 +512,8 @@ if(C_LIBRARY STREQUAL newlib) "RANLIB_FOR_TARGET=${LLVM_BINARY_DIR}/bin/llvm-ranlib" "READELF_FOR_TARGET=${LLVM_BINARY_DIR}/bin/llvm-readelf" "STRIP_FOR_TARGET=${LLVM_BINARY_DIR}/bin/llvm-strip" - "CFLAGS_FOR_TARGET=${flags} -Wno-error=implicit-function-declaration -D__USES_INITFINI__ -U_HAVE_INIT_FINI --sysroot ${TEMP_LIB_DIR}" - "CCASFLAGS=${flags} -Wno-error=implicit-function-declaration -D__USES_INITFINI__ -U_HAVE_INIT_FINI --sysroot ${TEMP_LIB_DIR}" + "CFLAGS_FOR_TARGET=${flags} ${newlib_optim_flags} -Wno-error=implicit-function-declaration -D__USES_INITFINI__ -U_HAVE_INIT_FINI --sysroot ${TEMP_LIB_DIR}" + "CCASFLAGS=${flags} ${newlib_optim_flags} -Wno-error=implicit-function-declaration -D__USES_INITFINI__ -U_HAVE_INIT_FINI --sysroot ${TEMP_LIB_DIR}" ) include(ProcessorCount) @@ -486,7 +524,7 @@ if(C_LIBRARY STREQUAL newlib) endif() ExternalProject_Add( - newlib + ${C_LIBRARY} STAMP_DIR ${PROJECT_PREFIX}/newlib/${VARIANT_BUILD_ID}/stamp BINARY_DIR ${PROJECT_PREFIX}/newlib/${VARIANT_BUILD_ID}/build DOWNLOAD_DIR ${PROJECT_PREFIX}/newlib/${VARIANT_BUILD_ID}/dl @@ -499,14 +537,7 @@ if(C_LIBRARY STREQUAL newlib) --target=${target_triple} --prefix "${TEMP_LIB_DIR}" --exec_prefix /tmpinstall - --enable-newlib-io-long-long - --enable-newlib-register-fini - --disable-newlib-supplied-syscalls - --enable-newlib-io-c99-formats - --disable-nls - --enable-lite-exit - --disable-multilib - --enable-newlib-retargetable-locking + ${newlib_flags} BUILD_COMMAND ${CMAKE_COMMAND} -E env ${build_env} make ${make_flags} @@ -690,7 +721,7 @@ if(ENABLE_CXX_LIBS) -DLLVM_LIT_ARGS=${cxxlibs_lit_args} ) endif() - elseif(C_LIBRARY STREQUAL newlib) + elseif(C_LIBRARY MATCHES "^newlib") set(cxxlibs_extra_cmake_options -DLIBCXXABI_ENABLE_THREADS=OFF -DLIBCXX_ENABLE_MONOTONIC_CLOCK=OFF @@ -703,6 +734,9 @@ if(ENABLE_CXX_LIBS) -DLIBCXX_ENABLE_EXCEPTIONS=${ENABLE_EXCEPTIONS} -DLIBCXX_ENABLE_RTTI=${ENABLE_RTTI} ) + if(C_LIBRARY STREQUAL newlib-nano) + set(lib_compile_flags "${lib_compile_flags} -g -Oz") + endif() endif() ExternalProject_Add( diff --git a/arm-software/embedded/cmake/generate_version_txt.cmake b/arm-software/embedded/cmake/generate_version_txt.cmake index a7fa157880aa..0b6cde61452e 100644 --- a/arm-software/embedded/cmake/generate_version_txt.cmake +++ b/arm-software/embedded/cmake/generate_version_txt.cmake @@ -18,8 +18,14 @@ if(NOT ${armtoolchain_COMMIT} MATCHES "^[a-f0-9]+$") endif() if(NOT (LLVM_TOOLCHAIN_C_LIBRARY STREQUAL llvmlibc)) # libc in a separate repo? + if(LLVM_TOOLCHAIN_C_LIBRARY MATCHES "^newlib") + set(base_library newlib) + else() + set(base_library $(LLVM_TOOLCHAIN_C_LIBRARY)) + endif() + execute_process( - COMMAND git -C ${${LLVM_TOOLCHAIN_C_LIBRARY}_SOURCE_DIR} rev-parse HEAD + COMMAND git -C ${${base_library}_SOURCE_DIR} rev-parse HEAD OUTPUT_VARIABLE ${LLVM_TOOLCHAIN_C_LIBRARY}_COMMIT OUTPUT_STRIP_TRAILING_WHITESPACE COMMAND_ERROR_IS_FATAL ANY diff --git a/arm-software/embedded/newlib-nano.cfg b/arm-software/embedded/newlib-nano.cfg new file mode 100644 index 000000000000..e0b7de08c444 --- /dev/null +++ b/arm-software/embedded/newlib-nano.cfg @@ -0,0 +1 @@ +--sysroot /../lib/clang-runtimes/newlib-nano From 82e7327a75aeadbd0ce295ecd3e11f3e43711a36 Mon Sep 17 00:00:00 2001 From: Steven Cooreman Date: Thu, 23 Jan 2025 20:28:39 +0100 Subject: [PATCH 2/3] Update documentation in relation to newlib-nano --- arm-software/embedded/README.md | 4 ++-- arm-software/embedded/docs/migrating.md | 4 ++-- arm-software/embedded/docs/newlib.md | 8 +++++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/arm-software/embedded/README.md b/arm-software/embedded/README.md index 52b187e87958..f5b08051c164 100644 --- a/arm-software/embedded/README.md +++ b/arm-software/embedded/README.md @@ -7,7 +7,7 @@ bare-metal LLVM based toolchain targeting Arm based on: * libc++abi * libc++ * compiler-rt -* picolibc, or optionally newlib or LLVM's libc +* picolibc, or optionally newlib(-nano) or LLVM's libc ## Goal @@ -191,7 +191,7 @@ relying on the Arm GNU Toolchain. > *Note:* `picolibc` provides excellent > [support for Arm GNU Toolchain](https://github.com/picolibc/picolibc/blob/main/doc/using.md), > so projects that require using both Arm GNU Toolchain and Arm Toolchain for Embedded -> can choose either `picolibc` or `newlib`. +> can choose either `picolibc` or `newlib`/`newlib-nano`. ## Building from source diff --git a/arm-software/embedded/docs/migrating.md b/arm-software/embedded/docs/migrating.md index dc19886ee96e..e4b32350096d 100644 --- a/arm-software/embedded/docs/migrating.md +++ b/arm-software/embedded/docs/migrating.md @@ -37,7 +37,7 @@ Armv8-M or later architecture, including the |Binutils​|`objdump`, `readelf`, ...|`llvm-objdump`, `llvm-readelf`, ...| |Compiler runtime library​|`libgcc​`|`compiler-rt`​| |Unwinder​|`libgcc`​|`libunwind`​| -|C standard library​|`newlib`, `newlib-nano`|`picolibc`|​ +|C standard library​|`newlib`, `newlib-nano`|`picolibc` (or `newlib`/`newlib-nano` as overlay)|​ |C++ ABI library​|`libsupc++.a`|`libc++abi`​|​ |C++ standard library​|`libstdc++​`|`libc++`​| @@ -90,7 +90,7 @@ however uses different command line options to control selection of semihosting. |--------|-----------|------------| |No semihosting|`--specs=nosys.specs`| |Semihosting|`--specs=rdimon.specs`|`-nostartfiles -lcrt0-semihost -lsemihost`| -|Newlib-nano|`--specs=nano.specs`|Not available: `picolibc` is an equivalent of `newlib-nano`. +|Newlib-nano|`--specs=nano.specs`|`--config=newlib-nano.cfg` (with [`newlib-nano` overlay](./newlib.md) installed)| ## Linker diff --git a/arm-software/embedded/docs/newlib.md b/arm-software/embedded/docs/newlib.md index 7e0a0581bdbd..07484a458857 100644 --- a/arm-software/embedded/docs/newlib.md +++ b/arm-software/embedded/docs/newlib.md @@ -46,4 +46,10 @@ overlay package. Note that the `-DLLVM_TOOLCHAIN_LIBRARY_OVERLAY_INSTALL=on` option only generates the `newlib` package, but does not install it as part -of the `install` CMake target. \ No newline at end of file +of the `install` CMake target. + +## About `newlib-nano` +`newlib-nano` is provided as a separate package, and is meant to be equal +to using GCC with `--specs=nano.specs`. In order to use the nano version +of newlib, where the documentation in this file refers to `newlib`, replace +it with `newlib-nano`. From c66cd73b972084feb42e3d6a5ee25397beafa38b Mon Sep 17 00:00:00 2001 From: Steven Cooreman Date: Sun, 26 Jan 2025 16:51:20 +0100 Subject: [PATCH 3/3] Ensure newlib gets compiled with the correct target flags newlib was not building correctly for ARMv7 and ARMv8 targets due to not being passed the -march, -mfpu and -mfloat-abi flags which are required for the compiler to generate correct assembly (it was outputing incorrect assembly without triggering any warnings) --- arm-software/embedded/arm-runtimes/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arm-software/embedded/arm-runtimes/CMakeLists.txt b/arm-software/embedded/arm-runtimes/CMakeLists.txt index e569529c10cc..2c78ab509148 100644 --- a/arm-software/embedded/arm-runtimes/CMakeLists.txt +++ b/arm-software/embedded/arm-runtimes/CMakeLists.txt @@ -512,8 +512,8 @@ if(C_LIBRARY MATCHES "^newlib") "RANLIB_FOR_TARGET=${LLVM_BINARY_DIR}/bin/llvm-ranlib" "READELF_FOR_TARGET=${LLVM_BINARY_DIR}/bin/llvm-readelf" "STRIP_FOR_TARGET=${LLVM_BINARY_DIR}/bin/llvm-strip" - "CFLAGS_FOR_TARGET=${flags} ${newlib_optim_flags} -Wno-error=implicit-function-declaration -D__USES_INITFINI__ -U_HAVE_INIT_FINI --sysroot ${TEMP_LIB_DIR}" - "CCASFLAGS=${flags} ${newlib_optim_flags} -Wno-error=implicit-function-declaration -D__USES_INITFINI__ -U_HAVE_INIT_FINI --sysroot ${TEMP_LIB_DIR}" + "CFLAGS_FOR_TARGET=${flags} ${newlib_optim_flags} ${lib_compile_flags} -Wno-error=implicit-function-declaration -D__USES_INITFINI__ -U_HAVE_INIT_FINI" + "CCASFLAGS=${flags} ${newlib_optim_flags} ${lib_compile_flags} -Wno-error=implicit-function-declaration -D__USES_INITFINI__ -U_HAVE_INIT_FINI" ) include(ProcessorCount)