diff mbox series

[v4] tclibc-picolibc: Adds a new TCLIBC variant to build with picolibc as C library

Message ID 20240618181226.2693197-1-alejandro@enedino.org
State Under Review
Headers show
Series [v4] tclibc-picolibc: Adds a new TCLIBC variant to build with picolibc as C library | expand

Commit Message

Alejandro Enedino Hernandez Samaniego June 18, 2024, 6:12 p.m. UTC
Enables usage of TCLIBC=picolibc extending OE functionality to build and use
picolibc based toolchains to build baremetal applications.

Picolibc is a set of standard C libraries, both libc and libm, designed for
smaller embedded systems with limited ROM and RAM. Picolibc includes code
from Newlib and AVR Libc, but adresses some of newlibs concerns, it retains
newlibs directory structure, math, string and locale implementations, but
removed the GPL bits used to build the library, swiches old C style code for
C18 and replaces autotools with meson.

This patch adds a picolibc recipe for the C library, a picolibc-helloworld
recipe that contains an example application and a testcase that builds it.

Picolibc can be built for ARM and RISCV architectures, its been tested both
for 32 and 64 bits, the provided example recipe produces the following output:

hello, world

Runqemu does not automatically show any output since it hides QEMU stderr which
is where the QEMU monitors output is directed to when using semihosting, but,
manually running the same QEMU command does work properly.

Signed-off-by: Alejandro Enedino Hernandez Samaniego <alejandro@enedino.org>
---
 meta/classes-recipe/baremetal-image.bbclass   |   4 +-
 meta/classes-recipe/cross-canadian.bbclass    |   2 +-
 meta/conf/distro/include/maintainers.inc      |   2 +
 meta/conf/distro/include/tclibc-picolibc.inc  |  40 ++++++
 meta/conf/documentation.conf                  |   2 +-
 .../conf/machine/include/riscv/arch-riscv.inc |   1 +
 meta/lib/oeqa/selftest/cases/distrodata.py    |   2 +-
 meta/lib/oeqa/selftest/cases/picolibc.py      |  18 +++
 .../picolibc/picolibc-helloworld_git.bb       |  40 ++++++
 meta/recipes-core/picolibc/picolibc.inc       |  21 ++++
 .../avoid_polluting_cross_directories.patch   | 119 ++++++++++++++++++
 .../picolibc/no-early-compiler-checks.cross   |   6 +
 meta/recipes-core/picolibc/picolibc_git.bb    |  35 ++++++
 meta/recipes-devtools/gcc/gcc-cross.inc       |   1 +
 meta/recipes-devtools/gcc/gcc-runtime.inc     |   3 +
 meta/recipes-devtools/gcc/libgcc-common.inc   |   5 +
 16 files changed, 296 insertions(+), 5 deletions(-)
 create mode 100644 meta/conf/distro/include/tclibc-picolibc.inc
 create mode 100644 meta/lib/oeqa/selftest/cases/picolibc.py
 create mode 100644 meta/recipes-core/picolibc/picolibc-helloworld_git.bb
 create mode 100644 meta/recipes-core/picolibc/picolibc.inc
 create mode 100644 meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
 create mode 100644 meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
 create mode 100644 meta/recipes-core/picolibc/picolibc_git.bb

Comments

Alejandro Enedino Hernandez Samaniego June 18, 2024, 6:11 p.m. UTC | #1
This version is rebased on top of master after the UNPACKDIR changes.

Alejandro

On Tue, Jun 18, 2024, 12:09 PM Alejandro Enedino Hernandez Samaniego <
alejandro@enedino.org> wrote:

> Enables usage of TCLIBC=picolibc extending OE functionality to build and
> use
> picolibc based toolchains to build baremetal applications.
>
> Picolibc is a set of standard C libraries, both libc and libm, designed for
> smaller embedded systems with limited ROM and RAM. Picolibc includes code
> from Newlib and AVR Libc, but adresses some of newlibs concerns, it retains
> newlibs directory structure, math, string and locale implementations, but
> removed the GPL bits used to build the library, swiches old C style code
> for
> C18 and replaces autotools with meson.
>
> This patch adds a picolibc recipe for the C library, a picolibc-helloworld
> recipe that contains an example application and a testcase that builds it.
>
> Picolibc can be built for ARM and RISCV architectures, its been tested both
> for 32 and 64 bits, the provided example recipe produces the following
> output:
>
> hello, world
>
> Runqemu does not automatically show any output since it hides QEMU stderr
> which
> is where the QEMU monitors output is directed to when using semihosting,
> but,
> manually running the same QEMU command does work properly.
>
> Signed-off-by: Alejandro Enedino Hernandez Samaniego <
> alejandro@enedino.org>
> ---
>  meta/classes-recipe/baremetal-image.bbclass   |   4 +-
>  meta/classes-recipe/cross-canadian.bbclass    |   2 +-
>  meta/conf/distro/include/maintainers.inc      |   2 +
>  meta/conf/distro/include/tclibc-picolibc.inc  |  40 ++++++
>  meta/conf/documentation.conf                  |   2 +-
>  .../conf/machine/include/riscv/arch-riscv.inc |   1 +
>  meta/lib/oeqa/selftest/cases/distrodata.py    |   2 +-
>  meta/lib/oeqa/selftest/cases/picolibc.py      |  18 +++
>  .../picolibc/picolibc-helloworld_git.bb       |  40 ++++++
>  meta/recipes-core/picolibc/picolibc.inc       |  21 ++++
>  .../avoid_polluting_cross_directories.patch   | 119 ++++++++++++++++++
>  .../picolibc/no-early-compiler-checks.cross   |   6 +
>  meta/recipes-core/picolibc/picolibc_git.bb    |  35 ++++++
>  meta/recipes-devtools/gcc/gcc-cross.inc       |   1 +
>  meta/recipes-devtools/gcc/gcc-runtime.inc     |   3 +
>  meta/recipes-devtools/gcc/libgcc-common.inc   |   5 +
>  16 files changed, 296 insertions(+), 5 deletions(-)
>  create mode 100644 meta/conf/distro/include/tclibc-picolibc.inc
>  create mode 100644 meta/lib/oeqa/selftest/cases/picolibc.py
>  create mode 100644 meta/recipes-core/picolibc/picolibc-helloworld_git.bb
>  create mode 100644 meta/recipes-core/picolibc/picolibc.inc
>  create mode 100644
> meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
>  create mode 100644
> meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
>  create mode 100644 meta/recipes-core/picolibc/picolibc_git.bb
>
> diff --git a/meta/classes-recipe/baremetal-image.bbclass
> b/meta/classes-recipe/baremetal-image.bbclass
> index 4e7d413626..27f2d2d10a 100644
> --- a/meta/classes-recipe/baremetal-image.bbclass
> +++ b/meta/classes-recipe/baremetal-image.bbclass
> @@ -16,8 +16,8 @@
>  # See meta-skeleton for a working example.
>
>
> -# Toolchain should be baremetal or newlib based.
> -# TCLIBC="baremetal" or TCLIBC="newlib"
> +# Toolchain should be baremetal or newlib/picolibc based.
> +# TCLIBC="baremetal" or TCLIBC="newlib" or TCLIBC="picolibc"
>  COMPATIBLE_HOST:libc-musl:class-target = "null"
>  COMPATIBLE_HOST:libc-glibc:class-target = "null"
>
> diff --git a/meta/classes-recipe/cross-canadian.bbclass
> b/meta/classes-recipe/cross-canadian.bbclass
> index 1670217d69..059d9aa95f 100644
> --- a/meta/classes-recipe/cross-canadian.bbclass
> +++ b/meta/classes-recipe/cross-canadian.bbclass
> @@ -36,7 +36,7 @@ python () {
>      if d.getVar("MODIFYTOS") != "1":
>          return
>
> -    if d.getVar("TCLIBC") in [ 'baremetal', 'newlib' ]:
> +    if d.getVar("TCLIBC") in [ 'baremetal', 'newlib', 'picolibc' ]:
>          return
>
>      tos = d.getVar("TARGET_OS")
> diff --git a/meta/conf/distro/include/maintainers.inc
> b/meta/conf/distro/include/maintainers.inc
> index 42599267c1..ff24597723 100644
> --- a/meta/conf/distro/include/maintainers.inc
> +++ b/meta/conf/distro/include/maintainers.inc
> @@ -578,6 +578,8 @@ RECIPE_MAINTAINER:pn-pcmanfm = "Alexander Kanavin <
> alex.kanavin@gmail.com>"
>  RECIPE_MAINTAINER:pn-perf = "Bruce Ashfield <bruce.ashfield@gmail.com>"
>  RECIPE_MAINTAINER:pn-perl = "Alexander Kanavin <alex.kanavin@gmail.com>"
>  RECIPE_MAINTAINER:pn-perlcross = "Alexander Kanavin <
> alex.kanavin@gmail.com>"
> +RECIPE_MAINTAINER:pn-picolibc = "Alejandro Hernandez <
> alejandro@enedino.org>"
> +RECIPE_MAINTAINER:pn-picolibc-helloworld = "Alejandro Hernandez <
> alejandro@enedino.org>"
>  RECIPE_MAINTAINER:pn-piglit = "Ross Burton <ross.burton@arm.com>"
>  RECIPE_MAINTAINER:pn-pigz = "Hongxu Jia <hongxu.jia@windriver.com>"
>  RECIPE_MAINTAINER:pn-pinentry = "Unassigned <unassigned@yoctoproject.org
> >"
> diff --git a/meta/conf/distro/include/tclibc-picolibc.inc
> b/meta/conf/distro/include/tclibc-picolibc.inc
> new file mode 100644
> index 0000000000..203765dfcb
> --- /dev/null
> +++ b/meta/conf/distro/include/tclibc-picolibc.inc
> @@ -0,0 +1,40 @@
> +#
> +# Picolibc configuration
> +#
> +
> +LIBCEXTENSION = "-picolibc"
> +LIBCOVERRIDE = ":libc-picolibc"
> +
> +PREFERRED_PROVIDER_virtual/libc ?= "picolibc"
> +PREFERRED_PROVIDER_virtual/libiconv ?= "picolibc"
> +PREFERRED_PROVIDER_virtual/libintl ?= "picolibc"
> +PREFERRED_PROVIDER_virtual/nativesdk-libintl ?= "nativesdk-glibc"
> +PREFERRED_PROVIDER_virtual/nativesdk-libiconv ?= "nativesdk-glibc"
> +
> +DISTRO_FEATURES_BACKFILL_CONSIDERED += "ldconfig"
> +
> +IMAGE_LINGUAS = ""
> +
> +LIBC_DEPENDENCIES = " \
> +    picolibc-dbg \
> +    picolibc-dev \
> +    libgcc-dev \
> +    libgcc-dbg \
> +    libstdc++-dev  \
> +    libstdc++-staticdev \
> +"
> +
> +ASSUME_PROVIDED += "virtual/crypt"
> +
> +TARGET_OS = "elf"
> +TARGET_OS:arm = "eabi"
> +
> +TOOLCHAIN_HOST_TASK ?= "packagegroup-cross-canadian-${MACHINE}
> nativesdk-qemu nativesdk-sdk-provides-dummy"
> +TOOLCHAIN_TARGET_TASK ?= "${LIBC_DEPENDENCIES}"
> +TOOLCHAIN_NEED_CONFIGSITE_CACHE:remove = "zlib ncurses"
> +
> +# RISCV linker doesnt support PIE
> +SECURITY_CFLAGS:libc-picolibc:qemuriscv32 = "${SECURITY_NOPIE_CFLAGS}"
> +SECURITY_CFLAGS:libc-picolibc:qemuriscv64 = "${SECURITY_NOPIE_CFLAGS}"
> +
> +
> diff --git a/meta/conf/documentation.conf b/meta/conf/documentation.conf
> index b0591881ba..ad89142934 100644
> --- a/meta/conf/documentation.conf
> +++ b/meta/conf/documentation.conf
> @@ -421,7 +421,7 @@ TARGET_FPU[doc] = "Specifies the method for handling
> FPU code. For FPU-less targ
>  TARGET_OS[doc] = "Specifies the target's operating system."
>  TARGET_PREFIX[doc] = "The prefix for the cross-compile toolchain (e.g.
> arm-linux-)."
>  TARGET_SYS[doc] = "The target system is comprised of
> TARGET_ARCH,TARGET_VENDOR and TARGET_OS."
> -TCLIBC[doc] = "Specifies C library (libc) variant to use during the build
> process. You can select 'baremetal', 'glibc', 'musl' or 'newlib'."
> +TCLIBC[doc] = "Specifies C library (libc) variant to use during the build
> process. You can select 'baremetal', 'glibc', 'musl', 'newlib', or
> 'picolibc'."
>  TCMODE[doc] = "Enables an external toolchain (where provided by an
> additional layer) if set to a value other than 'default'."
>  TESTIMAGE_AUTO[doc] = "Enables test booting of virtual machine images
> under the QEMU emulator after any root filesystems are created and runs
> tests against those images each time an image is built."
>  TEST_QEMUBOOT_TIMEOUT[doc] = "The time in seconds allowed for an image to
> boot before automated runtime tests begin to run against an image."
> diff --git a/meta/conf/machine/include/riscv/arch-riscv.inc
> b/meta/conf/machine/include/riscv/arch-riscv.inc
> index 230a266563..b34064e78f 100644
> --- a/meta/conf/machine/include/riscv/arch-riscv.inc
> +++ b/meta/conf/machine/include/riscv/arch-riscv.inc
> @@ -11,5 +11,6 @@ TUNE_CCARGS:append =
> "${@bb.utils.contains('TUNE_FEATURES', 'riscv64nc', ' -marc
>
>  # Fix: ld: unrecognized option '--hash-style=sysv'
>  LINKER_HASH_STYLE:libc-newlib = ""
> +LINKER_HASH_STYLE:libc-picolibc = ""
>  # Fix: ld: unrecognized option '--hash-style=gnu'
>  LINKER_HASH_STYLE:libc-baremetal = ""
> diff --git a/meta/lib/oeqa/selftest/cases/distrodata.py
> b/meta/lib/oeqa/selftest/cases/distrodata.py
> index ad952c004b..043953757f 100644
> --- a/meta/lib/oeqa/selftest/cases/distrodata.py
> +++ b/meta/lib/oeqa/selftest/cases/distrodata.py
> @@ -55,7 +55,7 @@ but their recipes claim otherwise by setting
> UPSTREAM_VERSION_UNKNOWN. Please re
>              return False
>
>          def is_maintainer_exception(entry):
> -            exceptions = ["musl", "newlib", "linux-yocto", "linux-dummy",
> "mesa-gl", "libgfortran", "libx11-compose-data",
> +            exceptions = ["musl", "newlib", "picolibc", "linux-yocto",
> "linux-dummy", "mesa-gl", "libgfortran", "libx11-compose-data",
>                            "cve-update-nvd2-native",]
>              for i in exceptions:
>                   if i in entry:
> diff --git a/meta/lib/oeqa/selftest/cases/picolibc.py
> b/meta/lib/oeqa/selftest/cases/picolibc.py
> new file mode 100644
> index 0000000000..e40b4fc3d3
> --- /dev/null
> +++ b/meta/lib/oeqa/selftest/cases/picolibc.py
> @@ -0,0 +1,18 @@
> +#
> +# Copyright OpenEmbedded Contributors
> +#
> +# SPDX-License-Identifier: MIT
> +#
> +
> +from oeqa.selftest.case import OESelftestTestCase
> +from oeqa.utils.commands import bitbake, get_bb_var
> +
> +class PicolibcTest(OESelftestTestCase):
> +
> +    def test_picolibc(self):
> +        compatible_machines = ['qemuarm', 'qemuarm64', 'qemuriscv32',
> 'qemuriscv64']
> +        machine = get_bb_var('MACHINE')
> +        if machine not in compatible_machines:
> +            self.skipTest('This test only works with machines : %s' % '
> '.join(compatible_machines))
> +        self.write_config('TCLIBC = "picolibc"')
> +        bitbake("picolibc-helloworld")
> diff --git a/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
> b/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
> new file mode 100644
> index 0000000000..573a571c24
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
> @@ -0,0 +1,40 @@
> +require picolibc.inc
> +
> +# baremetal-image overrides
> +BAREMETAL_BINNAME ?= "hello_picolibc_${MACHINE}"
> +IMAGE_LINK_NAME ?= "baremetal-picolibc-image-${MACHINE}"
> +IMAGE_NAME_SUFFIX ?= ""
> +QB_DEFAULT_KERNEL ?= "${IMAGE_LINK_NAME}.elf"
> +
> +inherit baremetal-image
> +
> +COMPATIBLE_MACHINE = "qemuarm|qemuarm64|qemuriscv32|qemuriscv64"
> +
> +# Use semihosting to test via QEMU
> +QB_OPT_APPEND:append = " -semihosting-config enable=on"
> +
> +# picolibc comes with a set of linker scripts, set the file
> +# according to the architecture being built.
> +PICOLIBC_LINKERSCRIPT:qemuarm64 = "aarch64.ld"
> +PICOLIBC_LINKERSCRIPT:qemuarm = "arm.ld"
> +PICOLIBC_LINKERSCRIPT:qemuriscv32 = "riscv.ld"
> +PICOLIBC_LINKERSCRIPT:qemuriscv64 = "riscv.ld"
> +
> +# Simple compile function that manually exemplifies usage; as noted,
> +# use a custom linker script, the GCC specs provided by picolibc
> +# and semihost to be able to test via QEMU's monitor
> +do_compile(){
> +    ${CC} ${CFLAGS} ${LDFLAGS} --verbose
> -T${S}/hello-world/${PICOLIBC_LINKERSCRIPT} -specs=picolibc.specs
> --oslib=semihost -o ${BAREMETAL_BINNAME}.elf ${S}/hello-world/hello-world.c
> +    ${OBJCOPY} -O binary ${BAREMETAL_BINNAME}.elf ${BAREMETAL_BINNAME}.bin
> +}
> +
> +do_install(){
> +    install -d ${D}/${base_libdir}/firmware
> +    install -m 755 ${B}/${BAREMETAL_BINNAME}.elf
> ${D}/${base_libdir}/firmware/${BAREMETAL_BINNAME}.elf
> +    install -m 755 ${B}/${BAREMETAL_BINNAME}.bin
> ${D}/${base_libdir}/firmware/${BAREMETAL_BINNAME}.bin
> +}
> +
> +FILES:${PN} += " \
> +    ${base_libdir}/firmware/${BAREMETAL_BINNAME}.elf \
> +    ${base_libdir}/firmware/${BAREMETAL_BINNAME}.bin \
> +"
> diff --git a/meta/recipes-core/picolibc/picolibc.inc
> b/meta/recipes-core/picolibc/picolibc.inc
> new file mode 100644
> index 0000000000..3b380fe7af
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc.inc
> @@ -0,0 +1,21 @@
> +SUMMARY = "C Libraries for Smaller Embedded Systems"
> +HOMEPAGE = "https://keithp.com/picolibc"
> +DESCRIPTION = "Picolibc is a set of standard C libraries, both libc and
> libm, designed for smaller embedded systems with limited ROM and RAM.
> Picolibc includes code from Newlib and AVR Libc."
> +SECTION = "libs"
> +
> +# Newlib based code but GPL related bits removed, test/printf-tests.c and
> test/testcases.c
> +# are GPLv2 and GeneratePicolibcCrossFile.sh is AGPL3 but not part of the
> artifacts.
> +LICENSE = "BSD-2-Clause & BSD-3-Clause"
> +LIC_FILES_CHKSUM = " \
> +               file://COPYING.GPL2;md5=59530bdf33659b29e73d4adb9f9f6552 \
> +               file://COPYING.NEWLIB;md5=08ae03456feb75b81cfdb359e0f1ef85
> \
> +
>  file://COPYING.picolibc;md5=e50fa9458a40929689861ed472d46bc7 \
> +               "
> +
> +BASEVER = "1.8.6"
> +PV = "${BASEVER}+git"
> +SRC_URI = "git://
> github.com/picolibc/picolibc.git;protocol=https;branch=main"
> +SRCREV="764ef4e401a8f4c6a86ab723533841f072885a5b"
> +
> +S = "${WORKDIR}/git"
> +B = "${WORKDIR}/build"
> diff --git
> a/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> b/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> new file mode 100644
> index 0000000000..da6460c95c
> --- /dev/null
> +++
> b/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> @@ -0,0 +1,119 @@
> +Upstream-Status: Pending
> +
> +Picolibc uses its own specs file: picolibc.specs to facilitate
> compilation, this
> +needs to be passed down to GCC via the -specs argument.
> +
> +Using this specs file overrides some of the default options our toolchain
> was
> +built with, in this case, they modify the include_dir and lib_dir paths
> used for
> +compilation, their intention was to add support for -picolibc-prefix and
> +-picolibc-buildtype arguments via the C preprocessor.
> +
> +-isystem %{-picolibc-prefix=*:%*/include/;
> -picolibc-buildtype=*:/usr/include/%*; :/usr/include} %(picolibc_cpp)
> +
> +This had the unwanted effect of defaulting to /usr/include for
> include_dir if
> +those arguments are not being passed, this works fine for their flow but
> for us
> +it pollutes the include directories with paths from the host. The same
> effect is
> +applicable for lib_dir and for the c runtime file.
> +
> +Our toolchain relies on --sysroot to avoid using any paths from the host,
> here we
> +manually add support for a third possible argument: -sysroot , if this is
> passed
> +then the paths used by the compiler will be relative to the path passed
> by the
> +--sysroot= cmdline argument, setting back the behavior that we intended
> in the
> +first place.
> +
> +
> +Signed-off-by: Alejandro Enedino Hernandez Samaniego <
> alejandro@enedino.org>
> +
> +Index: git/meson.build
> +===================================================================
> +--- git.orig/meson.build
> ++++ git/meson.build
> +@@ -622,12 +622,13 @@ else
> + #
> + picolibc_prefix_format = '-picolibc-prefix=*:@0@'
> + picolibc_buildtype_format = '-picolibc-buildtype=*:@0@'
> ++sysroot_format = '-sysroot=*:@0@'
> + gen_format = '@0@'
> +
> + #
> + # How to glue the three options together
> + #
> +-specs_option_format = '%{@0@; @1@; :@2@}'
> ++specs_option_format = '%{@0@; @1@; @2@; :@3@}'
> +
> + #
> + # Build the -isystem value
> +@@ -639,10 +640,13 @@ isystem_prefix = picolibc_prefix_format.
> + buildtype_include_dir =
> specs_prefix_format.format(get_option('includedir') / '%*')
> + isystem_buildtype =
> picolibc_buildtype_format.format(buildtype_include_dir)
> +
> ++sysroot_include_dir = '%*'
> ++isystem_sysroot = sysroot_format.format(sysroot_include_dir)
> ++
> + gen_include_dir = specs_prefix_format.format(get_option('includedir'))
> + isystem_gen = gen_format.format(gen_include_dir)
> +
> +-specs_isystem = '-isystem ' + specs_option_format.format(isystem_prefix,
> isystem_buildtype, isystem_gen)
> ++specs_isystem = '-isystem ' + specs_option_format.format(isystem_prefix,
> isystem_buildtype, isystem_sysroot, isystem_gen)
> +
> + #
> + # Build the non-multilib -L value
> +@@ -654,10 +658,13 @@ lib_prefix = picolibc_prefix_format.form
> + buildtype_lib_dir = specs_prefix_format.format(get_option('libdir') /
> '%*')
> + lib_buildtype = picolibc_buildtype_format.format(buildtype_lib_dir)
> +
> ++sysroot_lib_dir = '%*'
> ++lib_sysroot = sysroot_format.format(sysroot_lib_dir)
> ++
> + gen_lib_dir = specs_prefix_format.format(get_option('libdir'))
> + lib_gen = gen_format.format(gen_lib_dir)
> +
> +-specs_libpath = '-L' + specs_option_format.format(lib_prefix,
> lib_buildtype, lib_gen)
> ++specs_libpath = '-L' + specs_option_format.format(lib_prefix,
> lib_buildtype, lib_sysroot, lib_gen)
> +
> + #
> + # Build the non-multilib *startfile options
> +@@ -669,6 +676,9 @@ crt0_prefix = picolibc_prefix_format.for
> + buildtype_crt0_path = specs_prefix_format.format(get_option('libdir') /
> '%*' / crt0_expr)
> + crt0_buildtype = picolibc_buildtype_format.format(buildtype_crt0_path)
> +
> ++sysroot_crt0_path = '%*' + '/' + get_option('libdir') + '/' + '%*' + '/'
> + crt0_expr
> ++crt0_sysroot = picolibc_buildtype_format.format(sysroot_crt0_path)
> ++
> + gen_crt0_path = specs_prefix_format.format(get_option('libdir') /
> crt0_expr)
> + crt0_gen = gen_format.format(gen_crt0_path)
> +
> +@@ -686,10 +696,13 @@ if enable_multilib
> +   buildtype_multilib_dir =
> specs_prefix_format.format(get_option('libdir') / '%*/%M')
> +   multilib_buildtype =
> picolibc_buildtype_format.format(buildtype_multilib_dir)
> +
> ++  sysroot_multilib_dir = '%*' + '/' + get_option('libdir') + '/' +
> '%*/%M'
> ++  multilib_sysroot = sysroot_format.format(sysroot_multilib_dir)
> ++
> +   gen_multilib_dir = specs_prefix_format.format(get_option('libdir') /
> '%M')
> +   multilib_gen = gen_format.format(gen_multilib_dir)
> +
> +-  specs_multilibpath = '-L' +
> specs_option_format.format(multilib_prefix, multilib_buildtype,
> multilib_gen)
> ++  specs_multilibpath = '-L' +
> specs_option_format.format(multilib_prefix, multilib_buildtype,
> multilib_sysroot, multilib_gen)
> +
> +   #
> +   # Prepend the multilib -L option to the non-multilib option
> +@@ -705,6 +718,9 @@ if enable_multilib
> +   buildtype_multilib_crt0_path =
> specs_prefix_format.format(get_option('libdir') / '%*/%M' / crt0_expr)
> +   crt0_buildtype =
> picolibc_buildtype_format.format(buildtype_multilib_crt0_path)
> +
> ++  sysroot_multilib_crt0_path = '%*' + prefix + '/' +
> get_option('libdir') + '/' + '/%M' + '/' + crt0_expr
> ++  crt0_sysroot = sysroot_format.format(sysroot_multilib_crt0_path)
> ++
> +   gen_multilib_crt0_path =
> specs_prefix_format.format(get_option('libdir') / '%M' / crt0_expr)
> +   crt0_gen = gen_format.format(gen_multilib_crt0_path)
> + endif
> +@@ -714,7 +730,7 @@ endif
> + # above. As there's only one value, it's either the
> + # multilib path or the non-multilib path
> + #
> +-specs_startfile = specs_option_format.format(crt0_prefix,
> crt0_buildtype, crt0_gen)
> ++specs_startfile = specs_option_format.format(crt0_prefix,
> crt0_buildtype, crt0_sysroot, crt0_gen)
> + endif
> +
> + specs_data = configuration_data()
> diff --git
> a/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> b/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> new file mode 100644
> index 0000000000..87bfbad3c5
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> @@ -0,0 +1,6 @@
> +# We need to explicitly bypass mesons sanity check to avoid early
> compiler errors
> +# otherwise meson will try to compile AND run test applications:
> +# ../git/meson.build:35:0: ERROR: Executables created by c compiler are
> not runnable...
> +
> +[properties]
> +skip_sanity_check=true
> \ No newline at end of file
> diff --git a/meta/recipes-core/picolibc/picolibc_git.bb
> b/meta/recipes-core/picolibc/picolibc_git.bb
> new file mode 100644
> index 0000000000..fdb159328f
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc_git.bb
> @@ -0,0 +1,35 @@
> +require picolibc.inc
> +
> +INHIBIT_DEFAULT_DEPS = "1"
> +DEPENDS = "virtual/${TARGET_PREFIX}gcc"
> +
> +PROVIDES += "virtual/libc virtual/libiconv virtual/libintl"
> +
> +COMPATIBLE_HOST:libc-musl:class-target = "null"
> +COMPATIBLE_HOST:libc-glibc:class-target = "null"
> +COMPATIBLE_MACHINE = "qemuarm|qemuarm64|qemuriscv32|qemuriscv64"
> +
> +SRC_URI:append = " file://avoid_polluting_cross_directories.patch"
> +SRC_URI:append = " file://no-early-compiler-checks.cross"
> +
> +# This is being added by picolibc meson files as well to avoid
> +# early compiler tests from failing, cant remember why I added it
> +# to the newlib recipe but I would assume it was for the same reason
> +TARGET_CC_ARCH:append = " -nostdlib"
> +
> +# When using RISCV64 use medany for both C library and application recipes
> +TARGET_CFLAGS:append:qemuriscv64 = " -mcmodel=medany"
> +
> +inherit meson
> +
> +MESON_CROSS_FILE:append = "
> --cross-file=${UNPACKDIR}/no-early-compiler-checks.cross"
> +
> +PACKAGECONFIG ??= " specsdir"
> +# Install GCC specs on libdir
> +PACKAGECONFIG[specsdir] = "-Dspecsdir=${libdir},-Dspecsdir=none"
> +
> +
> +FILES:${PN}-dev:append = " ${libdir}/*.specs ${libdir}/*.ld"
> +
> +# No rpm package is actually created but -dev depends on it, avoid dnf
> error
> +DEV_PKG_DEPENDENCY:libc-picolibc = ""
> diff --git a/meta/recipes-devtools/gcc/gcc-cross.inc
> b/meta/recipes-devtools/gcc/gcc-cross.inc
> index 5b0ca15d47..c04177df5a 100644
> --- a/meta/recipes-devtools/gcc/gcc-cross.inc
> +++ b/meta/recipes-devtools/gcc/gcc-cross.inc
> @@ -34,6 +34,7 @@ EXTRA_OECONF += "\
>  EXTRA_OECONF:append:libc-baremetal = " --without-headers"
>  EXTRA_OECONF:remove:libc-baremetal = "--enable-threads=posix"
>  EXTRA_OECONF:remove:libc-newlib = "--enable-threads=posix"
> +EXTRA_OECONF:remove:libc-picolibc = "--enable-threads=posix"
>
>  EXTRA_OECONF_PATHS = "\
>      --with-gxx-include-dir=/not/exist${target_includedir}/c++/${BINV} \
> diff --git a/meta/recipes-devtools/gcc/gcc-runtime.inc
> b/meta/recipes-devtools/gcc/gcc-runtime.inc
> index 89b0bebcfb..1fca00f5f0 100644
> --- a/meta/recipes-devtools/gcc/gcc-runtime.inc
> +++ b/meta/recipes-devtools/gcc/gcc-runtime.inc
> @@ -17,6 +17,7 @@ EXTRA_OECONF_PATHS = "\
>  EXTRA_OECONF:append:linuxstdbase = " --enable-clocale=gnu"
>  EXTRA_OECONF:append = " --cache-file=${B}/config.cache"
>  EXTRA_OECONF:append:libc-newlib = " --with-newlib --with-target-subdir"
> +EXTRA_OECONF:append:libc-picolibc = " --with-newlib --with-target-subdir"
>  EXTRA_OECONF:append:libc-baremetal = " --with-target-subdir"
>
>  # Disable ifuncs for libatomic on arm conflicts -march/-mcpu
> @@ -27,6 +28,7 @@ DISABLE_STATIC:class-nativesdk ?= ""
>
>  # Newlib does not support symbol versioning on libsdtcc++
>  SYMVERS_CONF:libc-newlib = ""
> +SYMVERS_CONF:libc-picolibc = ""
>
>  # Building with thumb enabled on armv6t fails
>  ARM_INSTRUCTION_SET:armv6 = "arm"
> @@ -47,6 +49,7 @@ RUNTIMETARGET = "${RUNTIMELIBSSP} libstdc++-v3 libgomp
> libatomic ${RUNTIMELIBITM
>  "
>  # Only build libstdc++ for newlib
>  RUNTIMETARGET:libc-newlib = "libstdc++-v3"
> +RUNTIMETARGET:libc-picolibc = "libstdc++-v3"
>
>  # libiberty
>  # libgfortran needs separate recipe due to libquadmath dependency
> diff --git a/meta/recipes-devtools/gcc/libgcc-common.inc
> b/meta/recipes-devtools/gcc/libgcc-common.inc
> index d9084af51a..e3db17d700 100644
> --- a/meta/recipes-devtools/gcc/libgcc-common.inc
> +++ b/meta/recipes-devtools/gcc/libgcc-common.inc
> @@ -53,6 +53,11 @@ do_install:append:libc-newlib () {
>                 rmdir ${D}${base_libdir}
>         fi
>  }
> +do_install:append:libc-picolibc () {
> +       if [ "${base_libdir}" != "${libdir}" ]; then
> +               rmdir ${D}${base_libdir}
> +       fi
> +}
>
>  # No rpm package is actually created but -dev depends on it, avoid dnf
> error
>  DEV_PKG_DEPENDENCY:libc-baremetal = ""
> --
> 2.45.2
>
>
>
Alexandre Belloni June 19, 2024, 8:03 p.m. UTC | #2
Hello,

This causes selftest failures:

https://autobuilder.yoctoproject.org/typhoon/#/builders/80/builds/6833/steps/14/logs/stdio
https://autobuilder.yoctoproject.org/typhoon/#/builders/79/builds/6877/steps/15/logs/stdio
https://autobuilder.yoctoproject.org/typhoon/#/builders/86/builds/6902/steps/14/logs/stdio
https://autobuilder.yoctoproject.org/typhoon/#/builders/87/builds/6888/steps/14/logs/stdio
https://autobuilder.yoctoproject.org/typhoon/#/builders/127/builds/3495/steps/15/logs/stdio

On 18/06/2024 12:12:26-0600, Alejandro Hernandez Samaniego wrote:
> Enables usage of TCLIBC=picolibc extending OE functionality to build and use
> picolibc based toolchains to build baremetal applications.
> 
> Picolibc is a set of standard C libraries, both libc and libm, designed for
> smaller embedded systems with limited ROM and RAM. Picolibc includes code
> from Newlib and AVR Libc, but adresses some of newlibs concerns, it retains
> newlibs directory structure, math, string and locale implementations, but
> removed the GPL bits used to build the library, swiches old C style code for
> C18 and replaces autotools with meson.
> 
> This patch adds a picolibc recipe for the C library, a picolibc-helloworld
> recipe that contains an example application and a testcase that builds it.
> 
> Picolibc can be built for ARM and RISCV architectures, its been tested both
> for 32 and 64 bits, the provided example recipe produces the following output:
> 
> hello, world
> 
> Runqemu does not automatically show any output since it hides QEMU stderr which
> is where the QEMU monitors output is directed to when using semihosting, but,
> manually running the same QEMU command does work properly.
> 
> Signed-off-by: Alejandro Enedino Hernandez Samaniego <alejandro@enedino.org>
> ---
>  meta/classes-recipe/baremetal-image.bbclass   |   4 +-
>  meta/classes-recipe/cross-canadian.bbclass    |   2 +-
>  meta/conf/distro/include/maintainers.inc      |   2 +
>  meta/conf/distro/include/tclibc-picolibc.inc  |  40 ++++++
>  meta/conf/documentation.conf                  |   2 +-
>  .../conf/machine/include/riscv/arch-riscv.inc |   1 +
>  meta/lib/oeqa/selftest/cases/distrodata.py    |   2 +-
>  meta/lib/oeqa/selftest/cases/picolibc.py      |  18 +++
>  .../picolibc/picolibc-helloworld_git.bb       |  40 ++++++
>  meta/recipes-core/picolibc/picolibc.inc       |  21 ++++
>  .../avoid_polluting_cross_directories.patch   | 119 ++++++++++++++++++
>  .../picolibc/no-early-compiler-checks.cross   |   6 +
>  meta/recipes-core/picolibc/picolibc_git.bb    |  35 ++++++
>  meta/recipes-devtools/gcc/gcc-cross.inc       |   1 +
>  meta/recipes-devtools/gcc/gcc-runtime.inc     |   3 +
>  meta/recipes-devtools/gcc/libgcc-common.inc   |   5 +
>  16 files changed, 296 insertions(+), 5 deletions(-)
>  create mode 100644 meta/conf/distro/include/tclibc-picolibc.inc
>  create mode 100644 meta/lib/oeqa/selftest/cases/picolibc.py
>  create mode 100644 meta/recipes-core/picolibc/picolibc-helloworld_git.bb
>  create mode 100644 meta/recipes-core/picolibc/picolibc.inc
>  create mode 100644 meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
>  create mode 100644 meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
>  create mode 100644 meta/recipes-core/picolibc/picolibc_git.bb
> 
> diff --git a/meta/classes-recipe/baremetal-image.bbclass b/meta/classes-recipe/baremetal-image.bbclass
> index 4e7d413626..27f2d2d10a 100644
> --- a/meta/classes-recipe/baremetal-image.bbclass
> +++ b/meta/classes-recipe/baremetal-image.bbclass
> @@ -16,8 +16,8 @@
>  # See meta-skeleton for a working example.
>  
>  
> -# Toolchain should be baremetal or newlib based.
> -# TCLIBC="baremetal" or TCLIBC="newlib"
> +# Toolchain should be baremetal or newlib/picolibc based.
> +# TCLIBC="baremetal" or TCLIBC="newlib" or TCLIBC="picolibc"
>  COMPATIBLE_HOST:libc-musl:class-target = "null"
>  COMPATIBLE_HOST:libc-glibc:class-target = "null"
>  
> diff --git a/meta/classes-recipe/cross-canadian.bbclass b/meta/classes-recipe/cross-canadian.bbclass
> index 1670217d69..059d9aa95f 100644
> --- a/meta/classes-recipe/cross-canadian.bbclass
> +++ b/meta/classes-recipe/cross-canadian.bbclass
> @@ -36,7 +36,7 @@ python () {
>      if d.getVar("MODIFYTOS") != "1":
>          return
>  
> -    if d.getVar("TCLIBC") in [ 'baremetal', 'newlib' ]:
> +    if d.getVar("TCLIBC") in [ 'baremetal', 'newlib', 'picolibc' ]:
>          return
>  
>      tos = d.getVar("TARGET_OS")
> diff --git a/meta/conf/distro/include/maintainers.inc b/meta/conf/distro/include/maintainers.inc
> index 42599267c1..ff24597723 100644
> --- a/meta/conf/distro/include/maintainers.inc
> +++ b/meta/conf/distro/include/maintainers.inc
> @@ -578,6 +578,8 @@ RECIPE_MAINTAINER:pn-pcmanfm = "Alexander Kanavin <alex.kanavin@gmail.com>"
>  RECIPE_MAINTAINER:pn-perf = "Bruce Ashfield <bruce.ashfield@gmail.com>"
>  RECIPE_MAINTAINER:pn-perl = "Alexander Kanavin <alex.kanavin@gmail.com>"
>  RECIPE_MAINTAINER:pn-perlcross = "Alexander Kanavin <alex.kanavin@gmail.com>"
> +RECIPE_MAINTAINER:pn-picolibc = "Alejandro Hernandez <alejandro@enedino.org>"
> +RECIPE_MAINTAINER:pn-picolibc-helloworld = "Alejandro Hernandez <alejandro@enedino.org>"
>  RECIPE_MAINTAINER:pn-piglit = "Ross Burton <ross.burton@arm.com>"
>  RECIPE_MAINTAINER:pn-pigz = "Hongxu Jia <hongxu.jia@windriver.com>"
>  RECIPE_MAINTAINER:pn-pinentry = "Unassigned <unassigned@yoctoproject.org>"
> diff --git a/meta/conf/distro/include/tclibc-picolibc.inc b/meta/conf/distro/include/tclibc-picolibc.inc
> new file mode 100644
> index 0000000000..203765dfcb
> --- /dev/null
> +++ b/meta/conf/distro/include/tclibc-picolibc.inc
> @@ -0,0 +1,40 @@
> +#
> +# Picolibc configuration
> +#
> +
> +LIBCEXTENSION = "-picolibc"
> +LIBCOVERRIDE = ":libc-picolibc"
> +
> +PREFERRED_PROVIDER_virtual/libc ?= "picolibc"
> +PREFERRED_PROVIDER_virtual/libiconv ?= "picolibc"
> +PREFERRED_PROVIDER_virtual/libintl ?= "picolibc"
> +PREFERRED_PROVIDER_virtual/nativesdk-libintl ?= "nativesdk-glibc"
> +PREFERRED_PROVIDER_virtual/nativesdk-libiconv ?= "nativesdk-glibc"
> +
> +DISTRO_FEATURES_BACKFILL_CONSIDERED += "ldconfig"
> +
> +IMAGE_LINGUAS = ""
> +
> +LIBC_DEPENDENCIES = " \
> +    picolibc-dbg \
> +    picolibc-dev \
> +    libgcc-dev \
> +    libgcc-dbg \
> +    libstdc++-dev  \
> +    libstdc++-staticdev \
> +"
> +
> +ASSUME_PROVIDED += "virtual/crypt"
> +
> +TARGET_OS = "elf"
> +TARGET_OS:arm = "eabi"
> +
> +TOOLCHAIN_HOST_TASK ?= "packagegroup-cross-canadian-${MACHINE} nativesdk-qemu nativesdk-sdk-provides-dummy"
> +TOOLCHAIN_TARGET_TASK ?= "${LIBC_DEPENDENCIES}"
> +TOOLCHAIN_NEED_CONFIGSITE_CACHE:remove = "zlib ncurses"
> +
> +# RISCV linker doesnt support PIE
> +SECURITY_CFLAGS:libc-picolibc:qemuriscv32 = "${SECURITY_NOPIE_CFLAGS}"
> +SECURITY_CFLAGS:libc-picolibc:qemuriscv64 = "${SECURITY_NOPIE_CFLAGS}"
> +
> +
> diff --git a/meta/conf/documentation.conf b/meta/conf/documentation.conf
> index b0591881ba..ad89142934 100644
> --- a/meta/conf/documentation.conf
> +++ b/meta/conf/documentation.conf
> @@ -421,7 +421,7 @@ TARGET_FPU[doc] = "Specifies the method for handling FPU code. For FPU-less targ
>  TARGET_OS[doc] = "Specifies the target's operating system."
>  TARGET_PREFIX[doc] = "The prefix for the cross-compile toolchain (e.g. arm-linux-)."
>  TARGET_SYS[doc] = "The target system is comprised of TARGET_ARCH,TARGET_VENDOR and TARGET_OS."
> -TCLIBC[doc] = "Specifies C library (libc) variant to use during the build process. You can select 'baremetal', 'glibc', 'musl' or 'newlib'."
> +TCLIBC[doc] = "Specifies C library (libc) variant to use during the build process. You can select 'baremetal', 'glibc', 'musl', 'newlib', or 'picolibc'."
>  TCMODE[doc] = "Enables an external toolchain (where provided by an additional layer) if set to a value other than 'default'."
>  TESTIMAGE_AUTO[doc] = "Enables test booting of virtual machine images under the QEMU emulator after any root filesystems are created and runs tests against those images each time an image is built."
>  TEST_QEMUBOOT_TIMEOUT[doc] = "The time in seconds allowed for an image to boot before automated runtime tests begin to run against an image."
> diff --git a/meta/conf/machine/include/riscv/arch-riscv.inc b/meta/conf/machine/include/riscv/arch-riscv.inc
> index 230a266563..b34064e78f 100644
> --- a/meta/conf/machine/include/riscv/arch-riscv.inc
> +++ b/meta/conf/machine/include/riscv/arch-riscv.inc
> @@ -11,5 +11,6 @@ TUNE_CCARGS:append = "${@bb.utils.contains('TUNE_FEATURES', 'riscv64nc', ' -marc
>  
>  # Fix: ld: unrecognized option '--hash-style=sysv'
>  LINKER_HASH_STYLE:libc-newlib = ""
> +LINKER_HASH_STYLE:libc-picolibc = ""
>  # Fix: ld: unrecognized option '--hash-style=gnu'
>  LINKER_HASH_STYLE:libc-baremetal = ""
> diff --git a/meta/lib/oeqa/selftest/cases/distrodata.py b/meta/lib/oeqa/selftest/cases/distrodata.py
> index ad952c004b..043953757f 100644
> --- a/meta/lib/oeqa/selftest/cases/distrodata.py
> +++ b/meta/lib/oeqa/selftest/cases/distrodata.py
> @@ -55,7 +55,7 @@ but their recipes claim otherwise by setting UPSTREAM_VERSION_UNKNOWN. Please re
>              return False
>  
>          def is_maintainer_exception(entry):
> -            exceptions = ["musl", "newlib", "linux-yocto", "linux-dummy", "mesa-gl", "libgfortran", "libx11-compose-data",
> +            exceptions = ["musl", "newlib", "picolibc", "linux-yocto", "linux-dummy", "mesa-gl", "libgfortran", "libx11-compose-data",
>                            "cve-update-nvd2-native",]
>              for i in exceptions:
>                   if i in entry:
> diff --git a/meta/lib/oeqa/selftest/cases/picolibc.py b/meta/lib/oeqa/selftest/cases/picolibc.py
> new file mode 100644
> index 0000000000..e40b4fc3d3
> --- /dev/null
> +++ b/meta/lib/oeqa/selftest/cases/picolibc.py
> @@ -0,0 +1,18 @@
> +#
> +# Copyright OpenEmbedded Contributors
> +#
> +# SPDX-License-Identifier: MIT
> +#
> +
> +from oeqa.selftest.case import OESelftestTestCase
> +from oeqa.utils.commands import bitbake, get_bb_var
> +
> +class PicolibcTest(OESelftestTestCase):
> +
> +    def test_picolibc(self):
> +        compatible_machines = ['qemuarm', 'qemuarm64', 'qemuriscv32', 'qemuriscv64']
> +        machine = get_bb_var('MACHINE')
> +        if machine not in compatible_machines:
> +            self.skipTest('This test only works with machines : %s' % ' '.join(compatible_machines))
> +        self.write_config('TCLIBC = "picolibc"')
> +        bitbake("picolibc-helloworld")
> diff --git a/meta/recipes-core/picolibc/picolibc-helloworld_git.bb b/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
> new file mode 100644
> index 0000000000..573a571c24
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
> @@ -0,0 +1,40 @@
> +require picolibc.inc
> +
> +# baremetal-image overrides
> +BAREMETAL_BINNAME ?= "hello_picolibc_${MACHINE}"
> +IMAGE_LINK_NAME ?= "baremetal-picolibc-image-${MACHINE}"
> +IMAGE_NAME_SUFFIX ?= ""
> +QB_DEFAULT_KERNEL ?= "${IMAGE_LINK_NAME}.elf"
> +
> +inherit baremetal-image
> +
> +COMPATIBLE_MACHINE = "qemuarm|qemuarm64|qemuriscv32|qemuriscv64"
> +
> +# Use semihosting to test via QEMU
> +QB_OPT_APPEND:append = " -semihosting-config enable=on"
> +
> +# picolibc comes with a set of linker scripts, set the file
> +# according to the architecture being built.
> +PICOLIBC_LINKERSCRIPT:qemuarm64 = "aarch64.ld"
> +PICOLIBC_LINKERSCRIPT:qemuarm = "arm.ld"
> +PICOLIBC_LINKERSCRIPT:qemuriscv32 = "riscv.ld"
> +PICOLIBC_LINKERSCRIPT:qemuriscv64 = "riscv.ld"
> +
> +# Simple compile function that manually exemplifies usage; as noted,
> +# use a custom linker script, the GCC specs provided by picolibc
> +# and semihost to be able to test via QEMU's monitor
> +do_compile(){
> +    ${CC} ${CFLAGS} ${LDFLAGS} --verbose -T${S}/hello-world/${PICOLIBC_LINKERSCRIPT} -specs=picolibc.specs --oslib=semihost -o ${BAREMETAL_BINNAME}.elf ${S}/hello-world/hello-world.c
> +    ${OBJCOPY} -O binary ${BAREMETAL_BINNAME}.elf ${BAREMETAL_BINNAME}.bin
> +}
> +
> +do_install(){
> +    install -d ${D}/${base_libdir}/firmware
> +    install -m 755 ${B}/${BAREMETAL_BINNAME}.elf ${D}/${base_libdir}/firmware/${BAREMETAL_BINNAME}.elf
> +    install -m 755 ${B}/${BAREMETAL_BINNAME}.bin ${D}/${base_libdir}/firmware/${BAREMETAL_BINNAME}.bin
> +}
> +
> +FILES:${PN} += " \
> +    ${base_libdir}/firmware/${BAREMETAL_BINNAME}.elf \
> +    ${base_libdir}/firmware/${BAREMETAL_BINNAME}.bin \
> +"
> diff --git a/meta/recipes-core/picolibc/picolibc.inc b/meta/recipes-core/picolibc/picolibc.inc
> new file mode 100644
> index 0000000000..3b380fe7af
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc.inc
> @@ -0,0 +1,21 @@
> +SUMMARY = "C Libraries for Smaller Embedded Systems"
> +HOMEPAGE = "https://keithp.com/picolibc"
> +DESCRIPTION = "Picolibc is a set of standard C libraries, both libc and libm, designed for smaller embedded systems with limited ROM and RAM. Picolibc includes code from Newlib and AVR Libc."
> +SECTION = "libs"
> +
> +# Newlib based code but GPL related bits removed, test/printf-tests.c and test/testcases.c
> +# are GPLv2 and GeneratePicolibcCrossFile.sh is AGPL3 but not part of the artifacts.
> +LICENSE = "BSD-2-Clause & BSD-3-Clause"
> +LIC_FILES_CHKSUM = " \
> +		file://COPYING.GPL2;md5=59530bdf33659b29e73d4adb9f9f6552 \
> +		file://COPYING.NEWLIB;md5=08ae03456feb75b81cfdb359e0f1ef85 \
> +		file://COPYING.picolibc;md5=e50fa9458a40929689861ed472d46bc7 \
> +		"
> +
> +BASEVER = "1.8.6"
> +PV = "${BASEVER}+git"
> +SRC_URI = "git://github.com/picolibc/picolibc.git;protocol=https;branch=main"
> +SRCREV="764ef4e401a8f4c6a86ab723533841f072885a5b"
> +
> +S = "${WORKDIR}/git"
> +B = "${WORKDIR}/build"
> diff --git a/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch b/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> new file mode 100644
> index 0000000000..da6460c95c
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> @@ -0,0 +1,119 @@
> +Upstream-Status: Pending
> +
> +Picolibc uses its own specs file: picolibc.specs to facilitate compilation, this
> +needs to be passed down to GCC via the -specs argument.
> +
> +Using this specs file overrides some of the default options our toolchain was
> +built with, in this case, they modify the include_dir and lib_dir paths used for
> +compilation, their intention was to add support for -picolibc-prefix and
> +-picolibc-buildtype arguments via the C preprocessor.
> +
> +-isystem %{-picolibc-prefix=*:%*/include/; -picolibc-buildtype=*:/usr/include/%*; :/usr/include} %(picolibc_cpp)
> +
> +This had the unwanted effect of defaulting to /usr/include for include_dir if
> +those arguments are not being passed, this works fine for their flow but for us
> +it pollutes the include directories with paths from the host. The same effect is
> +applicable for lib_dir and for the c runtime file.
> +
> +Our toolchain relies on --sysroot to avoid using any paths from the host, here we
> +manually add support for a third possible argument: -sysroot , if this is passed
> +then the paths used by the compiler will be relative to the path passed by the
> +--sysroot= cmdline argument, setting back the behavior that we intended in the
> +first place.
> +
> +
> +Signed-off-by: Alejandro Enedino Hernandez Samaniego <alejandro@enedino.org>
> +
> +Index: git/meson.build
> +===================================================================
> +--- git.orig/meson.build
> ++++ git/meson.build
> +@@ -622,12 +622,13 @@ else
> + #
> + picolibc_prefix_format = '-picolibc-prefix=*:@0@'
> + picolibc_buildtype_format = '-picolibc-buildtype=*:@0@'
> ++sysroot_format = '-sysroot=*:@0@'
> + gen_format = '@0@'
> + 
> + #
> + # How to glue the three options together
> + #
> +-specs_option_format = '%{@0@; @1@; :@2@}'
> ++specs_option_format = '%{@0@; @1@; @2@; :@3@}'
> + 
> + #
> + # Build the -isystem value
> +@@ -639,10 +640,13 @@ isystem_prefix = picolibc_prefix_format.
> + buildtype_include_dir = specs_prefix_format.format(get_option('includedir') / '%*')
> + isystem_buildtype = picolibc_buildtype_format.format(buildtype_include_dir)
> + 
> ++sysroot_include_dir = '%*'
> ++isystem_sysroot = sysroot_format.format(sysroot_include_dir)
> ++
> + gen_include_dir = specs_prefix_format.format(get_option('includedir'))
> + isystem_gen = gen_format.format(gen_include_dir)
> + 
> +-specs_isystem = '-isystem ' + specs_option_format.format(isystem_prefix, isystem_buildtype, isystem_gen)
> ++specs_isystem = '-isystem ' + specs_option_format.format(isystem_prefix, isystem_buildtype, isystem_sysroot, isystem_gen)
> + 
> + #
> + # Build the non-multilib -L value
> +@@ -654,10 +658,13 @@ lib_prefix = picolibc_prefix_format.form
> + buildtype_lib_dir = specs_prefix_format.format(get_option('libdir') / '%*')
> + lib_buildtype = picolibc_buildtype_format.format(buildtype_lib_dir)
> + 
> ++sysroot_lib_dir = '%*'
> ++lib_sysroot = sysroot_format.format(sysroot_lib_dir)
> ++
> + gen_lib_dir = specs_prefix_format.format(get_option('libdir'))
> + lib_gen = gen_format.format(gen_lib_dir)
> + 
> +-specs_libpath = '-L' + specs_option_format.format(lib_prefix, lib_buildtype, lib_gen)
> ++specs_libpath = '-L' + specs_option_format.format(lib_prefix, lib_buildtype, lib_sysroot, lib_gen)
> + 
> + #
> + # Build the non-multilib *startfile options
> +@@ -669,6 +676,9 @@ crt0_prefix = picolibc_prefix_format.for
> + buildtype_crt0_path = specs_prefix_format.format(get_option('libdir') / '%*' / crt0_expr)
> + crt0_buildtype = picolibc_buildtype_format.format(buildtype_crt0_path)
> + 
> ++sysroot_crt0_path = '%*' + '/' + get_option('libdir') + '/' + '%*' + '/' + crt0_expr
> ++crt0_sysroot = picolibc_buildtype_format.format(sysroot_crt0_path)
> ++
> + gen_crt0_path = specs_prefix_format.format(get_option('libdir') / crt0_expr)
> + crt0_gen = gen_format.format(gen_crt0_path)
> + 
> +@@ -686,10 +696,13 @@ if enable_multilib
> +   buildtype_multilib_dir = specs_prefix_format.format(get_option('libdir') / '%*/%M')
> +   multilib_buildtype = picolibc_buildtype_format.format(buildtype_multilib_dir)
> + 
> ++  sysroot_multilib_dir = '%*' + '/' + get_option('libdir') + '/' + '%*/%M'
> ++  multilib_sysroot = sysroot_format.format(sysroot_multilib_dir)
> ++  
> +   gen_multilib_dir = specs_prefix_format.format(get_option('libdir') / '%M')
> +   multilib_gen = gen_format.format(gen_multilib_dir)
> + 
> +-  specs_multilibpath = '-L' + specs_option_format.format(multilib_prefix, multilib_buildtype, multilib_gen)
> ++  specs_multilibpath = '-L' + specs_option_format.format(multilib_prefix, multilib_buildtype, multilib_sysroot, multilib_gen)
> + 
> +   #
> +   # Prepend the multilib -L option to the non-multilib option
> +@@ -705,6 +718,9 @@ if enable_multilib
> +   buildtype_multilib_crt0_path = specs_prefix_format.format(get_option('libdir') / '%*/%M' / crt0_expr)
> +   crt0_buildtype = picolibc_buildtype_format.format(buildtype_multilib_crt0_path)
> + 
> ++  sysroot_multilib_crt0_path = '%*' + prefix + '/' + get_option('libdir') + '/' + '/%M' + '/' + crt0_expr
> ++  crt0_sysroot = sysroot_format.format(sysroot_multilib_crt0_path)
> ++  
> +   gen_multilib_crt0_path = specs_prefix_format.format(get_option('libdir') / '%M' / crt0_expr)
> +   crt0_gen = gen_format.format(gen_multilib_crt0_path)
> + endif
> +@@ -714,7 +730,7 @@ endif
> + # above. As there's only one value, it's either the
> + # multilib path or the non-multilib path
> + #
> +-specs_startfile = specs_option_format.format(crt0_prefix, crt0_buildtype, crt0_gen)
> ++specs_startfile = specs_option_format.format(crt0_prefix, crt0_buildtype, crt0_sysroot, crt0_gen)
> + endif
> + 
> + specs_data = configuration_data()
> diff --git a/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross b/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> new file mode 100644
> index 0000000000..87bfbad3c5
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> @@ -0,0 +1,6 @@
> +# We need to explicitly bypass mesons sanity check to avoid early compiler errors
> +# otherwise meson will try to compile AND run test applications:
> +# ../git/meson.build:35:0: ERROR: Executables created by c compiler are not runnable...
> +
> +[properties]
> +skip_sanity_check=true
> \ No newline at end of file
> diff --git a/meta/recipes-core/picolibc/picolibc_git.bb b/meta/recipes-core/picolibc/picolibc_git.bb
> new file mode 100644
> index 0000000000..fdb159328f
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc_git.bb
> @@ -0,0 +1,35 @@
> +require picolibc.inc
> +
> +INHIBIT_DEFAULT_DEPS = "1"
> +DEPENDS = "virtual/${TARGET_PREFIX}gcc"
> +
> +PROVIDES += "virtual/libc virtual/libiconv virtual/libintl"
> +
> +COMPATIBLE_HOST:libc-musl:class-target = "null"
> +COMPATIBLE_HOST:libc-glibc:class-target = "null"
> +COMPATIBLE_MACHINE = "qemuarm|qemuarm64|qemuriscv32|qemuriscv64"
> +
> +SRC_URI:append = " file://avoid_polluting_cross_directories.patch"
> +SRC_URI:append = " file://no-early-compiler-checks.cross"
> +
> +# This is being added by picolibc meson files as well to avoid
> +# early compiler tests from failing, cant remember why I added it
> +# to the newlib recipe but I would assume it was for the same reason
> +TARGET_CC_ARCH:append = " -nostdlib"
> +
> +# When using RISCV64 use medany for both C library and application recipes
> +TARGET_CFLAGS:append:qemuriscv64 = " -mcmodel=medany"
> +
> +inherit meson
> +
> +MESON_CROSS_FILE:append = " --cross-file=${UNPACKDIR}/no-early-compiler-checks.cross"
> +
> +PACKAGECONFIG ??= " specsdir"
> +# Install GCC specs on libdir
> +PACKAGECONFIG[specsdir] = "-Dspecsdir=${libdir},-Dspecsdir=none"
> +
> +
> +FILES:${PN}-dev:append = " ${libdir}/*.specs ${libdir}/*.ld"
> +
> +# No rpm package is actually created but -dev depends on it, avoid dnf error
> +DEV_PKG_DEPENDENCY:libc-picolibc = ""
> diff --git a/meta/recipes-devtools/gcc/gcc-cross.inc b/meta/recipes-devtools/gcc/gcc-cross.inc
> index 5b0ca15d47..c04177df5a 100644
> --- a/meta/recipes-devtools/gcc/gcc-cross.inc
> +++ b/meta/recipes-devtools/gcc/gcc-cross.inc
> @@ -34,6 +34,7 @@ EXTRA_OECONF += "\
>  EXTRA_OECONF:append:libc-baremetal = " --without-headers"
>  EXTRA_OECONF:remove:libc-baremetal = "--enable-threads=posix"
>  EXTRA_OECONF:remove:libc-newlib = "--enable-threads=posix"
> +EXTRA_OECONF:remove:libc-picolibc = "--enable-threads=posix"
>  
>  EXTRA_OECONF_PATHS = "\
>      --with-gxx-include-dir=/not/exist${target_includedir}/c++/${BINV} \
> diff --git a/meta/recipes-devtools/gcc/gcc-runtime.inc b/meta/recipes-devtools/gcc/gcc-runtime.inc
> index 89b0bebcfb..1fca00f5f0 100644
> --- a/meta/recipes-devtools/gcc/gcc-runtime.inc
> +++ b/meta/recipes-devtools/gcc/gcc-runtime.inc
> @@ -17,6 +17,7 @@ EXTRA_OECONF_PATHS = "\
>  EXTRA_OECONF:append:linuxstdbase = " --enable-clocale=gnu"
>  EXTRA_OECONF:append = " --cache-file=${B}/config.cache"
>  EXTRA_OECONF:append:libc-newlib = " --with-newlib --with-target-subdir"
> +EXTRA_OECONF:append:libc-picolibc = " --with-newlib --with-target-subdir"
>  EXTRA_OECONF:append:libc-baremetal = " --with-target-subdir"
>  
>  # Disable ifuncs for libatomic on arm conflicts -march/-mcpu
> @@ -27,6 +28,7 @@ DISABLE_STATIC:class-nativesdk ?= ""
>  
>  # Newlib does not support symbol versioning on libsdtcc++
>  SYMVERS_CONF:libc-newlib = ""
> +SYMVERS_CONF:libc-picolibc = ""
>  
>  # Building with thumb enabled on armv6t fails
>  ARM_INSTRUCTION_SET:armv6 = "arm"
> @@ -47,6 +49,7 @@ RUNTIMETARGET = "${RUNTIMELIBSSP} libstdc++-v3 libgomp libatomic ${RUNTIMELIBITM
>  "
>  # Only build libstdc++ for newlib
>  RUNTIMETARGET:libc-newlib = "libstdc++-v3"
> +RUNTIMETARGET:libc-picolibc = "libstdc++-v3"
>  
>  # libiberty
>  # libgfortran needs separate recipe due to libquadmath dependency
> diff --git a/meta/recipes-devtools/gcc/libgcc-common.inc b/meta/recipes-devtools/gcc/libgcc-common.inc
> index d9084af51a..e3db17d700 100644
> --- a/meta/recipes-devtools/gcc/libgcc-common.inc
> +++ b/meta/recipes-devtools/gcc/libgcc-common.inc
> @@ -53,6 +53,11 @@ do_install:append:libc-newlib () {
>  		rmdir ${D}${base_libdir}
>  	fi
>  }
> +do_install:append:libc-picolibc () {
> +	if [ "${base_libdir}" != "${libdir}" ]; then
> +		rmdir ${D}${base_libdir}
> +	fi
> +}
>  
>  # No rpm package is actually created but -dev depends on it, avoid dnf error
>  DEV_PKG_DEPENDENCY:libc-baremetal = ""
> -- 
> 2.45.2
> 

> 
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#200882): https://lists.openembedded.org/g/openembedded-core/message/200882
> Mute This Topic: https://lists.openembedded.org/mt/106746173/3617179
> Group Owner: openembedded-core+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [alexandre.belloni@bootlin.com]
> -=-=-=-=-=-=-=-=-=-=-=-
>
Ross Burton June 20, 2024, 4:10 p.m. UTC | #3
> On 19 Jun 2024, at 21:03, Alexandre Belloni via lists.openembedded.org <alexandre.belloni=bootlin.com@lists.openembedded.org> wrote:
> 
> Hello,
> 
> This causes selftest failures:
> 
> https://autobuilder.yoctoproject.org/typhoon/#/builders/80/builds/6833/steps/14/logs/stdio
> https://autobuilder.yoctoproject.org/typhoon/#/builders/79/builds/6877/steps/15/logs/stdio
> https://autobuilder.yoctoproject.org/typhoon/#/builders/86/builds/6902/steps/14/logs/stdio
> https://autobuilder.yoctoproject.org/typhoon/#/builders/87/builds/6888/steps/14/logs/stdio
> https://autobuilder.yoctoproject.org/typhoon/#/builders/127/builds/3495/steps/15/logs/stdio

Those look a lot like they’re Josh’s SPDX changes not this.  Can we pick these back into your master-next branch Alex?

Ross
Alexandre Belloni June 20, 2024, 4:45 p.m. UTC | #4
On 20/06/2024 16:10:41+0000, Ross Burton wrote:
> 
> 
> > On 19 Jun 2024, at 21:03, Alexandre Belloni via lists.openembedded.org <alexandre.belloni=bootlin.com@lists.openembedded.org> wrote:
> > 
> > Hello,
> > 
> > This causes selftest failures:
> > 
> > https://autobuilder.yoctoproject.org/typhoon/#/builders/80/builds/6833/steps/14/logs/stdio
> > https://autobuilder.yoctoproject.org/typhoon/#/builders/79/builds/6877/steps/15/logs/stdio
> > https://autobuilder.yoctoproject.org/typhoon/#/builders/86/builds/6902/steps/14/logs/stdio
> > https://autobuilder.yoctoproject.org/typhoon/#/builders/87/builds/6888/steps/14/logs/stdio
> > https://autobuilder.yoctoproject.org/typhoon/#/builders/127/builds/3495/steps/15/logs/stdio
> 
> Those look a lot like they’re Josh’s SPDX changes not this.  Can we pick these back into your master-next branch Alex?

I can but I never had Josh's changes in my branch so unless this
assumption is that the sstate is poisoned, I'm pretty sure it s caused
by this patch.

This was the only change between
https://autobuilder.yoctoproject.org/typhoon/#/builders/83/builds/7058
and https://autobuilder.yoctoproject.org/typhoon/#/builders/83/builds/7056
Alexandre Belloni June 21, 2024, 7:41 p.m. UTC | #5
On 20/06/2024 18:45:35+0200, Alexandre Belloni via lists.openembedded.org wrote:
> On 20/06/2024 16:10:41+0000, Ross Burton wrote:
> > 
> > 
> > > On 19 Jun 2024, at 21:03, Alexandre Belloni via lists.openembedded.org <alexandre.belloni=bootlin.com@lists.openembedded.org> wrote:
> > > 
> > > Hello,
> > > 
> > > This causes selftest failures:
> > > 
> > > https://autobuilder.yoctoproject.org/typhoon/#/builders/80/builds/6833/steps/14/logs/stdio
> > > https://autobuilder.yoctoproject.org/typhoon/#/builders/79/builds/6877/steps/15/logs/stdio
> > > https://autobuilder.yoctoproject.org/typhoon/#/builders/86/builds/6902/steps/14/logs/stdio
> > > https://autobuilder.yoctoproject.org/typhoon/#/builders/87/builds/6888/steps/14/logs/stdio
> > > https://autobuilder.yoctoproject.org/typhoon/#/builders/127/builds/3495/steps/15/logs/stdio
> > 
> > Those look a lot like they’re Josh’s SPDX changes not this.  Can we pick these back into your master-next branch Alex?
> 
> I can but I never had Josh's changes in my branch so unless this
> assumption is that the sstate is poisoned, I'm pretty sure it s caused
> by this patch.
> 
> This was the only change between
> https://autobuilder.yoctoproject.org/typhoon/#/builders/83/builds/7058
> and https://autobuilder.yoctoproject.org/typhoon/#/builders/83/builds/7056

So, tested v4 of Josh's patches, then I dropped them again, I included
this patch and I got the same failure:

https://autobuilder.yoctoproject.org/typhoon/#/builders/79/builds/6882/steps/14/logs/stdio
https://autobuilder.yoctoproject.org/typhoon/#/builders/80/builds/6838/steps/14/logs/stdio
https://autobuilder.yoctoproject.org/typhoon/#/builders/86/builds/6907/steps/14/logs/stdio
https://autobuilder.yoctoproject.org/typhoon/#/builders/87/builds/6893/steps/14/logs/stdio
https://autobuilder.yoctoproject.org/typhoon/#/builders/127/builds/3503/steps/15/logs/stdio
Ross Burton June 24, 2024, 1:10 p.m. UTC | #6
Can you also add a test case to oe-selftest?

Ross

> On 18 Jun 2024, at 19:12, Alejandro Hernandez Samaniego via lists.openembedded.org <alejandro=enedino.org@lists.openembedded.org> wrote:
> 
> Enables usage of TCLIBC=picolibc extending OE functionality to build and use
> picolibc based toolchains to build baremetal applications.
> 
> Picolibc is a set of standard C libraries, both libc and libm, designed for
> smaller embedded systems with limited ROM and RAM. Picolibc includes code
> from Newlib and AVR Libc, but adresses some of newlibs concerns, it retains
> newlibs directory structure, math, string and locale implementations, but
> removed the GPL bits used to build the library, swiches old C style code for
> C18 and replaces autotools with meson.
> 
> This patch adds a picolibc recipe for the C library, a picolibc-helloworld
> recipe that contains an example application and a testcase that builds it.
> 
> Picolibc can be built for ARM and RISCV architectures, its been tested both
> for 32 and 64 bits, the provided example recipe produces the following output:
> 
> hello, world
> 
> Runqemu does not automatically show any output since it hides QEMU stderr which
> is where the QEMU monitors output is directed to when using semihosting, but,
> manually running the same QEMU command does work properly.
> 
> Signed-off-by: Alejandro Enedino Hernandez Samaniego <alejandro@enedino.org>
> ---
> meta/classes-recipe/baremetal-image.bbclass   |   4 +-
> meta/classes-recipe/cross-canadian.bbclass    |   2 +-
> meta/conf/distro/include/maintainers.inc      |   2 +
> meta/conf/distro/include/tclibc-picolibc.inc  |  40 ++++++
> meta/conf/documentation.conf                  |   2 +-
> .../conf/machine/include/riscv/arch-riscv.inc |   1 +
> meta/lib/oeqa/selftest/cases/distrodata.py    |   2 +-
> meta/lib/oeqa/selftest/cases/picolibc.py      |  18 +++
> .../picolibc/picolibc-helloworld_git.bb       |  40 ++++++
> meta/recipes-core/picolibc/picolibc.inc       |  21 ++++
> .../avoid_polluting_cross_directories.patch   | 119 ++++++++++++++++++
> .../picolibc/no-early-compiler-checks.cross   |   6 +
> meta/recipes-core/picolibc/picolibc_git.bb    |  35 ++++++
> meta/recipes-devtools/gcc/gcc-cross.inc       |   1 +
> meta/recipes-devtools/gcc/gcc-runtime.inc     |   3 +
> meta/recipes-devtools/gcc/libgcc-common.inc   |   5 +
> 16 files changed, 296 insertions(+), 5 deletions(-)
> create mode 100644 meta/conf/distro/include/tclibc-picolibc.inc
> create mode 100644 meta/lib/oeqa/selftest/cases/picolibc.py
> create mode 100644 meta/recipes-core/picolibc/picolibc-helloworld_git.bb
> create mode 100644 meta/recipes-core/picolibc/picolibc.inc
> create mode 100644 meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> create mode 100644 meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> create mode 100644 meta/recipes-core/picolibc/picolibc_git.bb
> 
> diff --git a/meta/classes-recipe/baremetal-image.bbclass b/meta/classes-recipe/baremetal-image.bbclass
> index 4e7d413626..27f2d2d10a 100644
> --- a/meta/classes-recipe/baremetal-image.bbclass
> +++ b/meta/classes-recipe/baremetal-image.bbclass
> @@ -16,8 +16,8 @@
> # See meta-skeleton for a working example.
> 
> 
> -# Toolchain should be baremetal or newlib based.
> -# TCLIBC="baremetal" or TCLIBC="newlib"
> +# Toolchain should be baremetal or newlib/picolibc based.
> +# TCLIBC="baremetal" or TCLIBC="newlib" or TCLIBC="picolibc"
> COMPATIBLE_HOST:libc-musl:class-target = "null"
> COMPATIBLE_HOST:libc-glibc:class-target = "null"
> 
> diff --git a/meta/classes-recipe/cross-canadian.bbclass b/meta/classes-recipe/cross-canadian.bbclass
> index 1670217d69..059d9aa95f 100644
> --- a/meta/classes-recipe/cross-canadian.bbclass
> +++ b/meta/classes-recipe/cross-canadian.bbclass
> @@ -36,7 +36,7 @@ python () {
>     if d.getVar("MODIFYTOS") != "1":
>         return
> 
> -    if d.getVar("TCLIBC") in [ 'baremetal', 'newlib' ]:
> +    if d.getVar("TCLIBC") in [ 'baremetal', 'newlib', 'picolibc' ]:
>         return
> 
>     tos = d.getVar("TARGET_OS")
> diff --git a/meta/conf/distro/include/maintainers.inc b/meta/conf/distro/include/maintainers.inc
> index 42599267c1..ff24597723 100644
> --- a/meta/conf/distro/include/maintainers.inc
> +++ b/meta/conf/distro/include/maintainers.inc
> @@ -578,6 +578,8 @@ RECIPE_MAINTAINER:pn-pcmanfm = "Alexander Kanavin <alex.kanavin@gmail.com>"
> RECIPE_MAINTAINER:pn-perf = "Bruce Ashfield <bruce.ashfield@gmail.com>"
> RECIPE_MAINTAINER:pn-perl = "Alexander Kanavin <alex.kanavin@gmail.com>"
> RECIPE_MAINTAINER:pn-perlcross = "Alexander Kanavin <alex.kanavin@gmail.com>"
> +RECIPE_MAINTAINER:pn-picolibc = "Alejandro Hernandez <alejandro@enedino.org>"
> +RECIPE_MAINTAINER:pn-picolibc-helloworld = "Alejandro Hernandez <alejandro@enedino.org>"
> RECIPE_MAINTAINER:pn-piglit = "Ross Burton <ross.burton@arm.com>"
> RECIPE_MAINTAINER:pn-pigz = "Hongxu Jia <hongxu.jia@windriver.com>"
> RECIPE_MAINTAINER:pn-pinentry = "Unassigned <unassigned@yoctoproject.org>"
> diff --git a/meta/conf/distro/include/tclibc-picolibc.inc b/meta/conf/distro/include/tclibc-picolibc.inc
> new file mode 100644
> index 0000000000..203765dfcb
> --- /dev/null
> +++ b/meta/conf/distro/include/tclibc-picolibc.inc
> @@ -0,0 +1,40 @@
> +#
> +# Picolibc configuration
> +#
> +
> +LIBCEXTENSION = "-picolibc"
> +LIBCOVERRIDE = ":libc-picolibc"
> +
> +PREFERRED_PROVIDER_virtual/libc ?= "picolibc"
> +PREFERRED_PROVIDER_virtual/libiconv ?= "picolibc"
> +PREFERRED_PROVIDER_virtual/libintl ?= "picolibc"
> +PREFERRED_PROVIDER_virtual/nativesdk-libintl ?= "nativesdk-glibc"
> +PREFERRED_PROVIDER_virtual/nativesdk-libiconv ?= "nativesdk-glibc"
> +
> +DISTRO_FEATURES_BACKFILL_CONSIDERED += "ldconfig"
> +
> +IMAGE_LINGUAS = ""
> +
> +LIBC_DEPENDENCIES = " \
> +    picolibc-dbg \
> +    picolibc-dev \
> +    libgcc-dev \
> +    libgcc-dbg \
> +    libstdc++-dev  \
> +    libstdc++-staticdev \
> +"
> +
> +ASSUME_PROVIDED += "virtual/crypt"
> +
> +TARGET_OS = "elf"
> +TARGET_OS:arm = "eabi"
> +
> +TOOLCHAIN_HOST_TASK ?= "packagegroup-cross-canadian-${MACHINE} nativesdk-qemu nativesdk-sdk-provides-dummy"
> +TOOLCHAIN_TARGET_TASK ?= "${LIBC_DEPENDENCIES}"
> +TOOLCHAIN_NEED_CONFIGSITE_CACHE:remove = "zlib ncurses"
> +
> +# RISCV linker doesnt support PIE
> +SECURITY_CFLAGS:libc-picolibc:qemuriscv32 = "${SECURITY_NOPIE_CFLAGS}"
> +SECURITY_CFLAGS:libc-picolibc:qemuriscv64 = "${SECURITY_NOPIE_CFLAGS}"
> +
> +
> diff --git a/meta/conf/documentation.conf b/meta/conf/documentation.conf
> index b0591881ba..ad89142934 100644
> --- a/meta/conf/documentation.conf
> +++ b/meta/conf/documentation.conf
> @@ -421,7 +421,7 @@ TARGET_FPU[doc] = "Specifies the method for handling FPU code. For FPU-less targ
> TARGET_OS[doc] = "Specifies the target's operating system."
> TARGET_PREFIX[doc] = "The prefix for the cross-compile toolchain (e.g. arm-linux-)."
> TARGET_SYS[doc] = "The target system is comprised of TARGET_ARCH,TARGET_VENDOR and TARGET_OS."
> -TCLIBC[doc] = "Specifies C library (libc) variant to use during the build process. You can select 'baremetal', 'glibc', 'musl' or 'newlib'."
> +TCLIBC[doc] = "Specifies C library (libc) variant to use during the build process. You can select 'baremetal', 'glibc', 'musl', 'newlib', or 'picolibc'."
> TCMODE[doc] = "Enables an external toolchain (where provided by an additional layer) if set to a value other than 'default'."
> TESTIMAGE_AUTO[doc] = "Enables test booting of virtual machine images under the QEMU emulator after any root filesystems are created and runs tests against those images each time an image is built."
> TEST_QEMUBOOT_TIMEOUT[doc] = "The time in seconds allowed for an image to boot before automated runtime tests begin to run against an image."
> diff --git a/meta/conf/machine/include/riscv/arch-riscv.inc b/meta/conf/machine/include/riscv/arch-riscv.inc
> index 230a266563..b34064e78f 100644
> --- a/meta/conf/machine/include/riscv/arch-riscv.inc
> +++ b/meta/conf/machine/include/riscv/arch-riscv.inc
> @@ -11,5 +11,6 @@ TUNE_CCARGS:append = "${@bb.utils.contains('TUNE_FEATURES', 'riscv64nc', ' -marc
> 
> # Fix: ld: unrecognized option '--hash-style=sysv'
> LINKER_HASH_STYLE:libc-newlib = ""
> +LINKER_HASH_STYLE:libc-picolibc = ""
> # Fix: ld: unrecognized option '--hash-style=gnu'
> LINKER_HASH_STYLE:libc-baremetal = ""
> diff --git a/meta/lib/oeqa/selftest/cases/distrodata.py b/meta/lib/oeqa/selftest/cases/distrodata.py
> index ad952c004b..043953757f 100644
> --- a/meta/lib/oeqa/selftest/cases/distrodata.py
> +++ b/meta/lib/oeqa/selftest/cases/distrodata.py
> @@ -55,7 +55,7 @@ but their recipes claim otherwise by setting UPSTREAM_VERSION_UNKNOWN. Please re
>             return False
> 
>         def is_maintainer_exception(entry):
> -            exceptions = ["musl", "newlib", "linux-yocto", "linux-dummy", "mesa-gl", "libgfortran", "libx11-compose-data",
> +            exceptions = ["musl", "newlib", "picolibc", "linux-yocto", "linux-dummy", "mesa-gl", "libgfortran", "libx11-compose-data",
>                           "cve-update-nvd2-native",]
>             for i in exceptions:
>                  if i in entry:
> diff --git a/meta/lib/oeqa/selftest/cases/picolibc.py b/meta/lib/oeqa/selftest/cases/picolibc.py
> new file mode 100644
> index 0000000000..e40b4fc3d3
> --- /dev/null
> +++ b/meta/lib/oeqa/selftest/cases/picolibc.py
> @@ -0,0 +1,18 @@
> +#
> +# Copyright OpenEmbedded Contributors
> +#
> +# SPDX-License-Identifier: MIT
> +#
> +
> +from oeqa.selftest.case import OESelftestTestCase
> +from oeqa.utils.commands import bitbake, get_bb_var
> +
> +class PicolibcTest(OESelftestTestCase):
> +
> +    def test_picolibc(self):
> +        compatible_machines = ['qemuarm', 'qemuarm64', 'qemuriscv32', 'qemuriscv64']
> +        machine = get_bb_var('MACHINE')
> +        if machine not in compatible_machines:
> +            self.skipTest('This test only works with machines : %s' % ' '.join(compatible_machines))
> +        self.write_config('TCLIBC = "picolibc"')
> +        bitbake("picolibc-helloworld")
> diff --git a/meta/recipes-core/picolibc/picolibc-helloworld_git.bb b/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
> new file mode 100644
> index 0000000000..573a571c24
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
> @@ -0,0 +1,40 @@
> +require picolibc.inc
> +
> +# baremetal-image overrides
> +BAREMETAL_BINNAME ?= "hello_picolibc_${MACHINE}"
> +IMAGE_LINK_NAME ?= "baremetal-picolibc-image-${MACHINE}"
> +IMAGE_NAME_SUFFIX ?= ""
> +QB_DEFAULT_KERNEL ?= "${IMAGE_LINK_NAME}.elf"
> +
> +inherit baremetal-image
> +
> +COMPATIBLE_MACHINE = "qemuarm|qemuarm64|qemuriscv32|qemuriscv64"
> +
> +# Use semihosting to test via QEMU
> +QB_OPT_APPEND:append = " -semihosting-config enable=on"
> +
> +# picolibc comes with a set of linker scripts, set the file
> +# according to the architecture being built.
> +PICOLIBC_LINKERSCRIPT:qemuarm64 = "aarch64.ld"
> +PICOLIBC_LINKERSCRIPT:qemuarm = "arm.ld"
> +PICOLIBC_LINKERSCRIPT:qemuriscv32 = "riscv.ld"
> +PICOLIBC_LINKERSCRIPT:qemuriscv64 = "riscv.ld"
> +
> +# Simple compile function that manually exemplifies usage; as noted,
> +# use a custom linker script, the GCC specs provided by picolibc
> +# and semihost to be able to test via QEMU's monitor
> +do_compile(){
> +    ${CC} ${CFLAGS} ${LDFLAGS} --verbose -T${S}/hello-world/${PICOLIBC_LINKERSCRIPT} -specs=picolibc.specs --oslib=semihost -o ${BAREMETAL_BINNAME}.elf ${S}/hello-world/hello-world.c
> +    ${OBJCOPY} -O binary ${BAREMETAL_BINNAME}.elf ${BAREMETAL_BINNAME}.bin
> +}
> +
> +do_install(){
> +    install -d ${D}/${base_libdir}/firmware
> +    install -m 755 ${B}/${BAREMETAL_BINNAME}.elf ${D}/${base_libdir}/firmware/${BAREMETAL_BINNAME}.elf
> +    install -m 755 ${B}/${BAREMETAL_BINNAME}.bin ${D}/${base_libdir}/firmware/${BAREMETAL_BINNAME}.bin
> +}
> +
> +FILES:${PN} += " \
> +    ${base_libdir}/firmware/${BAREMETAL_BINNAME}.elf \
> +    ${base_libdir}/firmware/${BAREMETAL_BINNAME}.bin \
> +"
> diff --git a/meta/recipes-core/picolibc/picolibc.inc b/meta/recipes-core/picolibc/picolibc.inc
> new file mode 100644
> index 0000000000..3b380fe7af
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc.inc
> @@ -0,0 +1,21 @@
> +SUMMARY = "C Libraries for Smaller Embedded Systems"
> +HOMEPAGE = "https://keithp.com/picolibc"
> +DESCRIPTION = "Picolibc is a set of standard C libraries, both libc and libm, designed for smaller embedded systems with limited ROM and RAM. Picolibc includes code from Newlib and AVR Libc."
> +SECTION = "libs"
> +
> +# Newlib based code but GPL related bits removed, test/printf-tests.c and test/testcases.c
> +# are GPLv2 and GeneratePicolibcCrossFile.sh is AGPL3 but not part of the artifacts.
> +LICENSE = "BSD-2-Clause & BSD-3-Clause"
> +LIC_FILES_CHKSUM = " \
> + file://COPYING.GPL2;md5=59530bdf33659b29e73d4adb9f9f6552 \
> + file://COPYING.NEWLIB;md5=08ae03456feb75b81cfdb359e0f1ef85 \
> + file://COPYING.picolibc;md5=e50fa9458a40929689861ed472d46bc7 \
> + "
> +
> +BASEVER = "1.8.6"
> +PV = "${BASEVER}+git"
> +SRC_URI = "git://github.com/picolibc/picolibc.git;protocol=https;branch=main"
> +SRCREV="764ef4e401a8f4c6a86ab723533841f072885a5b"
> +
> +S = "${WORKDIR}/git"
> +B = "${WORKDIR}/build"
> diff --git a/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch b/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> new file mode 100644
> index 0000000000..da6460c95c
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> @@ -0,0 +1,119 @@
> +Upstream-Status: Pending
> +
> +Picolibc uses its own specs file: picolibc.specs to facilitate compilation, this
> +needs to be passed down to GCC via the -specs argument.
> +
> +Using this specs file overrides some of the default options our toolchain was
> +built with, in this case, they modify the include_dir and lib_dir paths used for
> +compilation, their intention was to add support for -picolibc-prefix and
> +-picolibc-buildtype arguments via the C preprocessor.
> +
> +-isystem %{-picolibc-prefix=*:%*/include/; -picolibc-buildtype=*:/usr/include/%*; :/usr/include} %(picolibc_cpp)
> +
> +This had the unwanted effect of defaulting to /usr/include for include_dir if
> +those arguments are not being passed, this works fine for their flow but for us
> +it pollutes the include directories with paths from the host. The same effect is
> +applicable for lib_dir and for the c runtime file.
> +
> +Our toolchain relies on --sysroot to avoid using any paths from the host, here we
> +manually add support for a third possible argument: -sysroot , if this is passed
> +then the paths used by the compiler will be relative to the path passed by the
> +--sysroot= cmdline argument, setting back the behavior that we intended in the
> +first place.
> +
> +
> +Signed-off-by: Alejandro Enedino Hernandez Samaniego <alejandro@enedino.org>
> +
> +Index: git/meson.build
> +===================================================================
> +--- git.orig/meson.build
> ++++ git/meson.build
> +@@ -622,12 +622,13 @@ else
> + #
> + picolibc_prefix_format = '-picolibc-prefix=*:@0@'
> + picolibc_buildtype_format = '-picolibc-buildtype=*:@0@'
> ++sysroot_format = '-sysroot=*:@0@'
> + gen_format = '@0@'
> + 
> + #
> + # How to glue the three options together
> + #
> +-specs_option_format = '%{@0@; @1@; :@2@}'
> ++specs_option_format = '%{@0@; @1@; @2@; :@3@}'
> + 
> + #
> + # Build the -isystem value
> +@@ -639,10 +640,13 @@ isystem_prefix = picolibc_prefix_format.
> + buildtype_include_dir = specs_prefix_format.format(get_option('includedir') / '%*')
> + isystem_buildtype = picolibc_buildtype_format.format(buildtype_include_dir)
> + 
> ++sysroot_include_dir = '%*'
> ++isystem_sysroot = sysroot_format.format(sysroot_include_dir)
> ++
> + gen_include_dir = specs_prefix_format.format(get_option('includedir'))
> + isystem_gen = gen_format.format(gen_include_dir)
> + 
> +-specs_isystem = '-isystem ' + specs_option_format.format(isystem_prefix, isystem_buildtype, isystem_gen)
> ++specs_isystem = '-isystem ' + specs_option_format.format(isystem_prefix, isystem_buildtype, isystem_sysroot, isystem_gen)
> + 
> + #
> + # Build the non-multilib -L value
> +@@ -654,10 +658,13 @@ lib_prefix = picolibc_prefix_format.form
> + buildtype_lib_dir = specs_prefix_format.format(get_option('libdir') / '%*')
> + lib_buildtype = picolibc_buildtype_format.format(buildtype_lib_dir)
> + 
> ++sysroot_lib_dir = '%*'
> ++lib_sysroot = sysroot_format.format(sysroot_lib_dir)
> ++
> + gen_lib_dir = specs_prefix_format.format(get_option('libdir'))
> + lib_gen = gen_format.format(gen_lib_dir)
> + 
> +-specs_libpath = '-L' + specs_option_format.format(lib_prefix, lib_buildtype, lib_gen)
> ++specs_libpath = '-L' + specs_option_format.format(lib_prefix, lib_buildtype, lib_sysroot, lib_gen)
> + 
> + #
> + # Build the non-multilib *startfile options
> +@@ -669,6 +676,9 @@ crt0_prefix = picolibc_prefix_format.for
> + buildtype_crt0_path = specs_prefix_format.format(get_option('libdir') / '%*' / crt0_expr)
> + crt0_buildtype = picolibc_buildtype_format.format(buildtype_crt0_path)
> + 
> ++sysroot_crt0_path = '%*' + '/' + get_option('libdir') + '/' + '%*' + '/' + crt0_expr
> ++crt0_sysroot = picolibc_buildtype_format.format(sysroot_crt0_path)
> ++
> + gen_crt0_path = specs_prefix_format.format(get_option('libdir') / crt0_expr)
> + crt0_gen = gen_format.format(gen_crt0_path)
> + 
> +@@ -686,10 +696,13 @@ if enable_multilib
> +   buildtype_multilib_dir = specs_prefix_format.format(get_option('libdir') / '%*/%M')
> +   multilib_buildtype = picolibc_buildtype_format.format(buildtype_multilib_dir)
> + 
> ++  sysroot_multilib_dir = '%*' + '/' + get_option('libdir') + '/' + '%*/%M'
> ++  multilib_sysroot = sysroot_format.format(sysroot_multilib_dir)
> ++  
> +   gen_multilib_dir = specs_prefix_format.format(get_option('libdir') / '%M')
> +   multilib_gen = gen_format.format(gen_multilib_dir)
> + 
> +-  specs_multilibpath = '-L' + specs_option_format.format(multilib_prefix, multilib_buildtype, multilib_gen)
> ++  specs_multilibpath = '-L' + specs_option_format.format(multilib_prefix, multilib_buildtype, multilib_sysroot, multilib_gen)
> + 
> +   #
> +   # Prepend the multilib -L option to the non-multilib option
> +@@ -705,6 +718,9 @@ if enable_multilib
> +   buildtype_multilib_crt0_path = specs_prefix_format.format(get_option('libdir') / '%*/%M' / crt0_expr)
> +   crt0_buildtype = picolibc_buildtype_format.format(buildtype_multilib_crt0_path)
> + 
> ++  sysroot_multilib_crt0_path = '%*' + prefix + '/' + get_option('libdir') + '/' + '/%M' + '/' + crt0_expr
> ++  crt0_sysroot = sysroot_format.format(sysroot_multilib_crt0_path)
> ++  
> +   gen_multilib_crt0_path = specs_prefix_format.format(get_option('libdir') / '%M' / crt0_expr)
> +   crt0_gen = gen_format.format(gen_multilib_crt0_path)
> + endif
> +@@ -714,7 +730,7 @@ endif
> + # above. As there's only one value, it's either the
> + # multilib path or the non-multilib path
> + #
> +-specs_startfile = specs_option_format.format(crt0_prefix, crt0_buildtype, crt0_gen)
> ++specs_startfile = specs_option_format.format(crt0_prefix, crt0_buildtype, crt0_sysroot, crt0_gen)
> + endif
> + 
> + specs_data = configuration_data()
> diff --git a/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross b/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> new file mode 100644
> index 0000000000..87bfbad3c5
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> @@ -0,0 +1,6 @@
> +# We need to explicitly bypass mesons sanity check to avoid early compiler errors
> +# otherwise meson will try to compile AND run test applications:
> +# ../git/meson.build:35:0: ERROR: Executables created by c compiler are not runnable...
> +
> +[properties]
> +skip_sanity_check=true
> \ No newline at end of file
> diff --git a/meta/recipes-core/picolibc/picolibc_git.bb b/meta/recipes-core/picolibc/picolibc_git.bb
> new file mode 100644
> index 0000000000..fdb159328f
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc_git.bb
> @@ -0,0 +1,35 @@
> +require picolibc.inc
> +
> +INHIBIT_DEFAULT_DEPS = "1"
> +DEPENDS = "virtual/${TARGET_PREFIX}gcc"
> +
> +PROVIDES += "virtual/libc virtual/libiconv virtual/libintl"
> +
> +COMPATIBLE_HOST:libc-musl:class-target = "null"
> +COMPATIBLE_HOST:libc-glibc:class-target = "null"
> +COMPATIBLE_MACHINE = "qemuarm|qemuarm64|qemuriscv32|qemuriscv64"
> +
> +SRC_URI:append = " file://avoid_polluting_cross_directories.patch"
> +SRC_URI:append = " file://no-early-compiler-checks.cross"
> +
> +# This is being added by picolibc meson files as well to avoid
> +# early compiler tests from failing, cant remember why I added it
> +# to the newlib recipe but I would assume it was for the same reason
> +TARGET_CC_ARCH:append = " -nostdlib"
> +
> +# When using RISCV64 use medany for both C library and application recipes
> +TARGET_CFLAGS:append:qemuriscv64 = " -mcmodel=medany"
> +
> +inherit meson
> +
> +MESON_CROSS_FILE:append = " --cross-file=${UNPACKDIR}/no-early-compiler-checks.cross"
> +
> +PACKAGECONFIG ??= " specsdir"
> +# Install GCC specs on libdir
> +PACKAGECONFIG[specsdir] = "-Dspecsdir=${libdir},-Dspecsdir=none"
> +
> +
> +FILES:${PN}-dev:append = " ${libdir}/*.specs ${libdir}/*.ld"
> +
> +# No rpm package is actually created but -dev depends on it, avoid dnf error
> +DEV_PKG_DEPENDENCY:libc-picolibc = ""
> diff --git a/meta/recipes-devtools/gcc/gcc-cross.inc b/meta/recipes-devtools/gcc/gcc-cross.inc
> index 5b0ca15d47..c04177df5a 100644
> --- a/meta/recipes-devtools/gcc/gcc-cross.inc
> +++ b/meta/recipes-devtools/gcc/gcc-cross.inc
> @@ -34,6 +34,7 @@ EXTRA_OECONF += "\
> EXTRA_OECONF:append:libc-baremetal = " --without-headers"
> EXTRA_OECONF:remove:libc-baremetal = "--enable-threads=posix"
> EXTRA_OECONF:remove:libc-newlib = "--enable-threads=posix"
> +EXTRA_OECONF:remove:libc-picolibc = "--enable-threads=posix"
> 
> EXTRA_OECONF_PATHS = "\
>     --with-gxx-include-dir=/not/exist${target_includedir}/c++/${BINV} \
> diff --git a/meta/recipes-devtools/gcc/gcc-runtime.inc b/meta/recipes-devtools/gcc/gcc-runtime.inc
> index 89b0bebcfb..1fca00f5f0 100644
> --- a/meta/recipes-devtools/gcc/gcc-runtime.inc
> +++ b/meta/recipes-devtools/gcc/gcc-runtime.inc
> @@ -17,6 +17,7 @@ EXTRA_OECONF_PATHS = "\
> EXTRA_OECONF:append:linuxstdbase = " --enable-clocale=gnu"
> EXTRA_OECONF:append = " --cache-file=${B}/config.cache"
> EXTRA_OECONF:append:libc-newlib = " --with-newlib --with-target-subdir"
> +EXTRA_OECONF:append:libc-picolibc = " --with-newlib --with-target-subdir"
> EXTRA_OECONF:append:libc-baremetal = " --with-target-subdir"
> 
> # Disable ifuncs for libatomic on arm conflicts -march/-mcpu
> @@ -27,6 +28,7 @@ DISABLE_STATIC:class-nativesdk ?= ""
> 
> # Newlib does not support symbol versioning on libsdtcc++
> SYMVERS_CONF:libc-newlib = ""
> +SYMVERS_CONF:libc-picolibc = ""
> 
> # Building with thumb enabled on armv6t fails
> ARM_INSTRUCTION_SET:armv6 = "arm"
> @@ -47,6 +49,7 @@ RUNTIMETARGET = "${RUNTIMELIBSSP} libstdc++-v3 libgomp libatomic ${RUNTIMELIBITM
> "
> # Only build libstdc++ for newlib
> RUNTIMETARGET:libc-newlib = "libstdc++-v3"
> +RUNTIMETARGET:libc-picolibc = "libstdc++-v3"
> 
> # libiberty
> # libgfortran needs separate recipe due to libquadmath dependency
> diff --git a/meta/recipes-devtools/gcc/libgcc-common.inc b/meta/recipes-devtools/gcc/libgcc-common.inc
> index d9084af51a..e3db17d700 100644
> --- a/meta/recipes-devtools/gcc/libgcc-common.inc
> +++ b/meta/recipes-devtools/gcc/libgcc-common.inc
> @@ -53,6 +53,11 @@ do_install:append:libc-newlib () {
> rmdir ${D}${base_libdir}
> fi
> }
> +do_install:append:libc-picolibc () {
> + if [ "${base_libdir}" != "${libdir}" ]; then
> + rmdir ${D}${base_libdir}
> + fi
> +}
> 
> # No rpm package is actually created but -dev depends on it, avoid dnf error
> DEV_PKG_DEPENDENCY:libc-baremetal = ""
> -- 
> 2.45.2
> 
> 
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#200882): https://lists.openembedded.org/g/openembedded-core/message/200882
> Mute This Topic: https://lists.openembedded.org/mt/106746173/6875888
> Group Owner: openembedded-core+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [ross.burton@arm.com]
> -=-=-=-=-=-=-=-=-=-=-=-
>
Alejandro Enedino Hernandez Samaniego June 24, 2024, 5:27 p.m. UTC | #7
On Mon, 24 Jun 2024 at 07:10, Ross Burton <Ross.Burton@arm.com> wrote:

> Can you also add a test case to oe-selftest?
>
> Ross
>

Hi Ross,

An oe-selftest test case is already included on this patch:
> meta/lib/oeqa/selftest/cases/picolibc.py      |  18 +++

oe-selftest - INFO - RESULTS - picolibc.PicolibcTest.test_picolibc: PASSED

This test case actually passed on the Autobuilder runs. I can add an extra
case if thats what you're referring to, but what would you want me to test?
.


While I don't see how this can be related to base-files/spdx, I'm open to
the possibility that there's something wrong with the patch so
I've been trying to reproduce the spdx test case issue but its been passing
for me:
2024-06-20 09:17:28,571 - oe-selftest - INFO -
spdx.SPDXCheck.test_spdx_base_files (subunit.RemotedTestCase)
2024-06-20 09:17:28,572 - oe-selftest - INFO -  ... ok
2024-06-20 09:17:28,573 - oe-selftest - INFO - 0: 1/1 1/1 (61.85s) (0
failed) (spdx.SPDXCheck.test_spdx_base_files)
2024-06-20 09:17:34,072 - oe-selftest - INFO - RESULTS -
spdx.SPDXCheck.test_spdx_base_files: PASSED (61.86s)

The spdx case executes create_spdx for base-files and then checks for the
existence of the base-files.spdx.json file in the deploy/spdx directory.
Here's the output of such directory:
ls -l
../qemuarm64-st-*/tmp/deploy/spdx/2.2/qemuarm64/packages/base-files.spdx.json

-rw-r--r-- 2 user user 8667 Jun 19 20:12
../qemuarm64-st-4129739/tmp/deploy/spdx/2.2/qemuarm64/packages/base-files.spdx.json
-rw-r--r-- 2 user user 8667 Jun 19 23:46
../qemuarm64-st-4129745/tmp/deploy/spdx/2.2/qemuarm64/packages/base-files.spdx.json
-rw-r--r-- 2 user user 8667 Jun 19 17:36
../qemuarm64-st-4129747/tmp/deploy/spdx/2.2/qemuarm64/packages/base-files.spdx.json
-rw-r--r-- 2 user user 8667 Jun 20 05:38
../qemuarm64-st-4129751/tmp/deploy/spdx/2.2/qemuarm64/packages/base-files.spdx.json
-rw-r--r-- 2 user user 8667 Jun 19 17:36
../qemuarm64-st-4129773/tmp/deploy/spdx/2.2/qemuarm64/packages/base-files.spdx.json
-rw-r--r-- 2 user user 8667 Jun 19 17:36
../qemuarm64-st-4129779/tmp/deploy/spdx/2.2/qemuarm64/packages/base-files.spdx.json

So, on my runs, the file is present every time I ran the test case.

I would like to help, but I simply don't know what else I could change to
be able to reproduce the issue, is there a way to make sure that the
sstate isnt being polluted?

Alejandro



>
> > On 18 Jun 2024, at 19:12, Alejandro Hernandez Samaniego via
> lists.openembedded.org <alejandro=enedino.org@lists.openembedded.org>
> wrote:
> >
> > Enables usage of TCLIBC=picolibc extending OE functionality to build and
> use
> > picolibc based toolchains to build baremetal applications.
> >
> > Picolibc is a set of standard C libraries, both libc and libm, designed
> for
> > smaller embedded systems with limited ROM and RAM. Picolibc includes code
> > from Newlib and AVR Libc, but adresses some of newlibs concerns, it
> retains
> > newlibs directory structure, math, string and locale implementations, but
> > removed the GPL bits used to build the library, swiches old C style code
> for
> > C18 and replaces autotools with meson.
> >
> > This patch adds a picolibc recipe for the C library, a
> picolibc-helloworld
> > recipe that contains an example application and a testcase that builds
> it.
> >
> > Picolibc can be built for ARM and RISCV architectures, its been tested
> both
> > for 32 and 64 bits, the provided example recipe produces the following
> output:
> >
> > hello, world
> >
> > Runqemu does not automatically show any output since it hides QEMU
> stderr which
> > is where the QEMU monitors output is directed to when using semihosting,
> but,
> > manually running the same QEMU command does work properly.
> >
> > Signed-off-by: Alejandro Enedino Hernandez Samaniego <
> alejandro@enedino.org>
> > ---
> > meta/classes-recipe/baremetal-image.bbclass   |   4 +-
> > meta/classes-recipe/cross-canadian.bbclass    |   2 +-
> > meta/conf/distro/include/maintainers.inc      |   2 +
> > meta/conf/distro/include/tclibc-picolibc.inc  |  40 ++++++
> > meta/conf/documentation.conf                  |   2 +-
> > .../conf/machine/include/riscv/arch-riscv.inc |   1 +
> > meta/lib/oeqa/selftest/cases/distrodata.py    |   2 +-
> > meta/lib/oeqa/selftest/cases/picolibc.py      |  18 +++
> > .../picolibc/picolibc-helloworld_git.bb       |  40 ++++++
> > meta/recipes-core/picolibc/picolibc.inc       |  21 ++++
> > .../avoid_polluting_cross_directories.patch   | 119 ++++++++++++++++++
> > .../picolibc/no-early-compiler-checks.cross   |   6 +
> > meta/recipes-core/picolibc/picolibc_git.bb    |  35 ++++++
> > meta/recipes-devtools/gcc/gcc-cross.inc       |   1 +
> > meta/recipes-devtools/gcc/gcc-runtime.inc     |   3 +
> > meta/recipes-devtools/gcc/libgcc-common.inc   |   5 +
> > 16 files changed, 296 insertions(+), 5 deletions(-)
> > create mode 100644 meta/conf/distro/include/tclibc-picolibc.inc
> > create mode 100644 meta/lib/oeqa/selftest/cases/picolibc.py
> > create mode 100644 meta/recipes-core/picolibc/picolibc-helloworld_git.bb
> > create mode 100644 meta/recipes-core/picolibc/picolibc.inc
> > create mode 100644
> meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> > create mode 100644
> meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> > create mode 100644 meta/recipes-core/picolibc/picolibc_git.bb
> >
> > diff --git a/meta/classes-recipe/baremetal-image.bbclass
> b/meta/classes-recipe/baremetal-image.bbclass
> > index 4e7d413626..27f2d2d10a 100644
> > --- a/meta/classes-recipe/baremetal-image.bbclass
> > +++ b/meta/classes-recipe/baremetal-image.bbclass
> > @@ -16,8 +16,8 @@
> > # See meta-skeleton for a working example.
> >
> >
> > -# Toolchain should be baremetal or newlib based.
> > -# TCLIBC="baremetal" or TCLIBC="newlib"
> > +# Toolchain should be baremetal or newlib/picolibc based.
> > +# TCLIBC="baremetal" or TCLIBC="newlib" or TCLIBC="picolibc"
> > COMPATIBLE_HOST:libc-musl:class-target = "null"
> > COMPATIBLE_HOST:libc-glibc:class-target = "null"
> >
> > diff --git a/meta/classes-recipe/cross-canadian.bbclass
> b/meta/classes-recipe/cross-canadian.bbclass
> > index 1670217d69..059d9aa95f 100644
> > --- a/meta/classes-recipe/cross-canadian.bbclass
> > +++ b/meta/classes-recipe/cross-canadian.bbclass
> > @@ -36,7 +36,7 @@ python () {
> >     if d.getVar("MODIFYTOS") != "1":
> >         return
> >
> > -    if d.getVar("TCLIBC") in [ 'baremetal', 'newlib' ]:
> > +    if d.getVar("TCLIBC") in [ 'baremetal', 'newlib', 'picolibc' ]:
> >         return
> >
> >     tos = d.getVar("TARGET_OS")
> > diff --git a/meta/conf/distro/include/maintainers.inc
> b/meta/conf/distro/include/maintainers.inc
> > index 42599267c1..ff24597723 100644
> > --- a/meta/conf/distro/include/maintainers.inc
> > +++ b/meta/conf/distro/include/maintainers.inc
> > @@ -578,6 +578,8 @@ RECIPE_MAINTAINER:pn-pcmanfm = "Alexander Kanavin <
> alex.kanavin@gmail.com>"
> > RECIPE_MAINTAINER:pn-perf = "Bruce Ashfield <bruce.ashfield@gmail.com>"
> > RECIPE_MAINTAINER:pn-perl = "Alexander Kanavin <alex.kanavin@gmail.com>"
> > RECIPE_MAINTAINER:pn-perlcross = "Alexander Kanavin <
> alex.kanavin@gmail.com>"
> > +RECIPE_MAINTAINER:pn-picolibc = "Alejandro Hernandez <
> alejandro@enedino.org>"
> > +RECIPE_MAINTAINER:pn-picolibc-helloworld = "Alejandro Hernandez <
> alejandro@enedino.org>"
> > RECIPE_MAINTAINER:pn-piglit = "Ross Burton <ross.burton@arm.com>"
> > RECIPE_MAINTAINER:pn-pigz = "Hongxu Jia <hongxu.jia@windriver.com>"
> > RECIPE_MAINTAINER:pn-pinentry = "Unassigned <unassigned@yoctoproject.org
> >"
> > diff --git a/meta/conf/distro/include/tclibc-picolibc.inc
> b/meta/conf/distro/include/tclibc-picolibc.inc
> > new file mode 100644
> > index 0000000000..203765dfcb
> > --- /dev/null
> > +++ b/meta/conf/distro/include/tclibc-picolibc.inc
> > @@ -0,0 +1,40 @@
> > +#
> > +# Picolibc configuration
> > +#
> > +
> > +LIBCEXTENSION = "-picolibc"
> > +LIBCOVERRIDE = ":libc-picolibc"
> > +
> > +PREFERRED_PROVIDER_virtual/libc ?= "picolibc"
> > +PREFERRED_PROVIDER_virtual/libiconv ?= "picolibc"
> > +PREFERRED_PROVIDER_virtual/libintl ?= "picolibc"
> > +PREFERRED_PROVIDER_virtual/nativesdk-libintl ?= "nativesdk-glibc"
> > +PREFERRED_PROVIDER_virtual/nativesdk-libiconv ?= "nativesdk-glibc"
> > +
> > +DISTRO_FEATURES_BACKFILL_CONSIDERED += "ldconfig"
> > +
> > +IMAGE_LINGUAS = ""
> > +
> > +LIBC_DEPENDENCIES = " \
> > +    picolibc-dbg \
> > +    picolibc-dev \
> > +    libgcc-dev \
> > +    libgcc-dbg \
> > +    libstdc++-dev  \
> > +    libstdc++-staticdev \
> > +"
> > +
> > +ASSUME_PROVIDED += "virtual/crypt"
> > +
> > +TARGET_OS = "elf"
> > +TARGET_OS:arm = "eabi"
> > +
> > +TOOLCHAIN_HOST_TASK ?= "packagegroup-cross-canadian-${MACHINE}
> nativesdk-qemu nativesdk-sdk-provides-dummy"
> > +TOOLCHAIN_TARGET_TASK ?= "${LIBC_DEPENDENCIES}"
> > +TOOLCHAIN_NEED_CONFIGSITE_CACHE:remove = "zlib ncurses"
> > +
> > +# RISCV linker doesnt support PIE
> > +SECURITY_CFLAGS:libc-picolibc:qemuriscv32 = "${SECURITY_NOPIE_CFLAGS}"
> > +SECURITY_CFLAGS:libc-picolibc:qemuriscv64 = "${SECURITY_NOPIE_CFLAGS}"
> > +
> > +
> > diff --git a/meta/conf/documentation.conf b/meta/conf/documentation.conf
> > index b0591881ba..ad89142934 100644
> > --- a/meta/conf/documentation.conf
> > +++ b/meta/conf/documentation.conf
> > @@ -421,7 +421,7 @@ TARGET_FPU[doc] = "Specifies the method for handling
> FPU code. For FPU-less targ
> > TARGET_OS[doc] = "Specifies the target's operating system."
> > TARGET_PREFIX[doc] = "The prefix for the cross-compile toolchain (e.g.
> arm-linux-)."
> > TARGET_SYS[doc] = "The target system is comprised of
> TARGET_ARCH,TARGET_VENDOR and TARGET_OS."
> > -TCLIBC[doc] = "Specifies C library (libc) variant to use during the
> build process. You can select 'baremetal', 'glibc', 'musl' or 'newlib'."
> > +TCLIBC[doc] = "Specifies C library (libc) variant to use during the
> build process. You can select 'baremetal', 'glibc', 'musl', 'newlib', or
> 'picolibc'."
> > TCMODE[doc] = "Enables an external toolchain (where provided by an
> additional layer) if set to a value other than 'default'."
> > TESTIMAGE_AUTO[doc] = "Enables test booting of virtual machine images
> under the QEMU emulator after any root filesystems are created and runs
> tests against those images each time an image is built."
> > TEST_QEMUBOOT_TIMEOUT[doc] = "The time in seconds allowed for an image
> to boot before automated runtime tests begin to run against an image."
> > diff --git a/meta/conf/machine/include/riscv/arch-riscv.inc
> b/meta/conf/machine/include/riscv/arch-riscv.inc
> > index 230a266563..b34064e78f 100644
> > --- a/meta/conf/machine/include/riscv/arch-riscv.inc
> > +++ b/meta/conf/machine/include/riscv/arch-riscv.inc
> > @@ -11,5 +11,6 @@ TUNE_CCARGS:append =
> "${@bb.utils.contains('TUNE_FEATURES', 'riscv64nc', ' -marc
> >
> > # Fix: ld: unrecognized option '--hash-style=sysv'
> > LINKER_HASH_STYLE:libc-newlib = ""
> > +LINKER_HASH_STYLE:libc-picolibc = ""
> > # Fix: ld: unrecognized option '--hash-style=gnu'
> > LINKER_HASH_STYLE:libc-baremetal = ""
> > diff --git a/meta/lib/oeqa/selftest/cases/distrodata.py
> b/meta/lib/oeqa/selftest/cases/distrodata.py
> > index ad952c004b..043953757f 100644
> > --- a/meta/lib/oeqa/selftest/cases/distrodata.py
> > +++ b/meta/lib/oeqa/selftest/cases/distrodata.py
> > @@ -55,7 +55,7 @@ but their recipes claim otherwise by setting
> UPSTREAM_VERSION_UNKNOWN. Please re
> >             return False
> >
> >         def is_maintainer_exception(entry):
> > -            exceptions = ["musl", "newlib", "linux-yocto",
> "linux-dummy", "mesa-gl", "libgfortran", "libx11-compose-data",
> > +            exceptions = ["musl", "newlib", "picolibc", "linux-yocto",
> "linux-dummy", "mesa-gl", "libgfortran", "libx11-compose-data",
> >                           "cve-update-nvd2-native",]
> >             for i in exceptions:
> >                  if i in entry:
> > diff --git a/meta/lib/oeqa/selftest/cases/picolibc.py
> b/meta/lib/oeqa/selftest/cases/picolibc.py
> > new file mode 100644
> > index 0000000000..e40b4fc3d3
> > --- /dev/null
> > +++ b/meta/lib/oeqa/selftest/cases/picolibc.py
> > @@ -0,0 +1,18 @@
> > +#
> > +# Copyright OpenEmbedded Contributors
> > +#
> > +# SPDX-License-Identifier: MIT
> > +#
> > +
> > +from oeqa.selftest.case import OESelftestTestCase
> > +from oeqa.utils.commands import bitbake, get_bb_var
> > +
> > +class PicolibcTest(OESelftestTestCase):
> > +
> > +    def test_picolibc(self):
> > +        compatible_machines = ['qemuarm', 'qemuarm64', 'qemuriscv32',
> 'qemuriscv64']
> > +        machine = get_bb_var('MACHINE')
> > +        if machine not in compatible_machines:
> > +            self.skipTest('This test only works with machines : %s' % '
> '.join(compatible_machines))
> > +        self.write_config('TCLIBC = "picolibc"')
> > +        bitbake("picolibc-helloworld")
> > diff --git a/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
> b/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
> > new file mode 100644
> > index 0000000000..573a571c24
> > --- /dev/null
> > +++ b/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
> > @@ -0,0 +1,40 @@
> > +require picolibc.inc
> > +
> > +# baremetal-image overrides
> > +BAREMETAL_BINNAME ?= "hello_picolibc_${MACHINE}"
> > +IMAGE_LINK_NAME ?= "baremetal-picolibc-image-${MACHINE}"
> > +IMAGE_NAME_SUFFIX ?= ""
> > +QB_DEFAULT_KERNEL ?= "${IMAGE_LINK_NAME}.elf"
> > +
> > +inherit baremetal-image
> > +
> > +COMPATIBLE_MACHINE = "qemuarm|qemuarm64|qemuriscv32|qemuriscv64"
> > +
> > +# Use semihosting to test via QEMU
> > +QB_OPT_APPEND:append = " -semihosting-config enable=on"
> > +
> > +# picolibc comes with a set of linker scripts, set the file
> > +# according to the architecture being built.
> > +PICOLIBC_LINKERSCRIPT:qemuarm64 = "aarch64.ld"
> > +PICOLIBC_LINKERSCRIPT:qemuarm = "arm.ld"
> > +PICOLIBC_LINKERSCRIPT:qemuriscv32 = "riscv.ld"
> > +PICOLIBC_LINKERSCRIPT:qemuriscv64 = "riscv.ld"
> > +
> > +# Simple compile function that manually exemplifies usage; as noted,
> > +# use a custom linker script, the GCC specs provided by picolibc
> > +# and semihost to be able to test via QEMU's monitor
> > +do_compile(){
> > +    ${CC} ${CFLAGS} ${LDFLAGS} --verbose
> -T${S}/hello-world/${PICOLIBC_LINKERSCRIPT} -specs=picolibc.specs
> --oslib=semihost -o ${BAREMETAL_BINNAME}.elf ${S}/hello-world/hello-world.c
> > +    ${OBJCOPY} -O binary ${BAREMETAL_BINNAME}.elf
> ${BAREMETAL_BINNAME}.bin
> > +}
> > +
> > +do_install(){
> > +    install -d ${D}/${base_libdir}/firmware
> > +    install -m 755 ${B}/${BAREMETAL_BINNAME}.elf
> ${D}/${base_libdir}/firmware/${BAREMETAL_BINNAME}.elf
> > +    install -m 755 ${B}/${BAREMETAL_BINNAME}.bin
> ${D}/${base_libdir}/firmware/${BAREMETAL_BINNAME}.bin
> > +}
> > +
> > +FILES:${PN} += " \
> > +    ${base_libdir}/firmware/${BAREMETAL_BINNAME}.elf \
> > +    ${base_libdir}/firmware/${BAREMETAL_BINNAME}.bin \
> > +"
> > diff --git a/meta/recipes-core/picolibc/picolibc.inc
> b/meta/recipes-core/picolibc/picolibc.inc
> > new file mode 100644
> > index 0000000000..3b380fe7af
> > --- /dev/null
> > +++ b/meta/recipes-core/picolibc/picolibc.inc
> > @@ -0,0 +1,21 @@
> > +SUMMARY = "C Libraries for Smaller Embedded Systems"
> > +HOMEPAGE = "https://keithp.com/picolibc"
> > +DESCRIPTION = "Picolibc is a set of standard C libraries, both libc and
> libm, designed for smaller embedded systems with limited ROM and RAM.
> Picolibc includes code from Newlib and AVR Libc."
> > +SECTION = "libs"
> > +
> > +# Newlib based code but GPL related bits removed, test/printf-tests.c
> and test/testcases.c
> > +# are GPLv2 and GeneratePicolibcCrossFile.sh is AGPL3 but not part of
> the artifacts.
> > +LICENSE = "BSD-2-Clause & BSD-3-Clause"
> > +LIC_FILES_CHKSUM = " \
> > + file://COPYING.GPL2;md5=59530bdf33659b29e73d4adb9f9f6552 \
> > + file://COPYING.NEWLIB;md5=08ae03456feb75b81cfdb359e0f1ef85 \
> > + file://COPYING.picolibc;md5=e50fa9458a40929689861ed472d46bc7 \
> > + "
> > +
> > +BASEVER = "1.8.6"
> > +PV = "${BASEVER}+git"
> > +SRC_URI = "git://
> github.com/picolibc/picolibc.git;protocol=https;branch=main"
> > +SRCREV="764ef4e401a8f4c6a86ab723533841f072885a5b"
> > +
> > +S = "${WORKDIR}/git"
> > +B = "${WORKDIR}/build"
> > diff --git
> a/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> b/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> > new file mode 100644
> > index 0000000000..da6460c95c
> > --- /dev/null
> > +++
> b/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> > @@ -0,0 +1,119 @@
> > +Upstream-Status: Pending
> > +
> > +Picolibc uses its own specs file: picolibc.specs to facilitate
> compilation, this
> > +needs to be passed down to GCC via the -specs argument.
> > +
> > +Using this specs file overrides some of the default options our
> toolchain was
> > +built with, in this case, they modify the include_dir and lib_dir paths
> used for
> > +compilation, their intention was to add support for -picolibc-prefix and
> > +-picolibc-buildtype arguments via the C preprocessor.
> > +
> > +-isystem %{-picolibc-prefix=*:%*/include/;
> -picolibc-buildtype=*:/usr/include/%*; :/usr/include} %(picolibc_cpp)
> > +
> > +This had the unwanted effect of defaulting to /usr/include for
> include_dir if
> > +those arguments are not being passed, this works fine for their flow
> but for us
> > +it pollutes the include directories with paths from the host. The same
> effect is
> > +applicable for lib_dir and for the c runtime file.
> > +
> > +Our toolchain relies on --sysroot to avoid using any paths from the
> host, here we
> > +manually add support for a third possible argument: -sysroot , if this
> is passed
> > +then the paths used by the compiler will be relative to the path passed
> by the
> > +--sysroot= cmdline argument, setting back the behavior that we intended
> in the
> > +first place.
> > +
> > +
> > +Signed-off-by: Alejandro Enedino Hernandez Samaniego <
> alejandro@enedino.org>
> > +
> > +Index: git/meson.build
> > +===================================================================
> > +--- git.orig/meson.build
> > ++++ git/meson.build
> > +@@ -622,12 +622,13 @@ else
> > + #
> > + picolibc_prefix_format = '-picolibc-prefix=*:@0@'
> > + picolibc_buildtype_format = '-picolibc-buildtype=*:@0@'
> > ++sysroot_format = '-sysroot=*:@0@'
> > + gen_format = '@0@'
> > +
> > + #
> > + # How to glue the three options together
> > + #
> > +-specs_option_format = '%{@0@; @1@; :@2@}'
> > ++specs_option_format = '%{@0@; @1@; @2@; :@3@}'
> > +
> > + #
> > + # Build the -isystem value
> > +@@ -639,10 +640,13 @@ isystem_prefix = picolibc_prefix_format.
> > + buildtype_include_dir =
> specs_prefix_format.format(get_option('includedir') / '%*')
> > + isystem_buildtype =
> picolibc_buildtype_format.format(buildtype_include_dir)
> > +
> > ++sysroot_include_dir = '%*'
> > ++isystem_sysroot = sysroot_format.format(sysroot_include_dir)
> > ++
> > + gen_include_dir = specs_prefix_format.format(get_option('includedir'))
> > + isystem_gen = gen_format.format(gen_include_dir)
> > +
> > +-specs_isystem = '-isystem ' +
> specs_option_format.format(isystem_prefix, isystem_buildtype, isystem_gen)
> > ++specs_isystem = '-isystem ' +
> specs_option_format.format(isystem_prefix, isystem_buildtype,
> isystem_sysroot, isystem_gen)
> > +
> > + #
> > + # Build the non-multilib -L value
> > +@@ -654,10 +658,13 @@ lib_prefix = picolibc_prefix_format.form
> > + buildtype_lib_dir = specs_prefix_format.format(get_option('libdir') /
> '%*')
> > + lib_buildtype = picolibc_buildtype_format.format(buildtype_lib_dir)
> > +
> > ++sysroot_lib_dir = '%*'
> > ++lib_sysroot = sysroot_format.format(sysroot_lib_dir)
> > ++
> > + gen_lib_dir = specs_prefix_format.format(get_option('libdir'))
> > + lib_gen = gen_format.format(gen_lib_dir)
> > +
> > +-specs_libpath = '-L' + specs_option_format.format(lib_prefix,
> lib_buildtype, lib_gen)
> > ++specs_libpath = '-L' + specs_option_format.format(lib_prefix,
> lib_buildtype, lib_sysroot, lib_gen)
> > +
> > + #
> > + # Build the non-multilib *startfile options
> > +@@ -669,6 +676,9 @@ crt0_prefix = picolibc_prefix_format.for
> > + buildtype_crt0_path = specs_prefix_format.format(get_option('libdir')
> / '%*' / crt0_expr)
> > + crt0_buildtype = picolibc_buildtype_format.format(buildtype_crt0_path)
> > +
> > ++sysroot_crt0_path = '%*' + '/' + get_option('libdir') + '/' + '%*' +
> '/' + crt0_expr
> > ++crt0_sysroot = picolibc_buildtype_format.format(sysroot_crt0_path)
> > ++
> > + gen_crt0_path = specs_prefix_format.format(get_option('libdir') /
> crt0_expr)
> > + crt0_gen = gen_format.format(gen_crt0_path)
> > +
> > +@@ -686,10 +696,13 @@ if enable_multilib
> > +   buildtype_multilib_dir =
> specs_prefix_format.format(get_option('libdir') / '%*/%M')
> > +   multilib_buildtype =
> picolibc_buildtype_format.format(buildtype_multilib_dir)
> > +
> > ++  sysroot_multilib_dir = '%*' + '/' + get_option('libdir') + '/' +
> '%*/%M'
> > ++  multilib_sysroot = sysroot_format.format(sysroot_multilib_dir)
> > ++
> > +   gen_multilib_dir = specs_prefix_format.format(get_option('libdir') /
> '%M')
> > +   multilib_gen = gen_format.format(gen_multilib_dir)
> > +
> > +-  specs_multilibpath = '-L' +
> specs_option_format.format(multilib_prefix, multilib_buildtype,
> multilib_gen)
> > ++  specs_multilibpath = '-L' +
> specs_option_format.format(multilib_prefix, multilib_buildtype,
> multilib_sysroot, multilib_gen)
> > +
> > +   #
> > +   # Prepend the multilib -L option to the non-multilib option
> > +@@ -705,6 +718,9 @@ if enable_multilib
> > +   buildtype_multilib_crt0_path =
> specs_prefix_format.format(get_option('libdir') / '%*/%M' / crt0_expr)
> > +   crt0_buildtype =
> picolibc_buildtype_format.format(buildtype_multilib_crt0_path)
> > +
> > ++  sysroot_multilib_crt0_path = '%*' + prefix + '/' +
> get_option('libdir') + '/' + '/%M' + '/' + crt0_expr
> > ++  crt0_sysroot = sysroot_format.format(sysroot_multilib_crt0_path)
> > ++
> > +   gen_multilib_crt0_path =
> specs_prefix_format.format(get_option('libdir') / '%M' / crt0_expr)
> > +   crt0_gen = gen_format.format(gen_multilib_crt0_path)
> > + endif
> > +@@ -714,7 +730,7 @@ endif
> > + # above. As there's only one value, it's either the
> > + # multilib path or the non-multilib path
> > + #
> > +-specs_startfile = specs_option_format.format(crt0_prefix,
> crt0_buildtype, crt0_gen)
> > ++specs_startfile = specs_option_format.format(crt0_prefix,
> crt0_buildtype, crt0_sysroot, crt0_gen)
> > + endif
> > +
> > + specs_data = configuration_data()
> > diff --git
> a/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> b/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> > new file mode 100644
> > index 0000000000..87bfbad3c5
> > --- /dev/null
> > +++ b/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> > @@ -0,0 +1,6 @@
> > +# We need to explicitly bypass mesons sanity check to avoid early
> compiler errors
> > +# otherwise meson will try to compile AND run test applications:
> > +# ../git/meson.build:35:0: ERROR: Executables created by c compiler are
> not runnable...
> > +
> > +[properties]
> > +skip_sanity_check=true
> > \ No newline at end of file
> > diff --git a/meta/recipes-core/picolibc/picolibc_git.bb
> b/meta/recipes-core/picolibc/picolibc_git.bb
> > new file mode 100644
> > index 0000000000..fdb159328f
> > --- /dev/null
> > +++ b/meta/recipes-core/picolibc/picolibc_git.bb
> > @@ -0,0 +1,35 @@
> > +require picolibc.inc
> > +
> > +INHIBIT_DEFAULT_DEPS = "1"
> > +DEPENDS = "virtual/${TARGET_PREFIX}gcc"
> > +
> > +PROVIDES += "virtual/libc virtual/libiconv virtual/libintl"
> > +
> > +COMPATIBLE_HOST:libc-musl:class-target = "null"
> > +COMPATIBLE_HOST:libc-glibc:class-target = "null"
> > +COMPATIBLE_MACHINE = "qemuarm|qemuarm64|qemuriscv32|qemuriscv64"
> > +
> > +SRC_URI:append = " file://avoid_polluting_cross_directories.patch"
> > +SRC_URI:append = " file://no-early-compiler-checks.cross"
> > +
> > +# This is being added by picolibc meson files as well to avoid
> > +# early compiler tests from failing, cant remember why I added it
> > +# to the newlib recipe but I would assume it was for the same reason
> > +TARGET_CC_ARCH:append = " -nostdlib"
> > +
> > +# When using RISCV64 use medany for both C library and application
> recipes
> > +TARGET_CFLAGS:append:qemuriscv64 = " -mcmodel=medany"
> > +
> > +inherit meson
> > +
> > +MESON_CROSS_FILE:append = "
> --cross-file=${UNPACKDIR}/no-early-compiler-checks.cross"
> > +
> > +PACKAGECONFIG ??= " specsdir"
> > +# Install GCC specs on libdir
> > +PACKAGECONFIG[specsdir] = "-Dspecsdir=${libdir},-Dspecsdir=none"
> > +
> > +
> > +FILES:${PN}-dev:append = " ${libdir}/*.specs ${libdir}/*.ld"
> > +
> > +# No rpm package is actually created but -dev depends on it, avoid dnf
> error
> > +DEV_PKG_DEPENDENCY:libc-picolibc = ""
> > diff --git a/meta/recipes-devtools/gcc/gcc-cross.inc
> b/meta/recipes-devtools/gcc/gcc-cross.inc
> > index 5b0ca15d47..c04177df5a 100644
> > --- a/meta/recipes-devtools/gcc/gcc-cross.inc
> > +++ b/meta/recipes-devtools/gcc/gcc-cross.inc
> > @@ -34,6 +34,7 @@ EXTRA_OECONF += "\
> > EXTRA_OECONF:append:libc-baremetal = " --without-headers"
> > EXTRA_OECONF:remove:libc-baremetal = "--enable-threads=posix"
> > EXTRA_OECONF:remove:libc-newlib = "--enable-threads=posix"
> > +EXTRA_OECONF:remove:libc-picolibc = "--enable-threads=posix"
> >
> > EXTRA_OECONF_PATHS = "\
> >     --with-gxx-include-dir=/not/exist${target_includedir}/c++/${BINV} \
> > diff --git a/meta/recipes-devtools/gcc/gcc-runtime.inc
> b/meta/recipes-devtools/gcc/gcc-runtime.inc
> > index 89b0bebcfb..1fca00f5f0 100644
> > --- a/meta/recipes-devtools/gcc/gcc-runtime.inc
> > +++ b/meta/recipes-devtools/gcc/gcc-runtime.inc
> > @@ -17,6 +17,7 @@ EXTRA_OECONF_PATHS = "\
> > EXTRA_OECONF:append:linuxstdbase = " --enable-clocale=gnu"
> > EXTRA_OECONF:append = " --cache-file=${B}/config.cache"
> > EXTRA_OECONF:append:libc-newlib = " --with-newlib --with-target-subdir"
> > +EXTRA_OECONF:append:libc-picolibc = " --with-newlib
> --with-target-subdir"
> > EXTRA_OECONF:append:libc-baremetal = " --with-target-subdir"
> >
> > # Disable ifuncs for libatomic on arm conflicts -march/-mcpu
> > @@ -27,6 +28,7 @@ DISABLE_STATIC:class-nativesdk ?= ""
> >
> > # Newlib does not support symbol versioning on libsdtcc++
> > SYMVERS_CONF:libc-newlib = ""
> > +SYMVERS_CONF:libc-picolibc = ""
> >
> > # Building with thumb enabled on armv6t fails
> > ARM_INSTRUCTION_SET:armv6 = "arm"
> > @@ -47,6 +49,7 @@ RUNTIMETARGET = "${RUNTIMELIBSSP} libstdc++-v3 libgomp
> libatomic ${RUNTIMELIBITM
> > "
> > # Only build libstdc++ for newlib
> > RUNTIMETARGET:libc-newlib = "libstdc++-v3"
> > +RUNTIMETARGET:libc-picolibc = "libstdc++-v3"
> >
> > # libiberty
> > # libgfortran needs separate recipe due to libquadmath dependency
> > diff --git a/meta/recipes-devtools/gcc/libgcc-common.inc
> b/meta/recipes-devtools/gcc/libgcc-common.inc
> > index d9084af51a..e3db17d700 100644
> > --- a/meta/recipes-devtools/gcc/libgcc-common.inc
> > +++ b/meta/recipes-devtools/gcc/libgcc-common.inc
> > @@ -53,6 +53,11 @@ do_install:append:libc-newlib () {
> > rmdir ${D}${base_libdir}
> > fi
> > }
> > +do_install:append:libc-picolibc () {
> > + if [ "${base_libdir}" != "${libdir}" ]; then
> > + rmdir ${D}${base_libdir}
> > + fi
> > +}
> >
> > # No rpm package is actually created but -dev depends on it, avoid dnf
> error
> > DEV_PKG_DEPENDENCY:libc-baremetal = ""
> > --
> > 2.45.2
> >
> >
> > -=-=-=-=-=-=-=-=-=-=-=-
> > Links: You receive all messages sent to this group.
> > View/Reply Online (#200882):
> https://lists.openembedded.org/g/openembedded-core/message/200882
> > Mute This Topic: https://lists.openembedded.org/mt/106746173/6875888
> > Group Owner: openembedded-core+owner@lists.openembedded.org
> > Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [
> ross.burton@arm.com]
> > -=-=-=-=-=-=-=-=-=-=-=-
> >
>
>
>
Alejandro Enedino Hernandez Samaniego July 24, 2024, 11:27 p.m. UTC | #8
Hello folks,

I think the final version of the spdx patches from Joshua have landed in
main already.

Would it be possible to try this one again? To this day I'm still not able
to reproduce the issue and I see no correlation from these changes to the
spdx test case.

Is there any other way in which we can discard the possibility of sstate
pollution?

Cheers,

Alejandro

On Mon, Jun 24, 2024, 11:27 AM Alejandro Enedino Hernandez Samaniego <
alejandro@enedino.org> wrote:

>
> On Mon, 24 Jun 2024 at 07:10, Ross Burton <Ross.Burton@arm.com> wrote:
>
>> Can you also add a test case to oe-selftest?
>>
>> Ross
>>
>
> Hi Ross,
>
> An oe-selftest test case is already included on this patch:
> > meta/lib/oeqa/selftest/cases/picolibc.py      |  18 +++
>
> oe-selftest - INFO - RESULTS - picolibc.PicolibcTest.test_picolibc: PASSED
>
> This test case actually passed on the Autobuilder runs. I can add an extra
> case if thats what you're referring to, but what would you want me to test?
> .
>
>
> While I don't see how this can be related to base-files/spdx, I'm open to
> the possibility that there's something wrong with the patch so
> I've been trying to reproduce the spdx test case issue but its been
> passing for me:
> 2024-06-20 09:17:28,571 - oe-selftest - INFO -
> spdx.SPDXCheck.test_spdx_base_files (subunit.RemotedTestCase)
> 2024-06-20 09:17:28,572 - oe-selftest - INFO -  ... ok
> 2024-06-20 09:17:28,573 - oe-selftest - INFO - 0: 1/1 1/1 (61.85s) (0
> failed) (spdx.SPDXCheck.test_spdx_base_files)
> 2024-06-20 09:17:34,072 - oe-selftest - INFO - RESULTS -
> spdx.SPDXCheck.test_spdx_base_files: PASSED (61.86s)
>
> The spdx case executes create_spdx for base-files and then checks for the
> existence of the base-files.spdx.json file in the deploy/spdx directory.
> Here's the output of such directory:
> ls -l
> ../qemuarm64-st-*/tmp/deploy/spdx/2.2/qemuarm64/packages/base-files.spdx.json
>
> -rw-r--r-- 2 user user 8667 Jun 19 20:12
> ../qemuarm64-st-4129739/tmp/deploy/spdx/2.2/qemuarm64/packages/base-files.spdx.json
> -rw-r--r-- 2 user user 8667 Jun 19 23:46
> ../qemuarm64-st-4129745/tmp/deploy/spdx/2.2/qemuarm64/packages/base-files.spdx.json
> -rw-r--r-- 2 user user 8667 Jun 19 17:36
> ../qemuarm64-st-4129747/tmp/deploy/spdx/2.2/qemuarm64/packages/base-files.spdx.json
> -rw-r--r-- 2 user user 8667 Jun 20 05:38
> ../qemuarm64-st-4129751/tmp/deploy/spdx/2.2/qemuarm64/packages/base-files.spdx.json
> -rw-r--r-- 2 user user 8667 Jun 19 17:36
> ../qemuarm64-st-4129773/tmp/deploy/spdx/2.2/qemuarm64/packages/base-files.spdx.json
> -rw-r--r-- 2 user user 8667 Jun 19 17:36
> ../qemuarm64-st-4129779/tmp/deploy/spdx/2.2/qemuarm64/packages/base-files.spdx.json
>
> So, on my runs, the file is present every time I ran the test case.
>
> I would like to help, but I simply don't know what else I could change to
> be able to reproduce the issue, is there a way to make sure that the
> sstate isnt being polluted?
>
> Alejandro
>
>
>
>>
>> > On 18 Jun 2024, at 19:12, Alejandro Hernandez Samaniego via
>> lists.openembedded.org <alejandro=enedino.org@lists.openembedded.org>
>> wrote:
>> >
>> > Enables usage of TCLIBC=picolibc extending OE functionality to build
>> and use
>> > picolibc based toolchains to build baremetal applications.
>> >
>> > Picolibc is a set of standard C libraries, both libc and libm, designed
>> for
>> > smaller embedded systems with limited ROM and RAM. Picolibc includes
>> code
>> > from Newlib and AVR Libc, but adresses some of newlibs concerns, it
>> retains
>> > newlibs directory structure, math, string and locale implementations,
>> but
>> > removed the GPL bits used to build the library, swiches old C style
>> code for
>> > C18 and replaces autotools with meson.
>> >
>> > This patch adds a picolibc recipe for the C library, a
>> picolibc-helloworld
>> > recipe that contains an example application and a testcase that builds
>> it.
>> >
>> > Picolibc can be built for ARM and RISCV architectures, its been tested
>> both
>> > for 32 and 64 bits, the provided example recipe produces the following
>> output:
>> >
>> > hello, world
>> >
>> > Runqemu does not automatically show any output since it hides QEMU
>> stderr which
>> > is where the QEMU monitors output is directed to when using
>> semihosting, but,
>> > manually running the same QEMU command does work properly.
>> >
>> > Signed-off-by: Alejandro Enedino Hernandez Samaniego <
>> alejandro@enedino.org>
>> > ---
>> > meta/classes-recipe/baremetal-image.bbclass   |   4 +-
>> > meta/classes-recipe/cross-canadian.bbclass    |   2 +-
>> > meta/conf/distro/include/maintainers.inc      |   2 +
>> > meta/conf/distro/include/tclibc-picolibc.inc  |  40 ++++++
>> > meta/conf/documentation.conf                  |   2 +-
>> > .../conf/machine/include/riscv/arch-riscv.inc |   1 +
>> > meta/lib/oeqa/selftest/cases/distrodata.py    |   2 +-
>> > meta/lib/oeqa/selftest/cases/picolibc.py      |  18 +++
>> > .../picolibc/picolibc-helloworld_git.bb       |  40 ++++++
>> > meta/recipes-core/picolibc/picolibc.inc       |  21 ++++
>> > .../avoid_polluting_cross_directories.patch   | 119 ++++++++++++++++++
>> > .../picolibc/no-early-compiler-checks.cross   |   6 +
>> > meta/recipes-core/picolibc/picolibc_git.bb    |  35 ++++++
>> > meta/recipes-devtools/gcc/gcc-cross.inc       |   1 +
>> > meta/recipes-devtools/gcc/gcc-runtime.inc     |   3 +
>> > meta/recipes-devtools/gcc/libgcc-common.inc   |   5 +
>> > 16 files changed, 296 insertions(+), 5 deletions(-)
>> > create mode 100644 meta/conf/distro/include/tclibc-picolibc.inc
>> > create mode 100644 meta/lib/oeqa/selftest/cases/picolibc.py
>> > create mode 100644 meta/recipes-core/picolibc/
>> picolibc-helloworld_git.bb
>> > create mode 100644 meta/recipes-core/picolibc/picolibc.inc
>> > create mode 100644
>> meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
>> > create mode 100644
>> meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
>> > create mode 100644 meta/recipes-core/picolibc/picolibc_git.bb
>> >
>> > diff --git a/meta/classes-recipe/baremetal-image.bbclass
>> b/meta/classes-recipe/baremetal-image.bbclass
>> > index 4e7d413626..27f2d2d10a 100644
>> > --- a/meta/classes-recipe/baremetal-image.bbclass
>> > +++ b/meta/classes-recipe/baremetal-image.bbclass
>> > @@ -16,8 +16,8 @@
>> > # See meta-skeleton for a working example.
>> >
>> >
>> > -# Toolchain should be baremetal or newlib based.
>> > -# TCLIBC="baremetal" or TCLIBC="newlib"
>> > +# Toolchain should be baremetal or newlib/picolibc based.
>> > +# TCLIBC="baremetal" or TCLIBC="newlib" or TCLIBC="picolibc"
>> > COMPATIBLE_HOST:libc-musl:class-target = "null"
>> > COMPATIBLE_HOST:libc-glibc:class-target = "null"
>> >
>> > diff --git a/meta/classes-recipe/cross-canadian.bbclass
>> b/meta/classes-recipe/cross-canadian.bbclass
>> > index 1670217d69..059d9aa95f 100644
>> > --- a/meta/classes-recipe/cross-canadian.bbclass
>> > +++ b/meta/classes-recipe/cross-canadian.bbclass
>> > @@ -36,7 +36,7 @@ python () {
>> >     if d.getVar("MODIFYTOS") != "1":
>> >         return
>> >
>> > -    if d.getVar("TCLIBC") in [ 'baremetal', 'newlib' ]:
>> > +    if d.getVar("TCLIBC") in [ 'baremetal', 'newlib', 'picolibc' ]:
>> >         return
>> >
>> >     tos = d.getVar("TARGET_OS")
>> > diff --git a/meta/conf/distro/include/maintainers.inc
>> b/meta/conf/distro/include/maintainers.inc
>> > index 42599267c1..ff24597723 100644
>> > --- a/meta/conf/distro/include/maintainers.inc
>> > +++ b/meta/conf/distro/include/maintainers.inc
>> > @@ -578,6 +578,8 @@ RECIPE_MAINTAINER:pn-pcmanfm = "Alexander Kanavin <
>> alex.kanavin@gmail.com>"
>> > RECIPE_MAINTAINER:pn-perf = "Bruce Ashfield <bruce.ashfield@gmail.com>"
>> > RECIPE_MAINTAINER:pn-perl = "Alexander Kanavin <alex.kanavin@gmail.com
>> >"
>> > RECIPE_MAINTAINER:pn-perlcross = "Alexander Kanavin <
>> alex.kanavin@gmail.com>"
>> > +RECIPE_MAINTAINER:pn-picolibc = "Alejandro Hernandez <
>> alejandro@enedino.org>"
>> > +RECIPE_MAINTAINER:pn-picolibc-helloworld = "Alejandro Hernandez <
>> alejandro@enedino.org>"
>> > RECIPE_MAINTAINER:pn-piglit = "Ross Burton <ross.burton@arm.com>"
>> > RECIPE_MAINTAINER:pn-pigz = "Hongxu Jia <hongxu.jia@windriver.com>"
>> > RECIPE_MAINTAINER:pn-pinentry = "Unassigned <
>> unassigned@yoctoproject.org>"
>> > diff --git a/meta/conf/distro/include/tclibc-picolibc.inc
>> b/meta/conf/distro/include/tclibc-picolibc.inc
>> > new file mode 100644
>> > index 0000000000..203765dfcb
>> > --- /dev/null
>> > +++ b/meta/conf/distro/include/tclibc-picolibc.inc
>> > @@ -0,0 +1,40 @@
>> > +#
>> > +# Picolibc configuration
>> > +#
>> > +
>> > +LIBCEXTENSION = "-picolibc"
>> > +LIBCOVERRIDE = ":libc-picolibc"
>> > +
>> > +PREFERRED_PROVIDER_virtual/libc ?= "picolibc"
>> > +PREFERRED_PROVIDER_virtual/libiconv ?= "picolibc"
>> > +PREFERRED_PROVIDER_virtual/libintl ?= "picolibc"
>> > +PREFERRED_PROVIDER_virtual/nativesdk-libintl ?= "nativesdk-glibc"
>> > +PREFERRED_PROVIDER_virtual/nativesdk-libiconv ?= "nativesdk-glibc"
>> > +
>> > +DISTRO_FEATURES_BACKFILL_CONSIDERED += "ldconfig"
>> > +
>> > +IMAGE_LINGUAS = ""
>> > +
>> > +LIBC_DEPENDENCIES = " \
>> > +    picolibc-dbg \
>> > +    picolibc-dev \
>> > +    libgcc-dev \
>> > +    libgcc-dbg \
>> > +    libstdc++-dev  \
>> > +    libstdc++-staticdev \
>> > +"
>> > +
>> > +ASSUME_PROVIDED += "virtual/crypt"
>> > +
>> > +TARGET_OS = "elf"
>> > +TARGET_OS:arm = "eabi"
>> > +
>> > +TOOLCHAIN_HOST_TASK ?= "packagegroup-cross-canadian-${MACHINE}
>> nativesdk-qemu nativesdk-sdk-provides-dummy"
>> > +TOOLCHAIN_TARGET_TASK ?= "${LIBC_DEPENDENCIES}"
>> > +TOOLCHAIN_NEED_CONFIGSITE_CACHE:remove = "zlib ncurses"
>> > +
>> > +# RISCV linker doesnt support PIE
>> > +SECURITY_CFLAGS:libc-picolibc:qemuriscv32 = "${SECURITY_NOPIE_CFLAGS}"
>> > +SECURITY_CFLAGS:libc-picolibc:qemuriscv64 = "${SECURITY_NOPIE_CFLAGS}"
>> > +
>> > +
>> > diff --git a/meta/conf/documentation.conf b/meta/conf/documentation.conf
>> > index b0591881ba..ad89142934 100644
>> > --- a/meta/conf/documentation.conf
>> > +++ b/meta/conf/documentation.conf
>> > @@ -421,7 +421,7 @@ TARGET_FPU[doc] = "Specifies the method for
>> handling FPU code. For FPU-less targ
>> > TARGET_OS[doc] = "Specifies the target's operating system."
>> > TARGET_PREFIX[doc] = "The prefix for the cross-compile toolchain (e.g.
>> arm-linux-)."
>> > TARGET_SYS[doc] = "The target system is comprised of
>> TARGET_ARCH,TARGET_VENDOR and TARGET_OS."
>> > -TCLIBC[doc] = "Specifies C library (libc) variant to use during the
>> build process. You can select 'baremetal', 'glibc', 'musl' or 'newlib'."
>> > +TCLIBC[doc] = "Specifies C library (libc) variant to use during the
>> build process. You can select 'baremetal', 'glibc', 'musl', 'newlib', or
>> 'picolibc'."
>> > TCMODE[doc] = "Enables an external toolchain (where provided by an
>> additional layer) if set to a value other than 'default'."
>> > TESTIMAGE_AUTO[doc] = "Enables test booting of virtual machine images
>> under the QEMU emulator after any root filesystems are created and runs
>> tests against those images each time an image is built."
>> > TEST_QEMUBOOT_TIMEOUT[doc] = "The time in seconds allowed for an image
>> to boot before automated runtime tests begin to run against an image."
>> > diff --git a/meta/conf/machine/include/riscv/arch-riscv.inc
>> b/meta/conf/machine/include/riscv/arch-riscv.inc
>> > index 230a266563..b34064e78f 100644
>> > --- a/meta/conf/machine/include/riscv/arch-riscv.inc
>> > +++ b/meta/conf/machine/include/riscv/arch-riscv.inc
>> > @@ -11,5 +11,6 @@ TUNE_CCARGS:append =
>> "${@bb.utils.contains('TUNE_FEATURES', 'riscv64nc', ' -marc
>> >
>> > # Fix: ld: unrecognized option '--hash-style=sysv'
>> > LINKER_HASH_STYLE:libc-newlib = ""
>> > +LINKER_HASH_STYLE:libc-picolibc = ""
>> > # Fix: ld: unrecognized option '--hash-style=gnu'
>> > LINKER_HASH_STYLE:libc-baremetal = ""
>> > diff --git a/meta/lib/oeqa/selftest/cases/distrodata.py
>> b/meta/lib/oeqa/selftest/cases/distrodata.py
>> > index ad952c004b..043953757f 100644
>> > --- a/meta/lib/oeqa/selftest/cases/distrodata.py
>> > +++ b/meta/lib/oeqa/selftest/cases/distrodata.py
>> > @@ -55,7 +55,7 @@ but their recipes claim otherwise by setting
>> UPSTREAM_VERSION_UNKNOWN. Please re
>> >             return False
>> >
>> >         def is_maintainer_exception(entry):
>> > -            exceptions = ["musl", "newlib", "linux-yocto",
>> "linux-dummy", "mesa-gl", "libgfortran", "libx11-compose-data",
>> > +            exceptions = ["musl", "newlib", "picolibc", "linux-yocto",
>> "linux-dummy", "mesa-gl", "libgfortran", "libx11-compose-data",
>> >                           "cve-update-nvd2-native",]
>> >             for i in exceptions:
>> >                  if i in entry:
>> > diff --git a/meta/lib/oeqa/selftest/cases/picolibc.py
>> b/meta/lib/oeqa/selftest/cases/picolibc.py
>> > new file mode 100644
>> > index 0000000000..e40b4fc3d3
>> > --- /dev/null
>> > +++ b/meta/lib/oeqa/selftest/cases/picolibc.py
>> > @@ -0,0 +1,18 @@
>> > +#
>> > +# Copyright OpenEmbedded Contributors
>> > +#
>> > +# SPDX-License-Identifier: MIT
>> > +#
>> > +
>> > +from oeqa.selftest.case import OESelftestTestCase
>> > +from oeqa.utils.commands import bitbake, get_bb_var
>> > +
>> > +class PicolibcTest(OESelftestTestCase):
>> > +
>> > +    def test_picolibc(self):
>> > +        compatible_machines = ['qemuarm', 'qemuarm64', 'qemuriscv32',
>> 'qemuriscv64']
>> > +        machine = get_bb_var('MACHINE')
>> > +        if machine not in compatible_machines:
>> > +            self.skipTest('This test only works with machines : %s' %
>> ' '.join(compatible_machines))
>> > +        self.write_config('TCLIBC = "picolibc"')
>> > +        bitbake("picolibc-helloworld")
>> > diff --git a/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
>> b/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
>> > new file mode 100644
>> > index 0000000000..573a571c24
>> > --- /dev/null
>> > +++ b/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
>> > @@ -0,0 +1,40 @@
>> > +require picolibc.inc
>> > +
>> > +# baremetal-image overrides
>> > +BAREMETAL_BINNAME ?= "hello_picolibc_${MACHINE}"
>> > +IMAGE_LINK_NAME ?= "baremetal-picolibc-image-${MACHINE}"
>> > +IMAGE_NAME_SUFFIX ?= ""
>> > +QB_DEFAULT_KERNEL ?= "${IMAGE_LINK_NAME}.elf"
>> > +
>> > +inherit baremetal-image
>> > +
>> > +COMPATIBLE_MACHINE = "qemuarm|qemuarm64|qemuriscv32|qemuriscv64"
>> > +
>> > +# Use semihosting to test via QEMU
>> > +QB_OPT_APPEND:append = " -semihosting-config enable=on"
>> > +
>> > +# picolibc comes with a set of linker scripts, set the file
>> > +# according to the architecture being built.
>> > +PICOLIBC_LINKERSCRIPT:qemuarm64 = "aarch64.ld"
>> > +PICOLIBC_LINKERSCRIPT:qemuarm = "arm.ld"
>> > +PICOLIBC_LINKERSCRIPT:qemuriscv32 = "riscv.ld"
>> > +PICOLIBC_LINKERSCRIPT:qemuriscv64 = "riscv.ld"
>> > +
>> > +# Simple compile function that manually exemplifies usage; as noted,
>> > +# use a custom linker script, the GCC specs provided by picolibc
>> > +# and semihost to be able to test via QEMU's monitor
>> > +do_compile(){
>> > +    ${CC} ${CFLAGS} ${LDFLAGS} --verbose
>> -T${S}/hello-world/${PICOLIBC_LINKERSCRIPT} -specs=picolibc.specs
>> --oslib=semihost -o ${BAREMETAL_BINNAME}.elf ${S}/hello-world/hello-world.c
>> > +    ${OBJCOPY} -O binary ${BAREMETAL_BINNAME}.elf
>> ${BAREMETAL_BINNAME}.bin
>> > +}
>> > +
>> > +do_install(){
>> > +    install -d ${D}/${base_libdir}/firmware
>> > +    install -m 755 ${B}/${BAREMETAL_BINNAME}.elf
>> ${D}/${base_libdir}/firmware/${BAREMETAL_BINNAME}.elf
>> > +    install -m 755 ${B}/${BAREMETAL_BINNAME}.bin
>> ${D}/${base_libdir}/firmware/${BAREMETAL_BINNAME}.bin
>> > +}
>> > +
>> > +FILES:${PN} += " \
>> > +    ${base_libdir}/firmware/${BAREMETAL_BINNAME}.elf \
>> > +    ${base_libdir}/firmware/${BAREMETAL_BINNAME}.bin \
>> > +"
>> > diff --git a/meta/recipes-core/picolibc/picolibc.inc
>> b/meta/recipes-core/picolibc/picolibc.inc
>> > new file mode 100644
>> > index 0000000000..3b380fe7af
>> > --- /dev/null
>> > +++ b/meta/recipes-core/picolibc/picolibc.inc
>> > @@ -0,0 +1,21 @@
>> > +SUMMARY = "C Libraries for Smaller Embedded Systems"
>> > +HOMEPAGE = "https://keithp.com/picolibc"
>> > +DESCRIPTION = "Picolibc is a set of standard C libraries, both libc
>> and libm, designed for smaller embedded systems with limited ROM and RAM.
>> Picolibc includes code from Newlib and AVR Libc."
>> > +SECTION = "libs"
>> > +
>> > +# Newlib based code but GPL related bits removed, test/printf-tests.c
>> and test/testcases.c
>> > +# are GPLv2 and GeneratePicolibcCrossFile.sh is AGPL3 but not part of
>> the artifacts.
>> > +LICENSE = "BSD-2-Clause & BSD-3-Clause"
>> > +LIC_FILES_CHKSUM = " \
>> > + file://COPYING.GPL2;md5=59530bdf33659b29e73d4adb9f9f6552 \
>> > + file://COPYING.NEWLIB;md5=08ae03456feb75b81cfdb359e0f1ef85 \
>> > + file://COPYING.picolibc;md5=e50fa9458a40929689861ed472d46bc7 \
>> > + "
>> > +
>> > +BASEVER = "1.8.6"
>> > +PV = "${BASEVER}+git"
>> > +SRC_URI = "git://
>> github.com/picolibc/picolibc.git;protocol=https;branch=main"
>> > +SRCREV="764ef4e401a8f4c6a86ab723533841f072885a5b"
>> > +
>> > +S = "${WORKDIR}/git"
>> > +B = "${WORKDIR}/build"
>> > diff --git
>> a/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
>> b/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
>> > new file mode 100644
>> > index 0000000000..da6460c95c
>> > --- /dev/null
>> > +++
>> b/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
>> > @@ -0,0 +1,119 @@
>> > +Upstream-Status: Pending
>> > +
>> > +Picolibc uses its own specs file: picolibc.specs to facilitate
>> compilation, this
>> > +needs to be passed down to GCC via the -specs argument.
>> > +
>> > +Using this specs file overrides some of the default options our
>> toolchain was
>> > +built with, in this case, they modify the include_dir and lib_dir
>> paths used for
>> > +compilation, their intention was to add support for -picolibc-prefix
>> and
>> > +-picolibc-buildtype arguments via the C preprocessor.
>> > +
>> > +-isystem %{-picolibc-prefix=*:%*/include/;
>> -picolibc-buildtype=*:/usr/include/%*; :/usr/include} %(picolibc_cpp)
>> > +
>> > +This had the unwanted effect of defaulting to /usr/include for
>> include_dir if
>> > +those arguments are not being passed, this works fine for their flow
>> but for us
>> > +it pollutes the include directories with paths from the host. The same
>> effect is
>> > +applicable for lib_dir and for the c runtime file.
>> > +
>> > +Our toolchain relies on --sysroot to avoid using any paths from the
>> host, here we
>> > +manually add support for a third possible argument: -sysroot , if this
>> is passed
>> > +then the paths used by the compiler will be relative to the path
>> passed by the
>> > +--sysroot= cmdline argument, setting back the behavior that we
>> intended in the
>> > +first place.
>> > +
>> > +
>> > +Signed-off-by: Alejandro Enedino Hernandez Samaniego <
>> alejandro@enedino.org>
>> > +
>> > +Index: git/meson.build
>> > +===================================================================
>> > +--- git.orig/meson.build
>> > ++++ git/meson.build
>> > +@@ -622,12 +622,13 @@ else
>> > + #
>> > + picolibc_prefix_format = '-picolibc-prefix=*:@0@'
>> > + picolibc_buildtype_format = '-picolibc-buildtype=*:@0@'
>> > ++sysroot_format = '-sysroot=*:@0@'
>> > + gen_format = '@0@'
>> > +
>> > + #
>> > + # How to glue the three options together
>> > + #
>> > +-specs_option_format = '%{@0@; @1@; :@2@}'
>> > ++specs_option_format = '%{@0@; @1@; @2@; :@3@}'
>> > +
>> > + #
>> > + # Build the -isystem value
>> > +@@ -639,10 +640,13 @@ isystem_prefix = picolibc_prefix_format.
>> > + buildtype_include_dir =
>> specs_prefix_format.format(get_option('includedir') / '%*')
>> > + isystem_buildtype =
>> picolibc_buildtype_format.format(buildtype_include_dir)
>> > +
>> > ++sysroot_include_dir = '%*'
>> > ++isystem_sysroot = sysroot_format.format(sysroot_include_dir)
>> > ++
>> > + gen_include_dir = specs_prefix_format.format(get_option('includedir'))
>> > + isystem_gen = gen_format.format(gen_include_dir)
>> > +
>> > +-specs_isystem = '-isystem ' +
>> specs_option_format.format(isystem_prefix, isystem_buildtype, isystem_gen)
>> > ++specs_isystem = '-isystem ' +
>> specs_option_format.format(isystem_prefix, isystem_buildtype,
>> isystem_sysroot, isystem_gen)
>> > +
>> > + #
>> > + # Build the non-multilib -L value
>> > +@@ -654,10 +658,13 @@ lib_prefix = picolibc_prefix_format.form
>> > + buildtype_lib_dir = specs_prefix_format.format(get_option('libdir') /
>> '%*')
>> > + lib_buildtype = picolibc_buildtype_format.format(buildtype_lib_dir)
>> > +
>> > ++sysroot_lib_dir = '%*'
>> > ++lib_sysroot = sysroot_format.format(sysroot_lib_dir)
>> > ++
>> > + gen_lib_dir = specs_prefix_format.format(get_option('libdir'))
>> > + lib_gen = gen_format.format(gen_lib_dir)
>> > +
>> > +-specs_libpath = '-L' + specs_option_format.format(lib_prefix,
>> lib_buildtype, lib_gen)
>> > ++specs_libpath = '-L' + specs_option_format.format(lib_prefix,
>> lib_buildtype, lib_sysroot, lib_gen)
>> > +
>> > + #
>> > + # Build the non-multilib *startfile options
>> > +@@ -669,6 +676,9 @@ crt0_prefix = picolibc_prefix_format.for
>> > + buildtype_crt0_path = specs_prefix_format.format(get_option('libdir')
>> / '%*' / crt0_expr)
>> > + crt0_buildtype = picolibc_buildtype_format.format(buildtype_crt0_path)
>> > +
>> > ++sysroot_crt0_path = '%*' + '/' + get_option('libdir') + '/' + '%*' +
>> '/' + crt0_expr
>> > ++crt0_sysroot = picolibc_buildtype_format.format(sysroot_crt0_path)
>> > ++
>> > + gen_crt0_path = specs_prefix_format.format(get_option('libdir') /
>> crt0_expr)
>> > + crt0_gen = gen_format.format(gen_crt0_path)
>> > +
>> > +@@ -686,10 +696,13 @@ if enable_multilib
>> > +   buildtype_multilib_dir =
>> specs_prefix_format.format(get_option('libdir') / '%*/%M')
>> > +   multilib_buildtype =
>> picolibc_buildtype_format.format(buildtype_multilib_dir)
>> > +
>> > ++  sysroot_multilib_dir = '%*' + '/' + get_option('libdir') + '/' +
>> '%*/%M'
>> > ++  multilib_sysroot = sysroot_format.format(sysroot_multilib_dir)
>> > ++
>> > +   gen_multilib_dir = specs_prefix_format.format(get_option('libdir')
>> / '%M')
>> > +   multilib_gen = gen_format.format(gen_multilib_dir)
>> > +
>> > +-  specs_multilibpath = '-L' +
>> specs_option_format.format(multilib_prefix, multilib_buildtype,
>> multilib_gen)
>> > ++  specs_multilibpath = '-L' +
>> specs_option_format.format(multilib_prefix, multilib_buildtype,
>> multilib_sysroot, multilib_gen)
>> > +
>> > +   #
>> > +   # Prepend the multilib -L option to the non-multilib option
>> > +@@ -705,6 +718,9 @@ if enable_multilib
>> > +   buildtype_multilib_crt0_path =
>> specs_prefix_format.format(get_option('libdir') / '%*/%M' / crt0_expr)
>> > +   crt0_buildtype =
>> picolibc_buildtype_format.format(buildtype_multilib_crt0_path)
>> > +
>> > ++  sysroot_multilib_crt0_path = '%*' + prefix + '/' +
>> get_option('libdir') + '/' + '/%M' + '/' + crt0_expr
>> > ++  crt0_sysroot = sysroot_format.format(sysroot_multilib_crt0_path)
>> > ++
>> > +   gen_multilib_crt0_path =
>> specs_prefix_format.format(get_option('libdir') / '%M' / crt0_expr)
>> > +   crt0_gen = gen_format.format(gen_multilib_crt0_path)
>> > + endif
>> > +@@ -714,7 +730,7 @@ endif
>> > + # above. As there's only one value, it's either the
>> > + # multilib path or the non-multilib path
>> > + #
>> > +-specs_startfile = specs_option_format.format(crt0_prefix,
>> crt0_buildtype, crt0_gen)
>> > ++specs_startfile = specs_option_format.format(crt0_prefix,
>> crt0_buildtype, crt0_sysroot, crt0_gen)
>> > + endif
>> > +
>> > + specs_data = configuration_data()
>> > diff --git
>> a/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
>> b/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
>> > new file mode 100644
>> > index 0000000000..87bfbad3c5
>> > --- /dev/null
>> > +++ b/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
>> > @@ -0,0 +1,6 @@
>> > +# We need to explicitly bypass mesons sanity check to avoid early
>> compiler errors
>> > +# otherwise meson will try to compile AND run test applications:
>> > +# ../git/meson.build:35:0: ERROR: Executables created by c compiler
>> are not runnable...
>> > +
>> > +[properties]
>> > +skip_sanity_check=true
>> > \ No newline at end of file
>> > diff --git a/meta/recipes-core/picolibc/picolibc_git.bb
>> b/meta/recipes-core/picolibc/picolibc_git.bb
>> > new file mode 100644
>> > index 0000000000..fdb159328f
>> > --- /dev/null
>> > +++ b/meta/recipes-core/picolibc/picolibc_git.bb
>> > @@ -0,0 +1,35 @@
>> > +require picolibc.inc
>> > +
>> > +INHIBIT_DEFAULT_DEPS = "1"
>> > +DEPENDS = "virtual/${TARGET_PREFIX}gcc"
>> > +
>> > +PROVIDES += "virtual/libc virtual/libiconv virtual/libintl"
>> > +
>> > +COMPATIBLE_HOST:libc-musl:class-target = "null"
>> > +COMPATIBLE_HOST:libc-glibc:class-target = "null"
>> > +COMPATIBLE_MACHINE = "qemuarm|qemuarm64|qemuriscv32|qemuriscv64"
>> > +
>> > +SRC_URI:append = " file://avoid_polluting_cross_directories.patch"
>> > +SRC_URI:append = " file://no-early-compiler-checks.cross"
>> > +
>> > +# This is being added by picolibc meson files as well to avoid
>> > +# early compiler tests from failing, cant remember why I added it
>> > +# to the newlib recipe but I would assume it was for the same reason
>> > +TARGET_CC_ARCH:append = " -nostdlib"
>> > +
>> > +# When using RISCV64 use medany for both C library and application
>> recipes
>> > +TARGET_CFLAGS:append:qemuriscv64 = " -mcmodel=medany"
>> > +
>> > +inherit meson
>> > +
>> > +MESON_CROSS_FILE:append = "
>> --cross-file=${UNPACKDIR}/no-early-compiler-checks.cross"
>> > +
>> > +PACKAGECONFIG ??= " specsdir"
>> > +# Install GCC specs on libdir
>> > +PACKAGECONFIG[specsdir] = "-Dspecsdir=${libdir},-Dspecsdir=none"
>> > +
>> > +
>> > +FILES:${PN}-dev:append = " ${libdir}/*.specs ${libdir}/*.ld"
>> > +
>> > +# No rpm package is actually created but -dev depends on it, avoid dnf
>> error
>> > +DEV_PKG_DEPENDENCY:libc-picolibc = ""
>> > diff --git a/meta/recipes-devtools/gcc/gcc-cross.inc
>> b/meta/recipes-devtools/gcc/gcc-cross.inc
>> > index 5b0ca15d47..c04177df5a 100644
>> > --- a/meta/recipes-devtools/gcc/gcc-cross.inc
>> > +++ b/meta/recipes-devtools/gcc/gcc-cross.inc
>> > @@ -34,6 +34,7 @@ EXTRA_OECONF += "\
>> > EXTRA_OECONF:append:libc-baremetal = " --without-headers"
>> > EXTRA_OECONF:remove:libc-baremetal = "--enable-threads=posix"
>> > EXTRA_OECONF:remove:libc-newlib = "--enable-threads=posix"
>> > +EXTRA_OECONF:remove:libc-picolibc = "--enable-threads=posix"
>> >
>> > EXTRA_OECONF_PATHS = "\
>> >     --with-gxx-include-dir=/not/exist${target_includedir}/c++/${BINV} \
>> > diff --git a/meta/recipes-devtools/gcc/gcc-runtime.inc
>> b/meta/recipes-devtools/gcc/gcc-runtime.inc
>> > index 89b0bebcfb..1fca00f5f0 100644
>> > --- a/meta/recipes-devtools/gcc/gcc-runtime.inc
>> > +++ b/meta/recipes-devtools/gcc/gcc-runtime.inc
>> > @@ -17,6 +17,7 @@ EXTRA_OECONF_PATHS = "\
>> > EXTRA_OECONF:append:linuxstdbase = " --enable-clocale=gnu"
>> > EXTRA_OECONF:append = " --cache-file=${B}/config.cache"
>> > EXTRA_OECONF:append:libc-newlib = " --with-newlib --with-target-subdir"
>> > +EXTRA_OECONF:append:libc-picolibc = " --with-newlib
>> --with-target-subdir"
>> > EXTRA_OECONF:append:libc-baremetal = " --with-target-subdir"
>> >
>> > # Disable ifuncs for libatomic on arm conflicts -march/-mcpu
>> > @@ -27,6 +28,7 @@ DISABLE_STATIC:class-nativesdk ?= ""
>> >
>> > # Newlib does not support symbol versioning on libsdtcc++
>> > SYMVERS_CONF:libc-newlib = ""
>> > +SYMVERS_CONF:libc-picolibc = ""
>> >
>> > # Building with thumb enabled on armv6t fails
>> > ARM_INSTRUCTION_SET:armv6 = "arm"
>> > @@ -47,6 +49,7 @@ RUNTIMETARGET = "${RUNTIMELIBSSP} libstdc++-v3
>> libgomp libatomic ${RUNTIMELIBITM
>> > "
>> > # Only build libstdc++ for newlib
>> > RUNTIMETARGET:libc-newlib = "libstdc++-v3"
>> > +RUNTIMETARGET:libc-picolibc = "libstdc++-v3"
>> >
>> > # libiberty
>> > # libgfortran needs separate recipe due to libquadmath dependency
>> > diff --git a/meta/recipes-devtools/gcc/libgcc-common.inc
>> b/meta/recipes-devtools/gcc/libgcc-common.inc
>> > index d9084af51a..e3db17d700 100644
>> > --- a/meta/recipes-devtools/gcc/libgcc-common.inc
>> > +++ b/meta/recipes-devtools/gcc/libgcc-common.inc
>> > @@ -53,6 +53,11 @@ do_install:append:libc-newlib () {
>> > rmdir ${D}${base_libdir}
>> > fi
>> > }
>> > +do_install:append:libc-picolibc () {
>> > + if [ "${base_libdir}" != "${libdir}" ]; then
>> > + rmdir ${D}${base_libdir}
>> > + fi
>> > +}
>> >
>> > # No rpm package is actually created but -dev depends on it, avoid dnf
>> error
>> > DEV_PKG_DEPENDENCY:libc-baremetal = ""
>> > --
>> > 2.45.2
>> >
>> >
>> > -=-=-=-=-=-=-=-=-=-=-=-
>> > Links: You receive all messages sent to this group.
>> > View/Reply Online (#200882):
>> https://lists.openembedded.org/g/openembedded-core/message/200882
>> > Mute This Topic: https://lists.openembedded.org/mt/106746173/6875888
>> > Group Owner: openembedded-core+owner@lists.openembedded.org
>> > Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [
>> ross.burton@arm.com]
>> > -=-=-=-=-=-=-=-=-=-=-=-
>> >
>>
>>
>>
Alexander Kanavin July 30, 2024, 7 p.m. UTC | #9
Can you submit the pending avoid_polluting_cross_directories.patch
upstream please?

Alex

On Tue, 18 Jun 2024 at 20:09, Alejandro Hernandez Samaniego via
lists.openembedded.org <alejandro=enedino.org@lists.openembedded.org>
wrote:
>
> Enables usage of TCLIBC=picolibc extending OE functionality to build and use
> picolibc based toolchains to build baremetal applications.
>
> Picolibc is a set of standard C libraries, both libc and libm, designed for
> smaller embedded systems with limited ROM and RAM. Picolibc includes code
> from Newlib and AVR Libc, but adresses some of newlibs concerns, it retains
> newlibs directory structure, math, string and locale implementations, but
> removed the GPL bits used to build the library, swiches old C style code for
> C18 and replaces autotools with meson.
>
> This patch adds a picolibc recipe for the C library, a picolibc-helloworld
> recipe that contains an example application and a testcase that builds it.
>
> Picolibc can be built for ARM and RISCV architectures, its been tested both
> for 32 and 64 bits, the provided example recipe produces the following output:
>
> hello, world
>
> Runqemu does not automatically show any output since it hides QEMU stderr which
> is where the QEMU monitors output is directed to when using semihosting, but,
> manually running the same QEMU command does work properly.
>
> Signed-off-by: Alejandro Enedino Hernandez Samaniego <alejandro@enedino.org>
> ---
>  meta/classes-recipe/baremetal-image.bbclass   |   4 +-
>  meta/classes-recipe/cross-canadian.bbclass    |   2 +-
>  meta/conf/distro/include/maintainers.inc      |   2 +
>  meta/conf/distro/include/tclibc-picolibc.inc  |  40 ++++++
>  meta/conf/documentation.conf                  |   2 +-
>  .../conf/machine/include/riscv/arch-riscv.inc |   1 +
>  meta/lib/oeqa/selftest/cases/distrodata.py    |   2 +-
>  meta/lib/oeqa/selftest/cases/picolibc.py      |  18 +++
>  .../picolibc/picolibc-helloworld_git.bb       |  40 ++++++
>  meta/recipes-core/picolibc/picolibc.inc       |  21 ++++
>  .../avoid_polluting_cross_directories.patch   | 119 ++++++++++++++++++
>  .../picolibc/no-early-compiler-checks.cross   |   6 +
>  meta/recipes-core/picolibc/picolibc_git.bb    |  35 ++++++
>  meta/recipes-devtools/gcc/gcc-cross.inc       |   1 +
>  meta/recipes-devtools/gcc/gcc-runtime.inc     |   3 +
>  meta/recipes-devtools/gcc/libgcc-common.inc   |   5 +
>  16 files changed, 296 insertions(+), 5 deletions(-)
>  create mode 100644 meta/conf/distro/include/tclibc-picolibc.inc
>  create mode 100644 meta/lib/oeqa/selftest/cases/picolibc.py
>  create mode 100644 meta/recipes-core/picolibc/picolibc-helloworld_git.bb
>  create mode 100644 meta/recipes-core/picolibc/picolibc.inc
>  create mode 100644 meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
>  create mode 100644 meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
>  create mode 100644 meta/recipes-core/picolibc/picolibc_git.bb
>
> diff --git a/meta/classes-recipe/baremetal-image.bbclass b/meta/classes-recipe/baremetal-image.bbclass
> index 4e7d413626..27f2d2d10a 100644
> --- a/meta/classes-recipe/baremetal-image.bbclass
> +++ b/meta/classes-recipe/baremetal-image.bbclass
> @@ -16,8 +16,8 @@
>  # See meta-skeleton for a working example.
>
>
> -# Toolchain should be baremetal or newlib based.
> -# TCLIBC="baremetal" or TCLIBC="newlib"
> +# Toolchain should be baremetal or newlib/picolibc based.
> +# TCLIBC="baremetal" or TCLIBC="newlib" or TCLIBC="picolibc"
>  COMPATIBLE_HOST:libc-musl:class-target = "null"
>  COMPATIBLE_HOST:libc-glibc:class-target = "null"
>
> diff --git a/meta/classes-recipe/cross-canadian.bbclass b/meta/classes-recipe/cross-canadian.bbclass
> index 1670217d69..059d9aa95f 100644
> --- a/meta/classes-recipe/cross-canadian.bbclass
> +++ b/meta/classes-recipe/cross-canadian.bbclass
> @@ -36,7 +36,7 @@ python () {
>      if d.getVar("MODIFYTOS") != "1":
>          return
>
> -    if d.getVar("TCLIBC") in [ 'baremetal', 'newlib' ]:
> +    if d.getVar("TCLIBC") in [ 'baremetal', 'newlib', 'picolibc' ]:
>          return
>
>      tos = d.getVar("TARGET_OS")
> diff --git a/meta/conf/distro/include/maintainers.inc b/meta/conf/distro/include/maintainers.inc
> index 42599267c1..ff24597723 100644
> --- a/meta/conf/distro/include/maintainers.inc
> +++ b/meta/conf/distro/include/maintainers.inc
> @@ -578,6 +578,8 @@ RECIPE_MAINTAINER:pn-pcmanfm = "Alexander Kanavin <alex.kanavin@gmail.com>"
>  RECIPE_MAINTAINER:pn-perf = "Bruce Ashfield <bruce.ashfield@gmail.com>"
>  RECIPE_MAINTAINER:pn-perl = "Alexander Kanavin <alex.kanavin@gmail.com>"
>  RECIPE_MAINTAINER:pn-perlcross = "Alexander Kanavin <alex.kanavin@gmail.com>"
> +RECIPE_MAINTAINER:pn-picolibc = "Alejandro Hernandez <alejandro@enedino.org>"
> +RECIPE_MAINTAINER:pn-picolibc-helloworld = "Alejandro Hernandez <alejandro@enedino.org>"
>  RECIPE_MAINTAINER:pn-piglit = "Ross Burton <ross.burton@arm.com>"
>  RECIPE_MAINTAINER:pn-pigz = "Hongxu Jia <hongxu.jia@windriver.com>"
>  RECIPE_MAINTAINER:pn-pinentry = "Unassigned <unassigned@yoctoproject.org>"
> diff --git a/meta/conf/distro/include/tclibc-picolibc.inc b/meta/conf/distro/include/tclibc-picolibc.inc
> new file mode 100644
> index 0000000000..203765dfcb
> --- /dev/null
> +++ b/meta/conf/distro/include/tclibc-picolibc.inc
> @@ -0,0 +1,40 @@
> +#
> +# Picolibc configuration
> +#
> +
> +LIBCEXTENSION = "-picolibc"
> +LIBCOVERRIDE = ":libc-picolibc"
> +
> +PREFERRED_PROVIDER_virtual/libc ?= "picolibc"
> +PREFERRED_PROVIDER_virtual/libiconv ?= "picolibc"
> +PREFERRED_PROVIDER_virtual/libintl ?= "picolibc"
> +PREFERRED_PROVIDER_virtual/nativesdk-libintl ?= "nativesdk-glibc"
> +PREFERRED_PROVIDER_virtual/nativesdk-libiconv ?= "nativesdk-glibc"
> +
> +DISTRO_FEATURES_BACKFILL_CONSIDERED += "ldconfig"
> +
> +IMAGE_LINGUAS = ""
> +
> +LIBC_DEPENDENCIES = " \
> +    picolibc-dbg \
> +    picolibc-dev \
> +    libgcc-dev \
> +    libgcc-dbg \
> +    libstdc++-dev  \
> +    libstdc++-staticdev \
> +"
> +
> +ASSUME_PROVIDED += "virtual/crypt"
> +
> +TARGET_OS = "elf"
> +TARGET_OS:arm = "eabi"
> +
> +TOOLCHAIN_HOST_TASK ?= "packagegroup-cross-canadian-${MACHINE} nativesdk-qemu nativesdk-sdk-provides-dummy"
> +TOOLCHAIN_TARGET_TASK ?= "${LIBC_DEPENDENCIES}"
> +TOOLCHAIN_NEED_CONFIGSITE_CACHE:remove = "zlib ncurses"
> +
> +# RISCV linker doesnt support PIE
> +SECURITY_CFLAGS:libc-picolibc:qemuriscv32 = "${SECURITY_NOPIE_CFLAGS}"
> +SECURITY_CFLAGS:libc-picolibc:qemuriscv64 = "${SECURITY_NOPIE_CFLAGS}"
> +
> +
> diff --git a/meta/conf/documentation.conf b/meta/conf/documentation.conf
> index b0591881ba..ad89142934 100644
> --- a/meta/conf/documentation.conf
> +++ b/meta/conf/documentation.conf
> @@ -421,7 +421,7 @@ TARGET_FPU[doc] = "Specifies the method for handling FPU code. For FPU-less targ
>  TARGET_OS[doc] = "Specifies the target's operating system."
>  TARGET_PREFIX[doc] = "The prefix for the cross-compile toolchain (e.g. arm-linux-)."
>  TARGET_SYS[doc] = "The target system is comprised of TARGET_ARCH,TARGET_VENDOR and TARGET_OS."
> -TCLIBC[doc] = "Specifies C library (libc) variant to use during the build process. You can select 'baremetal', 'glibc', 'musl' or 'newlib'."
> +TCLIBC[doc] = "Specifies C library (libc) variant to use during the build process. You can select 'baremetal', 'glibc', 'musl', 'newlib', or 'picolibc'."
>  TCMODE[doc] = "Enables an external toolchain (where provided by an additional layer) if set to a value other than 'default'."
>  TESTIMAGE_AUTO[doc] = "Enables test booting of virtual machine images under the QEMU emulator after any root filesystems are created and runs tests against those images each time an image is built."
>  TEST_QEMUBOOT_TIMEOUT[doc] = "The time in seconds allowed for an image to boot before automated runtime tests begin to run against an image."
> diff --git a/meta/conf/machine/include/riscv/arch-riscv.inc b/meta/conf/machine/include/riscv/arch-riscv.inc
> index 230a266563..b34064e78f 100644
> --- a/meta/conf/machine/include/riscv/arch-riscv.inc
> +++ b/meta/conf/machine/include/riscv/arch-riscv.inc
> @@ -11,5 +11,6 @@ TUNE_CCARGS:append = "${@bb.utils.contains('TUNE_FEATURES', 'riscv64nc', ' -marc
>
>  # Fix: ld: unrecognized option '--hash-style=sysv'
>  LINKER_HASH_STYLE:libc-newlib = ""
> +LINKER_HASH_STYLE:libc-picolibc = ""
>  # Fix: ld: unrecognized option '--hash-style=gnu'
>  LINKER_HASH_STYLE:libc-baremetal = ""
> diff --git a/meta/lib/oeqa/selftest/cases/distrodata.py b/meta/lib/oeqa/selftest/cases/distrodata.py
> index ad952c004b..043953757f 100644
> --- a/meta/lib/oeqa/selftest/cases/distrodata.py
> +++ b/meta/lib/oeqa/selftest/cases/distrodata.py
> @@ -55,7 +55,7 @@ but their recipes claim otherwise by setting UPSTREAM_VERSION_UNKNOWN. Please re
>              return False
>
>          def is_maintainer_exception(entry):
> -            exceptions = ["musl", "newlib", "linux-yocto", "linux-dummy", "mesa-gl", "libgfortran", "libx11-compose-data",
> +            exceptions = ["musl", "newlib", "picolibc", "linux-yocto", "linux-dummy", "mesa-gl", "libgfortran", "libx11-compose-data",
>                            "cve-update-nvd2-native",]
>              for i in exceptions:
>                   if i in entry:
> diff --git a/meta/lib/oeqa/selftest/cases/picolibc.py b/meta/lib/oeqa/selftest/cases/picolibc.py
> new file mode 100644
> index 0000000000..e40b4fc3d3
> --- /dev/null
> +++ b/meta/lib/oeqa/selftest/cases/picolibc.py
> @@ -0,0 +1,18 @@
> +#
> +# Copyright OpenEmbedded Contributors
> +#
> +# SPDX-License-Identifier: MIT
> +#
> +
> +from oeqa.selftest.case import OESelftestTestCase
> +from oeqa.utils.commands import bitbake, get_bb_var
> +
> +class PicolibcTest(OESelftestTestCase):
> +
> +    def test_picolibc(self):
> +        compatible_machines = ['qemuarm', 'qemuarm64', 'qemuriscv32', 'qemuriscv64']
> +        machine = get_bb_var('MACHINE')
> +        if machine not in compatible_machines:
> +            self.skipTest('This test only works with machines : %s' % ' '.join(compatible_machines))
> +        self.write_config('TCLIBC = "picolibc"')
> +        bitbake("picolibc-helloworld")
> diff --git a/meta/recipes-core/picolibc/picolibc-helloworld_git.bb b/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
> new file mode 100644
> index 0000000000..573a571c24
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
> @@ -0,0 +1,40 @@
> +require picolibc.inc
> +
> +# baremetal-image overrides
> +BAREMETAL_BINNAME ?= "hello_picolibc_${MACHINE}"
> +IMAGE_LINK_NAME ?= "baremetal-picolibc-image-${MACHINE}"
> +IMAGE_NAME_SUFFIX ?= ""
> +QB_DEFAULT_KERNEL ?= "${IMAGE_LINK_NAME}.elf"
> +
> +inherit baremetal-image
> +
> +COMPATIBLE_MACHINE = "qemuarm|qemuarm64|qemuriscv32|qemuriscv64"
> +
> +# Use semihosting to test via QEMU
> +QB_OPT_APPEND:append = " -semihosting-config enable=on"
> +
> +# picolibc comes with a set of linker scripts, set the file
> +# according to the architecture being built.
> +PICOLIBC_LINKERSCRIPT:qemuarm64 = "aarch64.ld"
> +PICOLIBC_LINKERSCRIPT:qemuarm = "arm.ld"
> +PICOLIBC_LINKERSCRIPT:qemuriscv32 = "riscv.ld"
> +PICOLIBC_LINKERSCRIPT:qemuriscv64 = "riscv.ld"
> +
> +# Simple compile function that manually exemplifies usage; as noted,
> +# use a custom linker script, the GCC specs provided by picolibc
> +# and semihost to be able to test via QEMU's monitor
> +do_compile(){
> +    ${CC} ${CFLAGS} ${LDFLAGS} --verbose -T${S}/hello-world/${PICOLIBC_LINKERSCRIPT} -specs=picolibc.specs --oslib=semihost -o ${BAREMETAL_BINNAME}.elf ${S}/hello-world/hello-world.c
> +    ${OBJCOPY} -O binary ${BAREMETAL_BINNAME}.elf ${BAREMETAL_BINNAME}.bin
> +}
> +
> +do_install(){
> +    install -d ${D}/${base_libdir}/firmware
> +    install -m 755 ${B}/${BAREMETAL_BINNAME}.elf ${D}/${base_libdir}/firmware/${BAREMETAL_BINNAME}.elf
> +    install -m 755 ${B}/${BAREMETAL_BINNAME}.bin ${D}/${base_libdir}/firmware/${BAREMETAL_BINNAME}.bin
> +}
> +
> +FILES:${PN} += " \
> +    ${base_libdir}/firmware/${BAREMETAL_BINNAME}.elf \
> +    ${base_libdir}/firmware/${BAREMETAL_BINNAME}.bin \
> +"
> diff --git a/meta/recipes-core/picolibc/picolibc.inc b/meta/recipes-core/picolibc/picolibc.inc
> new file mode 100644
> index 0000000000..3b380fe7af
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc.inc
> @@ -0,0 +1,21 @@
> +SUMMARY = "C Libraries for Smaller Embedded Systems"
> +HOMEPAGE = "https://keithp.com/picolibc"
> +DESCRIPTION = "Picolibc is a set of standard C libraries, both libc and libm, designed for smaller embedded systems with limited ROM and RAM. Picolibc includes code from Newlib and AVR Libc."
> +SECTION = "libs"
> +
> +# Newlib based code but GPL related bits removed, test/printf-tests.c and test/testcases.c
> +# are GPLv2 and GeneratePicolibcCrossFile.sh is AGPL3 but not part of the artifacts.
> +LICENSE = "BSD-2-Clause & BSD-3-Clause"
> +LIC_FILES_CHKSUM = " \
> +               file://COPYING.GPL2;md5=59530bdf33659b29e73d4adb9f9f6552 \
> +               file://COPYING.NEWLIB;md5=08ae03456feb75b81cfdb359e0f1ef85 \
> +               file://COPYING.picolibc;md5=e50fa9458a40929689861ed472d46bc7 \
> +               "
> +
> +BASEVER = "1.8.6"
> +PV = "${BASEVER}+git"
> +SRC_URI = "git://github.com/picolibc/picolibc.git;protocol=https;branch=main"
> +SRCREV="764ef4e401a8f4c6a86ab723533841f072885a5b"
> +
> +S = "${WORKDIR}/git"
> +B = "${WORKDIR}/build"
> diff --git a/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch b/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> new file mode 100644
> index 0000000000..da6460c95c
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> @@ -0,0 +1,119 @@
> +Upstream-Status: Pending
> +
> +Picolibc uses its own specs file: picolibc.specs to facilitate compilation, this
> +needs to be passed down to GCC via the -specs argument.
> +
> +Using this specs file overrides some of the default options our toolchain was
> +built with, in this case, they modify the include_dir and lib_dir paths used for
> +compilation, their intention was to add support for -picolibc-prefix and
> +-picolibc-buildtype arguments via the C preprocessor.
> +
> +-isystem %{-picolibc-prefix=*:%*/include/; -picolibc-buildtype=*:/usr/include/%*; :/usr/include} %(picolibc_cpp)
> +
> +This had the unwanted effect of defaulting to /usr/include for include_dir if
> +those arguments are not being passed, this works fine for their flow but for us
> +it pollutes the include directories with paths from the host. The same effect is
> +applicable for lib_dir and for the c runtime file.
> +
> +Our toolchain relies on --sysroot to avoid using any paths from the host, here we
> +manually add support for a third possible argument: -sysroot , if this is passed
> +then the paths used by the compiler will be relative to the path passed by the
> +--sysroot= cmdline argument, setting back the behavior that we intended in the
> +first place.
> +
> +
> +Signed-off-by: Alejandro Enedino Hernandez Samaniego <alejandro@enedino.org>
> +
> +Index: git/meson.build
> +===================================================================
> +--- git.orig/meson.build
> ++++ git/meson.build
> +@@ -622,12 +622,13 @@ else
> + #
> + picolibc_prefix_format = '-picolibc-prefix=*:@0@'
> + picolibc_buildtype_format = '-picolibc-buildtype=*:@0@'
> ++sysroot_format = '-sysroot=*:@0@'
> + gen_format = '@0@'
> +
> + #
> + # How to glue the three options together
> + #
> +-specs_option_format = '%{@0@; @1@; :@2@}'
> ++specs_option_format = '%{@0@; @1@; @2@; :@3@}'
> +
> + #
> + # Build the -isystem value
> +@@ -639,10 +640,13 @@ isystem_prefix = picolibc_prefix_format.
> + buildtype_include_dir = specs_prefix_format.format(get_option('includedir') / '%*')
> + isystem_buildtype = picolibc_buildtype_format.format(buildtype_include_dir)
> +
> ++sysroot_include_dir = '%*'
> ++isystem_sysroot = sysroot_format.format(sysroot_include_dir)
> ++
> + gen_include_dir = specs_prefix_format.format(get_option('includedir'))
> + isystem_gen = gen_format.format(gen_include_dir)
> +
> +-specs_isystem = '-isystem ' + specs_option_format.format(isystem_prefix, isystem_buildtype, isystem_gen)
> ++specs_isystem = '-isystem ' + specs_option_format.format(isystem_prefix, isystem_buildtype, isystem_sysroot, isystem_gen)
> +
> + #
> + # Build the non-multilib -L value
> +@@ -654,10 +658,13 @@ lib_prefix = picolibc_prefix_format.form
> + buildtype_lib_dir = specs_prefix_format.format(get_option('libdir') / '%*')
> + lib_buildtype = picolibc_buildtype_format.format(buildtype_lib_dir)
> +
> ++sysroot_lib_dir = '%*'
> ++lib_sysroot = sysroot_format.format(sysroot_lib_dir)
> ++
> + gen_lib_dir = specs_prefix_format.format(get_option('libdir'))
> + lib_gen = gen_format.format(gen_lib_dir)
> +
> +-specs_libpath = '-L' + specs_option_format.format(lib_prefix, lib_buildtype, lib_gen)
> ++specs_libpath = '-L' + specs_option_format.format(lib_prefix, lib_buildtype, lib_sysroot, lib_gen)
> +
> + #
> + # Build the non-multilib *startfile options
> +@@ -669,6 +676,9 @@ crt0_prefix = picolibc_prefix_format.for
> + buildtype_crt0_path = specs_prefix_format.format(get_option('libdir') / '%*' / crt0_expr)
> + crt0_buildtype = picolibc_buildtype_format.format(buildtype_crt0_path)
> +
> ++sysroot_crt0_path = '%*' + '/' + get_option('libdir') + '/' + '%*' + '/' + crt0_expr
> ++crt0_sysroot = picolibc_buildtype_format.format(sysroot_crt0_path)
> ++
> + gen_crt0_path = specs_prefix_format.format(get_option('libdir') / crt0_expr)
> + crt0_gen = gen_format.format(gen_crt0_path)
> +
> +@@ -686,10 +696,13 @@ if enable_multilib
> +   buildtype_multilib_dir = specs_prefix_format.format(get_option('libdir') / '%*/%M')
> +   multilib_buildtype = picolibc_buildtype_format.format(buildtype_multilib_dir)
> +
> ++  sysroot_multilib_dir = '%*' + '/' + get_option('libdir') + '/' + '%*/%M'
> ++  multilib_sysroot = sysroot_format.format(sysroot_multilib_dir)
> ++
> +   gen_multilib_dir = specs_prefix_format.format(get_option('libdir') / '%M')
> +   multilib_gen = gen_format.format(gen_multilib_dir)
> +
> +-  specs_multilibpath = '-L' + specs_option_format.format(multilib_prefix, multilib_buildtype, multilib_gen)
> ++  specs_multilibpath = '-L' + specs_option_format.format(multilib_prefix, multilib_buildtype, multilib_sysroot, multilib_gen)
> +
> +   #
> +   # Prepend the multilib -L option to the non-multilib option
> +@@ -705,6 +718,9 @@ if enable_multilib
> +   buildtype_multilib_crt0_path = specs_prefix_format.format(get_option('libdir') / '%*/%M' / crt0_expr)
> +   crt0_buildtype = picolibc_buildtype_format.format(buildtype_multilib_crt0_path)
> +
> ++  sysroot_multilib_crt0_path = '%*' + prefix + '/' + get_option('libdir') + '/' + '/%M' + '/' + crt0_expr
> ++  crt0_sysroot = sysroot_format.format(sysroot_multilib_crt0_path)
> ++
> +   gen_multilib_crt0_path = specs_prefix_format.format(get_option('libdir') / '%M' / crt0_expr)
> +   crt0_gen = gen_format.format(gen_multilib_crt0_path)
> + endif
> +@@ -714,7 +730,7 @@ endif
> + # above. As there's only one value, it's either the
> + # multilib path or the non-multilib path
> + #
> +-specs_startfile = specs_option_format.format(crt0_prefix, crt0_buildtype, crt0_gen)
> ++specs_startfile = specs_option_format.format(crt0_prefix, crt0_buildtype, crt0_sysroot, crt0_gen)
> + endif
> +
> + specs_data = configuration_data()
> diff --git a/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross b/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> new file mode 100644
> index 0000000000..87bfbad3c5
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> @@ -0,0 +1,6 @@
> +# We need to explicitly bypass mesons sanity check to avoid early compiler errors
> +# otherwise meson will try to compile AND run test applications:
> +# ../git/meson.build:35:0: ERROR: Executables created by c compiler are not runnable...
> +
> +[properties]
> +skip_sanity_check=true
> \ No newline at end of file
> diff --git a/meta/recipes-core/picolibc/picolibc_git.bb b/meta/recipes-core/picolibc/picolibc_git.bb
> new file mode 100644
> index 0000000000..fdb159328f
> --- /dev/null
> +++ b/meta/recipes-core/picolibc/picolibc_git.bb
> @@ -0,0 +1,35 @@
> +require picolibc.inc
> +
> +INHIBIT_DEFAULT_DEPS = "1"
> +DEPENDS = "virtual/${TARGET_PREFIX}gcc"
> +
> +PROVIDES += "virtual/libc virtual/libiconv virtual/libintl"
> +
> +COMPATIBLE_HOST:libc-musl:class-target = "null"
> +COMPATIBLE_HOST:libc-glibc:class-target = "null"
> +COMPATIBLE_MACHINE = "qemuarm|qemuarm64|qemuriscv32|qemuriscv64"
> +
> +SRC_URI:append = " file://avoid_polluting_cross_directories.patch"
> +SRC_URI:append = " file://no-early-compiler-checks.cross"
> +
> +# This is being added by picolibc meson files as well to avoid
> +# early compiler tests from failing, cant remember why I added it
> +# to the newlib recipe but I would assume it was for the same reason
> +TARGET_CC_ARCH:append = " -nostdlib"
> +
> +# When using RISCV64 use medany for both C library and application recipes
> +TARGET_CFLAGS:append:qemuriscv64 = " -mcmodel=medany"
> +
> +inherit meson
> +
> +MESON_CROSS_FILE:append = " --cross-file=${UNPACKDIR}/no-early-compiler-checks.cross"
> +
> +PACKAGECONFIG ??= " specsdir"
> +# Install GCC specs on libdir
> +PACKAGECONFIG[specsdir] = "-Dspecsdir=${libdir},-Dspecsdir=none"
> +
> +
> +FILES:${PN}-dev:append = " ${libdir}/*.specs ${libdir}/*.ld"
> +
> +# No rpm package is actually created but -dev depends on it, avoid dnf error
> +DEV_PKG_DEPENDENCY:libc-picolibc = ""
> diff --git a/meta/recipes-devtools/gcc/gcc-cross.inc b/meta/recipes-devtools/gcc/gcc-cross.inc
> index 5b0ca15d47..c04177df5a 100644
> --- a/meta/recipes-devtools/gcc/gcc-cross.inc
> +++ b/meta/recipes-devtools/gcc/gcc-cross.inc
> @@ -34,6 +34,7 @@ EXTRA_OECONF += "\
>  EXTRA_OECONF:append:libc-baremetal = " --without-headers"
>  EXTRA_OECONF:remove:libc-baremetal = "--enable-threads=posix"
>  EXTRA_OECONF:remove:libc-newlib = "--enable-threads=posix"
> +EXTRA_OECONF:remove:libc-picolibc = "--enable-threads=posix"
>
>  EXTRA_OECONF_PATHS = "\
>      --with-gxx-include-dir=/not/exist${target_includedir}/c++/${BINV} \
> diff --git a/meta/recipes-devtools/gcc/gcc-runtime.inc b/meta/recipes-devtools/gcc/gcc-runtime.inc
> index 89b0bebcfb..1fca00f5f0 100644
> --- a/meta/recipes-devtools/gcc/gcc-runtime.inc
> +++ b/meta/recipes-devtools/gcc/gcc-runtime.inc
> @@ -17,6 +17,7 @@ EXTRA_OECONF_PATHS = "\
>  EXTRA_OECONF:append:linuxstdbase = " --enable-clocale=gnu"
>  EXTRA_OECONF:append = " --cache-file=${B}/config.cache"
>  EXTRA_OECONF:append:libc-newlib = " --with-newlib --with-target-subdir"
> +EXTRA_OECONF:append:libc-picolibc = " --with-newlib --with-target-subdir"
>  EXTRA_OECONF:append:libc-baremetal = " --with-target-subdir"
>
>  # Disable ifuncs for libatomic on arm conflicts -march/-mcpu
> @@ -27,6 +28,7 @@ DISABLE_STATIC:class-nativesdk ?= ""
>
>  # Newlib does not support symbol versioning on libsdtcc++
>  SYMVERS_CONF:libc-newlib = ""
> +SYMVERS_CONF:libc-picolibc = ""
>
>  # Building with thumb enabled on armv6t fails
>  ARM_INSTRUCTION_SET:armv6 = "arm"
> @@ -47,6 +49,7 @@ RUNTIMETARGET = "${RUNTIMELIBSSP} libstdc++-v3 libgomp libatomic ${RUNTIMELIBITM
>  "
>  # Only build libstdc++ for newlib
>  RUNTIMETARGET:libc-newlib = "libstdc++-v3"
> +RUNTIMETARGET:libc-picolibc = "libstdc++-v3"
>
>  # libiberty
>  # libgfortran needs separate recipe due to libquadmath dependency
> diff --git a/meta/recipes-devtools/gcc/libgcc-common.inc b/meta/recipes-devtools/gcc/libgcc-common.inc
> index d9084af51a..e3db17d700 100644
> --- a/meta/recipes-devtools/gcc/libgcc-common.inc
> +++ b/meta/recipes-devtools/gcc/libgcc-common.inc
> @@ -53,6 +53,11 @@ do_install:append:libc-newlib () {
>                 rmdir ${D}${base_libdir}
>         fi
>  }
> +do_install:append:libc-picolibc () {
> +       if [ "${base_libdir}" != "${libdir}" ]; then
> +               rmdir ${D}${base_libdir}
> +       fi
> +}
>
>  # No rpm package is actually created but -dev depends on it, avoid dnf error
>  DEV_PKG_DEPENDENCY:libc-baremetal = ""
> --
> 2.45.2
>
>
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#200882): https://lists.openembedded.org/g/openembedded-core/message/200882
> Mute This Topic: https://lists.openembedded.org/mt/106746173/1686489
> Group Owner: openembedded-core+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [alex.kanavin@gmail.com]
> -=-=-=-=-=-=-=-=-=-=-=-
>
Alejandro Enedino Hernandez Samaniego July 30, 2024, 7:15 p.m. UTC | #10
Sure thing, I'm in the process of doing so

On Tue, Jul 30, 2024, 1:00 PM Alexander Kanavin <alex.kanavin@gmail.com>
wrote:

> Can you submit the pending avoid_polluting_cross_directories.patch
> upstream please?
>
> Alex
>
> On Tue, 18 Jun 2024 at 20:09, Alejandro Hernandez Samaniego via
> lists.openembedded.org <alejandro=enedino.org@lists.openembedded.org>
> wrote:
> >
> > Enables usage of TCLIBC=picolibc extending OE functionality to build and
> use
> > picolibc based toolchains to build baremetal applications.
> >
> > Picolibc is a set of standard C libraries, both libc and libm, designed
> for
> > smaller embedded systems with limited ROM and RAM. Picolibc includes code
> > from Newlib and AVR Libc, but adresses some of newlibs concerns, it
> retains
> > newlibs directory structure, math, string and locale implementations, but
> > removed the GPL bits used to build the library, swiches old C style code
> for
> > C18 and replaces autotools with meson.
> >
> > This patch adds a picolibc recipe for the C library, a
> picolibc-helloworld
> > recipe that contains an example application and a testcase that builds
> it.
> >
> > Picolibc can be built for ARM and RISCV architectures, its been tested
> both
> > for 32 and 64 bits, the provided example recipe produces the following
> output:
> >
> > hello, world
> >
> > Runqemu does not automatically show any output since it hides QEMU
> stderr which
> > is where the QEMU monitors output is directed to when using semihosting,
> but,
> > manually running the same QEMU command does work properly.
> >
> > Signed-off-by: Alejandro Enedino Hernandez Samaniego <
> alejandro@enedino.org>
> > ---
> >  meta/classes-recipe/baremetal-image.bbclass   |   4 +-
> >  meta/classes-recipe/cross-canadian.bbclass    |   2 +-
> >  meta/conf/distro/include/maintainers.inc      |   2 +
> >  meta/conf/distro/include/tclibc-picolibc.inc  |  40 ++++++
> >  meta/conf/documentation.conf                  |   2 +-
> >  .../conf/machine/include/riscv/arch-riscv.inc |   1 +
> >  meta/lib/oeqa/selftest/cases/distrodata.py    |   2 +-
> >  meta/lib/oeqa/selftest/cases/picolibc.py      |  18 +++
> >  .../picolibc/picolibc-helloworld_git.bb       |  40 ++++++
> >  meta/recipes-core/picolibc/picolibc.inc       |  21 ++++
> >  .../avoid_polluting_cross_directories.patch   | 119 ++++++++++++++++++
> >  .../picolibc/no-early-compiler-checks.cross   |   6 +
> >  meta/recipes-core/picolibc/picolibc_git.bb    |  35 ++++++
> >  meta/recipes-devtools/gcc/gcc-cross.inc       |   1 +
> >  meta/recipes-devtools/gcc/gcc-runtime.inc     |   3 +
> >  meta/recipes-devtools/gcc/libgcc-common.inc   |   5 +
> >  16 files changed, 296 insertions(+), 5 deletions(-)
> >  create mode 100644 meta/conf/distro/include/tclibc-picolibc.inc
> >  create mode 100644 meta/lib/oeqa/selftest/cases/picolibc.py
> >  create mode 100644 meta/recipes-core/picolibc/
> picolibc-helloworld_git.bb
> >  create mode 100644 meta/recipes-core/picolibc/picolibc.inc
> >  create mode 100644
> meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> >  create mode 100644
> meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> >  create mode 100644 meta/recipes-core/picolibc/picolibc_git.bb
> >
> > diff --git a/meta/classes-recipe/baremetal-image.bbclass
> b/meta/classes-recipe/baremetal-image.bbclass
> > index 4e7d413626..27f2d2d10a 100644
> > --- a/meta/classes-recipe/baremetal-image.bbclass
> > +++ b/meta/classes-recipe/baremetal-image.bbclass
> > @@ -16,8 +16,8 @@
> >  # See meta-skeleton for a working example.
> >
> >
> > -# Toolchain should be baremetal or newlib based.
> > -# TCLIBC="baremetal" or TCLIBC="newlib"
> > +# Toolchain should be baremetal or newlib/picolibc based.
> > +# TCLIBC="baremetal" or TCLIBC="newlib" or TCLIBC="picolibc"
> >  COMPATIBLE_HOST:libc-musl:class-target = "null"
> >  COMPATIBLE_HOST:libc-glibc:class-target = "null"
> >
> > diff --git a/meta/classes-recipe/cross-canadian.bbclass
> b/meta/classes-recipe/cross-canadian.bbclass
> > index 1670217d69..059d9aa95f 100644
> > --- a/meta/classes-recipe/cross-canadian.bbclass
> > +++ b/meta/classes-recipe/cross-canadian.bbclass
> > @@ -36,7 +36,7 @@ python () {
> >      if d.getVar("MODIFYTOS") != "1":
> >          return
> >
> > -    if d.getVar("TCLIBC") in [ 'baremetal', 'newlib' ]:
> > +    if d.getVar("TCLIBC") in [ 'baremetal', 'newlib', 'picolibc' ]:
> >          return
> >
> >      tos = d.getVar("TARGET_OS")
> > diff --git a/meta/conf/distro/include/maintainers.inc
> b/meta/conf/distro/include/maintainers.inc
> > index 42599267c1..ff24597723 100644
> > --- a/meta/conf/distro/include/maintainers.inc
> > +++ b/meta/conf/distro/include/maintainers.inc
> > @@ -578,6 +578,8 @@ RECIPE_MAINTAINER:pn-pcmanfm = "Alexander Kanavin <
> alex.kanavin@gmail.com>"
> >  RECIPE_MAINTAINER:pn-perf = "Bruce Ashfield <bruce.ashfield@gmail.com>"
> >  RECIPE_MAINTAINER:pn-perl = "Alexander Kanavin <alex.kanavin@gmail.com
> >"
> >  RECIPE_MAINTAINER:pn-perlcross = "Alexander Kanavin <
> alex.kanavin@gmail.com>"
> > +RECIPE_MAINTAINER:pn-picolibc = "Alejandro Hernandez <
> alejandro@enedino.org>"
> > +RECIPE_MAINTAINER:pn-picolibc-helloworld = "Alejandro Hernandez <
> alejandro@enedino.org>"
> >  RECIPE_MAINTAINER:pn-piglit = "Ross Burton <ross.burton@arm.com>"
> >  RECIPE_MAINTAINER:pn-pigz = "Hongxu Jia <hongxu.jia@windriver.com>"
> >  RECIPE_MAINTAINER:pn-pinentry = "Unassigned <
> unassigned@yoctoproject.org>"
> > diff --git a/meta/conf/distro/include/tclibc-picolibc.inc
> b/meta/conf/distro/include/tclibc-picolibc.inc
> > new file mode 100644
> > index 0000000000..203765dfcb
> > --- /dev/null
> > +++ b/meta/conf/distro/include/tclibc-picolibc.inc
> > @@ -0,0 +1,40 @@
> > +#
> > +# Picolibc configuration
> > +#
> > +
> > +LIBCEXTENSION = "-picolibc"
> > +LIBCOVERRIDE = ":libc-picolibc"
> > +
> > +PREFERRED_PROVIDER_virtual/libc ?= "picolibc"
> > +PREFERRED_PROVIDER_virtual/libiconv ?= "picolibc"
> > +PREFERRED_PROVIDER_virtual/libintl ?= "picolibc"
> > +PREFERRED_PROVIDER_virtual/nativesdk-libintl ?= "nativesdk-glibc"
> > +PREFERRED_PROVIDER_virtual/nativesdk-libiconv ?= "nativesdk-glibc"
> > +
> > +DISTRO_FEATURES_BACKFILL_CONSIDERED += "ldconfig"
> > +
> > +IMAGE_LINGUAS = ""
> > +
> > +LIBC_DEPENDENCIES = " \
> > +    picolibc-dbg \
> > +    picolibc-dev \
> > +    libgcc-dev \
> > +    libgcc-dbg \
> > +    libstdc++-dev  \
> > +    libstdc++-staticdev \
> > +"
> > +
> > +ASSUME_PROVIDED += "virtual/crypt"
> > +
> > +TARGET_OS = "elf"
> > +TARGET_OS:arm = "eabi"
> > +
> > +TOOLCHAIN_HOST_TASK ?= "packagegroup-cross-canadian-${MACHINE}
> nativesdk-qemu nativesdk-sdk-provides-dummy"
> > +TOOLCHAIN_TARGET_TASK ?= "${LIBC_DEPENDENCIES}"
> > +TOOLCHAIN_NEED_CONFIGSITE_CACHE:remove = "zlib ncurses"
> > +
> > +# RISCV linker doesnt support PIE
> > +SECURITY_CFLAGS:libc-picolibc:qemuriscv32 = "${SECURITY_NOPIE_CFLAGS}"
> > +SECURITY_CFLAGS:libc-picolibc:qemuriscv64 = "${SECURITY_NOPIE_CFLAGS}"
> > +
> > +
> > diff --git a/meta/conf/documentation.conf b/meta/conf/documentation.conf
> > index b0591881ba..ad89142934 100644
> > --- a/meta/conf/documentation.conf
> > +++ b/meta/conf/documentation.conf
> > @@ -421,7 +421,7 @@ TARGET_FPU[doc] = "Specifies the method for handling
> FPU code. For FPU-less targ
> >  TARGET_OS[doc] = "Specifies the target's operating system."
> >  TARGET_PREFIX[doc] = "The prefix for the cross-compile toolchain (e.g.
> arm-linux-)."
> >  TARGET_SYS[doc] = "The target system is comprised of
> TARGET_ARCH,TARGET_VENDOR and TARGET_OS."
> > -TCLIBC[doc] = "Specifies C library (libc) variant to use during the
> build process. You can select 'baremetal', 'glibc', 'musl' or 'newlib'."
> > +TCLIBC[doc] = "Specifies C library (libc) variant to use during the
> build process. You can select 'baremetal', 'glibc', 'musl', 'newlib', or
> 'picolibc'."
> >  TCMODE[doc] = "Enables an external toolchain (where provided by an
> additional layer) if set to a value other than 'default'."
> >  TESTIMAGE_AUTO[doc] = "Enables test booting of virtual machine images
> under the QEMU emulator after any root filesystems are created and runs
> tests against those images each time an image is built."
> >  TEST_QEMUBOOT_TIMEOUT[doc] = "The time in seconds allowed for an image
> to boot before automated runtime tests begin to run against an image."
> > diff --git a/meta/conf/machine/include/riscv/arch-riscv.inc
> b/meta/conf/machine/include/riscv/arch-riscv.inc
> > index 230a266563..b34064e78f 100644
> > --- a/meta/conf/machine/include/riscv/arch-riscv.inc
> > +++ b/meta/conf/machine/include/riscv/arch-riscv.inc
> > @@ -11,5 +11,6 @@ TUNE_CCARGS:append =
> "${@bb.utils.contains('TUNE_FEATURES', 'riscv64nc', ' -marc
> >
> >  # Fix: ld: unrecognized option '--hash-style=sysv'
> >  LINKER_HASH_STYLE:libc-newlib = ""
> > +LINKER_HASH_STYLE:libc-picolibc = ""
> >  # Fix: ld: unrecognized option '--hash-style=gnu'
> >  LINKER_HASH_STYLE:libc-baremetal = ""
> > diff --git a/meta/lib/oeqa/selftest/cases/distrodata.py
> b/meta/lib/oeqa/selftest/cases/distrodata.py
> > index ad952c004b..043953757f 100644
> > --- a/meta/lib/oeqa/selftest/cases/distrodata.py
> > +++ b/meta/lib/oeqa/selftest/cases/distrodata.py
> > @@ -55,7 +55,7 @@ but their recipes claim otherwise by setting
> UPSTREAM_VERSION_UNKNOWN. Please re
> >              return False
> >
> >          def is_maintainer_exception(entry):
> > -            exceptions = ["musl", "newlib", "linux-yocto",
> "linux-dummy", "mesa-gl", "libgfortran", "libx11-compose-data",
> > +            exceptions = ["musl", "newlib", "picolibc", "linux-yocto",
> "linux-dummy", "mesa-gl", "libgfortran", "libx11-compose-data",
> >                            "cve-update-nvd2-native",]
> >              for i in exceptions:
> >                   if i in entry:
> > diff --git a/meta/lib/oeqa/selftest/cases/picolibc.py
> b/meta/lib/oeqa/selftest/cases/picolibc.py
> > new file mode 100644
> > index 0000000000..e40b4fc3d3
> > --- /dev/null
> > +++ b/meta/lib/oeqa/selftest/cases/picolibc.py
> > @@ -0,0 +1,18 @@
> > +#
> > +# Copyright OpenEmbedded Contributors
> > +#
> > +# SPDX-License-Identifier: MIT
> > +#
> > +
> > +from oeqa.selftest.case import OESelftestTestCase
> > +from oeqa.utils.commands import bitbake, get_bb_var
> > +
> > +class PicolibcTest(OESelftestTestCase):
> > +
> > +    def test_picolibc(self):
> > +        compatible_machines = ['qemuarm', 'qemuarm64', 'qemuriscv32',
> 'qemuriscv64']
> > +        machine = get_bb_var('MACHINE')
> > +        if machine not in compatible_machines:
> > +            self.skipTest('This test only works with machines : %s' % '
> '.join(compatible_machines))
> > +        self.write_config('TCLIBC = "picolibc"')
> > +        bitbake("picolibc-helloworld")
> > diff --git a/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
> b/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
> > new file mode 100644
> > index 0000000000..573a571c24
> > --- /dev/null
> > +++ b/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
> > @@ -0,0 +1,40 @@
> > +require picolibc.inc
> > +
> > +# baremetal-image overrides
> > +BAREMETAL_BINNAME ?= "hello_picolibc_${MACHINE}"
> > +IMAGE_LINK_NAME ?= "baremetal-picolibc-image-${MACHINE}"
> > +IMAGE_NAME_SUFFIX ?= ""
> > +QB_DEFAULT_KERNEL ?= "${IMAGE_LINK_NAME}.elf"
> > +
> > +inherit baremetal-image
> > +
> > +COMPATIBLE_MACHINE = "qemuarm|qemuarm64|qemuriscv32|qemuriscv64"
> > +
> > +# Use semihosting to test via QEMU
> > +QB_OPT_APPEND:append = " -semihosting-config enable=on"
> > +
> > +# picolibc comes with a set of linker scripts, set the file
> > +# according to the architecture being built.
> > +PICOLIBC_LINKERSCRIPT:qemuarm64 = "aarch64.ld"
> > +PICOLIBC_LINKERSCRIPT:qemuarm = "arm.ld"
> > +PICOLIBC_LINKERSCRIPT:qemuriscv32 = "riscv.ld"
> > +PICOLIBC_LINKERSCRIPT:qemuriscv64 = "riscv.ld"
> > +
> > +# Simple compile function that manually exemplifies usage; as noted,
> > +# use a custom linker script, the GCC specs provided by picolibc
> > +# and semihost to be able to test via QEMU's monitor
> > +do_compile(){
> > +    ${CC} ${CFLAGS} ${LDFLAGS} --verbose
> -T${S}/hello-world/${PICOLIBC_LINKERSCRIPT} -specs=picolibc.specs
> --oslib=semihost -o ${BAREMETAL_BINNAME}.elf ${S}/hello-world/hello-world.c
> > +    ${OBJCOPY} -O binary ${BAREMETAL_BINNAME}.elf
> ${BAREMETAL_BINNAME}.bin
> > +}
> > +
> > +do_install(){
> > +    install -d ${D}/${base_libdir}/firmware
> > +    install -m 755 ${B}/${BAREMETAL_BINNAME}.elf
> ${D}/${base_libdir}/firmware/${BAREMETAL_BINNAME}.elf
> > +    install -m 755 ${B}/${BAREMETAL_BINNAME}.bin
> ${D}/${base_libdir}/firmware/${BAREMETAL_BINNAME}.bin
> > +}
> > +
> > +FILES:${PN} += " \
> > +    ${base_libdir}/firmware/${BAREMETAL_BINNAME}.elf \
> > +    ${base_libdir}/firmware/${BAREMETAL_BINNAME}.bin \
> > +"
> > diff --git a/meta/recipes-core/picolibc/picolibc.inc
> b/meta/recipes-core/picolibc/picolibc.inc
> > new file mode 100644
> > index 0000000000..3b380fe7af
> > --- /dev/null
> > +++ b/meta/recipes-core/picolibc/picolibc.inc
> > @@ -0,0 +1,21 @@
> > +SUMMARY = "C Libraries for Smaller Embedded Systems"
> > +HOMEPAGE = "https://keithp.com/picolibc"
> > +DESCRIPTION = "Picolibc is a set of standard C libraries, both libc and
> libm, designed for smaller embedded systems with limited ROM and RAM.
> Picolibc includes code from Newlib and AVR Libc."
> > +SECTION = "libs"
> > +
> > +# Newlib based code but GPL related bits removed, test/printf-tests.c
> and test/testcases.c
> > +# are GPLv2 and GeneratePicolibcCrossFile.sh is AGPL3 but not part of
> the artifacts.
> > +LICENSE = "BSD-2-Clause & BSD-3-Clause"
> > +LIC_FILES_CHKSUM = " \
> > +               file://COPYING.GPL2;md5=59530bdf33659b29e73d4adb9f9f6552
> \
> > +
>  file://COPYING.NEWLIB;md5=08ae03456feb75b81cfdb359e0f1ef85 \
> > +
>  file://COPYING.picolibc;md5=e50fa9458a40929689861ed472d46bc7 \
> > +               "
> > +
> > +BASEVER = "1.8.6"
> > +PV = "${BASEVER}+git"
> > +SRC_URI = "git://
> github.com/picolibc/picolibc.git;protocol=https;branch=main"
> > +SRCREV="764ef4e401a8f4c6a86ab723533841f072885a5b"
> > +
> > +S = "${WORKDIR}/git"
> > +B = "${WORKDIR}/build"
> > diff --git
> a/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> b/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> > new file mode 100644
> > index 0000000000..da6460c95c
> > --- /dev/null
> > +++
> b/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
> > @@ -0,0 +1,119 @@
> > +Upstream-Status: Pending
> > +
> > +Picolibc uses its own specs file: picolibc.specs to facilitate
> compilation, this
> > +needs to be passed down to GCC via the -specs argument.
> > +
> > +Using this specs file overrides some of the default options our
> toolchain was
> > +built with, in this case, they modify the include_dir and lib_dir paths
> used for
> > +compilation, their intention was to add support for -picolibc-prefix and
> > +-picolibc-buildtype arguments via the C preprocessor.
> > +
> > +-isystem %{-picolibc-prefix=*:%*/include/;
> -picolibc-buildtype=*:/usr/include/%*; :/usr/include} %(picolibc_cpp)
> > +
> > +This had the unwanted effect of defaulting to /usr/include for
> include_dir if
> > +those arguments are not being passed, this works fine for their flow
> but for us
> > +it pollutes the include directories with paths from the host. The same
> effect is
> > +applicable for lib_dir and for the c runtime file.
> > +
> > +Our toolchain relies on --sysroot to avoid using any paths from the
> host, here we
> > +manually add support for a third possible argument: -sysroot , if this
> is passed
> > +then the paths used by the compiler will be relative to the path passed
> by the
> > +--sysroot= cmdline argument, setting back the behavior that we intended
> in the
> > +first place.
> > +
> > +
> > +Signed-off-by: Alejandro Enedino Hernandez Samaniego <
> alejandro@enedino.org>
> > +
> > +Index: git/meson.build
> > +===================================================================
> > +--- git.orig/meson.build
> > ++++ git/meson.build
> > +@@ -622,12 +622,13 @@ else
> > + #
> > + picolibc_prefix_format = '-picolibc-prefix=*:@0@'
> > + picolibc_buildtype_format = '-picolibc-buildtype=*:@0@'
> > ++sysroot_format = '-sysroot=*:@0@'
> > + gen_format = '@0@'
> > +
> > + #
> > + # How to glue the three options together
> > + #
> > +-specs_option_format = '%{@0@; @1@; :@2@}'
> > ++specs_option_format = '%{@0@; @1@; @2@; :@3@}'
> > +
> > + #
> > + # Build the -isystem value
> > +@@ -639,10 +640,13 @@ isystem_prefix = picolibc_prefix_format.
> > + buildtype_include_dir =
> specs_prefix_format.format(get_option('includedir') / '%*')
> > + isystem_buildtype =
> picolibc_buildtype_format.format(buildtype_include_dir)
> > +
> > ++sysroot_include_dir = '%*'
> > ++isystem_sysroot = sysroot_format.format(sysroot_include_dir)
> > ++
> > + gen_include_dir = specs_prefix_format.format(get_option('includedir'))
> > + isystem_gen = gen_format.format(gen_include_dir)
> > +
> > +-specs_isystem = '-isystem ' +
> specs_option_format.format(isystem_prefix, isystem_buildtype, isystem_gen)
> > ++specs_isystem = '-isystem ' +
> specs_option_format.format(isystem_prefix, isystem_buildtype,
> isystem_sysroot, isystem_gen)
> > +
> > + #
> > + # Build the non-multilib -L value
> > +@@ -654,10 +658,13 @@ lib_prefix = picolibc_prefix_format.form
> > + buildtype_lib_dir = specs_prefix_format.format(get_option('libdir') /
> '%*')
> > + lib_buildtype = picolibc_buildtype_format.format(buildtype_lib_dir)
> > +
> > ++sysroot_lib_dir = '%*'
> > ++lib_sysroot = sysroot_format.format(sysroot_lib_dir)
> > ++
> > + gen_lib_dir = specs_prefix_format.format(get_option('libdir'))
> > + lib_gen = gen_format.format(gen_lib_dir)
> > +
> > +-specs_libpath = '-L' + specs_option_format.format(lib_prefix,
> lib_buildtype, lib_gen)
> > ++specs_libpath = '-L' + specs_option_format.format(lib_prefix,
> lib_buildtype, lib_sysroot, lib_gen)
> > +
> > + #
> > + # Build the non-multilib *startfile options
> > +@@ -669,6 +676,9 @@ crt0_prefix = picolibc_prefix_format.for
> > + buildtype_crt0_path = specs_prefix_format.format(get_option('libdir')
> / '%*' / crt0_expr)
> > + crt0_buildtype = picolibc_buildtype_format.format(buildtype_crt0_path)
> > +
> > ++sysroot_crt0_path = '%*' + '/' + get_option('libdir') + '/' + '%*' +
> '/' + crt0_expr
> > ++crt0_sysroot = picolibc_buildtype_format.format(sysroot_crt0_path)
> > ++
> > + gen_crt0_path = specs_prefix_format.format(get_option('libdir') /
> crt0_expr)
> > + crt0_gen = gen_format.format(gen_crt0_path)
> > +
> > +@@ -686,10 +696,13 @@ if enable_multilib
> > +   buildtype_multilib_dir =
> specs_prefix_format.format(get_option('libdir') / '%*/%M')
> > +   multilib_buildtype =
> picolibc_buildtype_format.format(buildtype_multilib_dir)
> > +
> > ++  sysroot_multilib_dir = '%*' + '/' + get_option('libdir') + '/' +
> '%*/%M'
> > ++  multilib_sysroot = sysroot_format.format(sysroot_multilib_dir)
> > ++
> > +   gen_multilib_dir = specs_prefix_format.format(get_option('libdir') /
> '%M')
> > +   multilib_gen = gen_format.format(gen_multilib_dir)
> > +
> > +-  specs_multilibpath = '-L' +
> specs_option_format.format(multilib_prefix, multilib_buildtype,
> multilib_gen)
> > ++  specs_multilibpath = '-L' +
> specs_option_format.format(multilib_prefix, multilib_buildtype,
> multilib_sysroot, multilib_gen)
> > +
> > +   #
> > +   # Prepend the multilib -L option to the non-multilib option
> > +@@ -705,6 +718,9 @@ if enable_multilib
> > +   buildtype_multilib_crt0_path =
> specs_prefix_format.format(get_option('libdir') / '%*/%M' / crt0_expr)
> > +   crt0_buildtype =
> picolibc_buildtype_format.format(buildtype_multilib_crt0_path)
> > +
> > ++  sysroot_multilib_crt0_path = '%*' + prefix + '/' +
> get_option('libdir') + '/' + '/%M' + '/' + crt0_expr
> > ++  crt0_sysroot = sysroot_format.format(sysroot_multilib_crt0_path)
> > ++
> > +   gen_multilib_crt0_path =
> specs_prefix_format.format(get_option('libdir') / '%M' / crt0_expr)
> > +   crt0_gen = gen_format.format(gen_multilib_crt0_path)
> > + endif
> > +@@ -714,7 +730,7 @@ endif
> > + # above. As there's only one value, it's either the
> > + # multilib path or the non-multilib path
> > + #
> > +-specs_startfile = specs_option_format.format(crt0_prefix,
> crt0_buildtype, crt0_gen)
> > ++specs_startfile = specs_option_format.format(crt0_prefix,
> crt0_buildtype, crt0_sysroot, crt0_gen)
> > + endif
> > +
> > + specs_data = configuration_data()
> > diff --git
> a/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> b/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> > new file mode 100644
> > index 0000000000..87bfbad3c5
> > --- /dev/null
> > +++ b/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
> > @@ -0,0 +1,6 @@
> > +# We need to explicitly bypass mesons sanity check to avoid early
> compiler errors
> > +# otherwise meson will try to compile AND run test applications:
> > +# ../git/meson.build:35:0: ERROR: Executables created by c compiler are
> not runnable...
> > +
> > +[properties]
> > +skip_sanity_check=true
> > \ No newline at end of file
> > diff --git a/meta/recipes-core/picolibc/picolibc_git.bb
> b/meta/recipes-core/picolibc/picolibc_git.bb
> > new file mode 100644
> > index 0000000000..fdb159328f
> > --- /dev/null
> > +++ b/meta/recipes-core/picolibc/picolibc_git.bb
> > @@ -0,0 +1,35 @@
> > +require picolibc.inc
> > +
> > +INHIBIT_DEFAULT_DEPS = "1"
> > +DEPENDS = "virtual/${TARGET_PREFIX}gcc"
> > +
> > +PROVIDES += "virtual/libc virtual/libiconv virtual/libintl"
> > +
> > +COMPATIBLE_HOST:libc-musl:class-target = "null"
> > +COMPATIBLE_HOST:libc-glibc:class-target = "null"
> > +COMPATIBLE_MACHINE = "qemuarm|qemuarm64|qemuriscv32|qemuriscv64"
> > +
> > +SRC_URI:append = " file://avoid_polluting_cross_directories.patch"
> > +SRC_URI:append = " file://no-early-compiler-checks.cross"
> > +
> > +# This is being added by picolibc meson files as well to avoid
> > +# early compiler tests from failing, cant remember why I added it
> > +# to the newlib recipe but I would assume it was for the same reason
> > +TARGET_CC_ARCH:append = " -nostdlib"
> > +
> > +# When using RISCV64 use medany for both C library and application
> recipes
> > +TARGET_CFLAGS:append:qemuriscv64 = " -mcmodel=medany"
> > +
> > +inherit meson
> > +
> > +MESON_CROSS_FILE:append = "
> --cross-file=${UNPACKDIR}/no-early-compiler-checks.cross"
> > +
> > +PACKAGECONFIG ??= " specsdir"
> > +# Install GCC specs on libdir
> > +PACKAGECONFIG[specsdir] = "-Dspecsdir=${libdir},-Dspecsdir=none"
> > +
> > +
> > +FILES:${PN}-dev:append = " ${libdir}/*.specs ${libdir}/*.ld"
> > +
> > +# No rpm package is actually created but -dev depends on it, avoid dnf
> error
> > +DEV_PKG_DEPENDENCY:libc-picolibc = ""
> > diff --git a/meta/recipes-devtools/gcc/gcc-cross.inc
> b/meta/recipes-devtools/gcc/gcc-cross.inc
> > index 5b0ca15d47..c04177df5a 100644
> > --- a/meta/recipes-devtools/gcc/gcc-cross.inc
> > +++ b/meta/recipes-devtools/gcc/gcc-cross.inc
> > @@ -34,6 +34,7 @@ EXTRA_OECONF += "\
> >  EXTRA_OECONF:append:libc-baremetal = " --without-headers"
> >  EXTRA_OECONF:remove:libc-baremetal = "--enable-threads=posix"
> >  EXTRA_OECONF:remove:libc-newlib = "--enable-threads=posix"
> > +EXTRA_OECONF:remove:libc-picolibc = "--enable-threads=posix"
> >
> >  EXTRA_OECONF_PATHS = "\
> >      --with-gxx-include-dir=/not/exist${target_includedir}/c++/${BINV} \
> > diff --git a/meta/recipes-devtools/gcc/gcc-runtime.inc
> b/meta/recipes-devtools/gcc/gcc-runtime.inc
> > index 89b0bebcfb..1fca00f5f0 100644
> > --- a/meta/recipes-devtools/gcc/gcc-runtime.inc
> > +++ b/meta/recipes-devtools/gcc/gcc-runtime.inc
> > @@ -17,6 +17,7 @@ EXTRA_OECONF_PATHS = "\
> >  EXTRA_OECONF:append:linuxstdbase = " --enable-clocale=gnu"
> >  EXTRA_OECONF:append = " --cache-file=${B}/config.cache"
> >  EXTRA_OECONF:append:libc-newlib = " --with-newlib --with-target-subdir"
> > +EXTRA_OECONF:append:libc-picolibc = " --with-newlib
> --with-target-subdir"
> >  EXTRA_OECONF:append:libc-baremetal = " --with-target-subdir"
> >
> >  # Disable ifuncs for libatomic on arm conflicts -march/-mcpu
> > @@ -27,6 +28,7 @@ DISABLE_STATIC:class-nativesdk ?= ""
> >
> >  # Newlib does not support symbol versioning on libsdtcc++
> >  SYMVERS_CONF:libc-newlib = ""
> > +SYMVERS_CONF:libc-picolibc = ""
> >
> >  # Building with thumb enabled on armv6t fails
> >  ARM_INSTRUCTION_SET:armv6 = "arm"
> > @@ -47,6 +49,7 @@ RUNTIMETARGET = "${RUNTIMELIBSSP} libstdc++-v3 libgomp
> libatomic ${RUNTIMELIBITM
> >  "
> >  # Only build libstdc++ for newlib
> >  RUNTIMETARGET:libc-newlib = "libstdc++-v3"
> > +RUNTIMETARGET:libc-picolibc = "libstdc++-v3"
> >
> >  # libiberty
> >  # libgfortran needs separate recipe due to libquadmath dependency
> > diff --git a/meta/recipes-devtools/gcc/libgcc-common.inc
> b/meta/recipes-devtools/gcc/libgcc-common.inc
> > index d9084af51a..e3db17d700 100644
> > --- a/meta/recipes-devtools/gcc/libgcc-common.inc
> > +++ b/meta/recipes-devtools/gcc/libgcc-common.inc
> > @@ -53,6 +53,11 @@ do_install:append:libc-newlib () {
> >                 rmdir ${D}${base_libdir}
> >         fi
> >  }
> > +do_install:append:libc-picolibc () {
> > +       if [ "${base_libdir}" != "${libdir}" ]; then
> > +               rmdir ${D}${base_libdir}
> > +       fi
> > +}
> >
> >  # No rpm package is actually created but -dev depends on it, avoid dnf
> error
> >  DEV_PKG_DEPENDENCY:libc-baremetal = ""
> > --
> > 2.45.2
> >
> >
> >
> >
>
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#202682):
> https://lists.openembedded.org/g/openembedded-core/message/202682
> Mute This Topic: https://lists.openembedded.org/mt/106746173/3619605
> Group Owner: openembedded-core+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [
> alejandro@enedino.org]
> -=-=-=-=-=-=-=-=-=-=-=-
>
>
diff mbox series

Patch

diff --git a/meta/classes-recipe/baremetal-image.bbclass b/meta/classes-recipe/baremetal-image.bbclass
index 4e7d413626..27f2d2d10a 100644
--- a/meta/classes-recipe/baremetal-image.bbclass
+++ b/meta/classes-recipe/baremetal-image.bbclass
@@ -16,8 +16,8 @@ 
 # See meta-skeleton for a working example.
 
 
-# Toolchain should be baremetal or newlib based.
-# TCLIBC="baremetal" or TCLIBC="newlib"
+# Toolchain should be baremetal or newlib/picolibc based.
+# TCLIBC="baremetal" or TCLIBC="newlib" or TCLIBC="picolibc"
 COMPATIBLE_HOST:libc-musl:class-target = "null"
 COMPATIBLE_HOST:libc-glibc:class-target = "null"
 
diff --git a/meta/classes-recipe/cross-canadian.bbclass b/meta/classes-recipe/cross-canadian.bbclass
index 1670217d69..059d9aa95f 100644
--- a/meta/classes-recipe/cross-canadian.bbclass
+++ b/meta/classes-recipe/cross-canadian.bbclass
@@ -36,7 +36,7 @@  python () {
     if d.getVar("MODIFYTOS") != "1":
         return
 
-    if d.getVar("TCLIBC") in [ 'baremetal', 'newlib' ]:
+    if d.getVar("TCLIBC") in [ 'baremetal', 'newlib', 'picolibc' ]:
         return
 
     tos = d.getVar("TARGET_OS")
diff --git a/meta/conf/distro/include/maintainers.inc b/meta/conf/distro/include/maintainers.inc
index 42599267c1..ff24597723 100644
--- a/meta/conf/distro/include/maintainers.inc
+++ b/meta/conf/distro/include/maintainers.inc
@@ -578,6 +578,8 @@  RECIPE_MAINTAINER:pn-pcmanfm = "Alexander Kanavin <alex.kanavin@gmail.com>"
 RECIPE_MAINTAINER:pn-perf = "Bruce Ashfield <bruce.ashfield@gmail.com>"
 RECIPE_MAINTAINER:pn-perl = "Alexander Kanavin <alex.kanavin@gmail.com>"
 RECIPE_MAINTAINER:pn-perlcross = "Alexander Kanavin <alex.kanavin@gmail.com>"
+RECIPE_MAINTAINER:pn-picolibc = "Alejandro Hernandez <alejandro@enedino.org>"
+RECIPE_MAINTAINER:pn-picolibc-helloworld = "Alejandro Hernandez <alejandro@enedino.org>"
 RECIPE_MAINTAINER:pn-piglit = "Ross Burton <ross.burton@arm.com>"
 RECIPE_MAINTAINER:pn-pigz = "Hongxu Jia <hongxu.jia@windriver.com>"
 RECIPE_MAINTAINER:pn-pinentry = "Unassigned <unassigned@yoctoproject.org>"
diff --git a/meta/conf/distro/include/tclibc-picolibc.inc b/meta/conf/distro/include/tclibc-picolibc.inc
new file mode 100644
index 0000000000..203765dfcb
--- /dev/null
+++ b/meta/conf/distro/include/tclibc-picolibc.inc
@@ -0,0 +1,40 @@ 
+#
+# Picolibc configuration
+#
+
+LIBCEXTENSION = "-picolibc"
+LIBCOVERRIDE = ":libc-picolibc"
+
+PREFERRED_PROVIDER_virtual/libc ?= "picolibc"
+PREFERRED_PROVIDER_virtual/libiconv ?= "picolibc"
+PREFERRED_PROVIDER_virtual/libintl ?= "picolibc"
+PREFERRED_PROVIDER_virtual/nativesdk-libintl ?= "nativesdk-glibc"
+PREFERRED_PROVIDER_virtual/nativesdk-libiconv ?= "nativesdk-glibc"
+
+DISTRO_FEATURES_BACKFILL_CONSIDERED += "ldconfig"
+
+IMAGE_LINGUAS = ""
+
+LIBC_DEPENDENCIES = " \
+    picolibc-dbg \
+    picolibc-dev \
+    libgcc-dev \
+    libgcc-dbg \
+    libstdc++-dev  \
+    libstdc++-staticdev \
+"
+
+ASSUME_PROVIDED += "virtual/crypt"
+
+TARGET_OS = "elf"
+TARGET_OS:arm = "eabi"
+
+TOOLCHAIN_HOST_TASK ?= "packagegroup-cross-canadian-${MACHINE} nativesdk-qemu nativesdk-sdk-provides-dummy"
+TOOLCHAIN_TARGET_TASK ?= "${LIBC_DEPENDENCIES}"
+TOOLCHAIN_NEED_CONFIGSITE_CACHE:remove = "zlib ncurses"
+
+# RISCV linker doesnt support PIE
+SECURITY_CFLAGS:libc-picolibc:qemuriscv32 = "${SECURITY_NOPIE_CFLAGS}"
+SECURITY_CFLAGS:libc-picolibc:qemuriscv64 = "${SECURITY_NOPIE_CFLAGS}"
+
+
diff --git a/meta/conf/documentation.conf b/meta/conf/documentation.conf
index b0591881ba..ad89142934 100644
--- a/meta/conf/documentation.conf
+++ b/meta/conf/documentation.conf
@@ -421,7 +421,7 @@  TARGET_FPU[doc] = "Specifies the method for handling FPU code. For FPU-less targ
 TARGET_OS[doc] = "Specifies the target's operating system."
 TARGET_PREFIX[doc] = "The prefix for the cross-compile toolchain (e.g. arm-linux-)."
 TARGET_SYS[doc] = "The target system is comprised of TARGET_ARCH,TARGET_VENDOR and TARGET_OS."
-TCLIBC[doc] = "Specifies C library (libc) variant to use during the build process. You can select 'baremetal', 'glibc', 'musl' or 'newlib'."
+TCLIBC[doc] = "Specifies C library (libc) variant to use during the build process. You can select 'baremetal', 'glibc', 'musl', 'newlib', or 'picolibc'."
 TCMODE[doc] = "Enables an external toolchain (where provided by an additional layer) if set to a value other than 'default'."
 TESTIMAGE_AUTO[doc] = "Enables test booting of virtual machine images under the QEMU emulator after any root filesystems are created and runs tests against those images each time an image is built."
 TEST_QEMUBOOT_TIMEOUT[doc] = "The time in seconds allowed for an image to boot before automated runtime tests begin to run against an image."
diff --git a/meta/conf/machine/include/riscv/arch-riscv.inc b/meta/conf/machine/include/riscv/arch-riscv.inc
index 230a266563..b34064e78f 100644
--- a/meta/conf/machine/include/riscv/arch-riscv.inc
+++ b/meta/conf/machine/include/riscv/arch-riscv.inc
@@ -11,5 +11,6 @@  TUNE_CCARGS:append = "${@bb.utils.contains('TUNE_FEATURES', 'riscv64nc', ' -marc
 
 # Fix: ld: unrecognized option '--hash-style=sysv'
 LINKER_HASH_STYLE:libc-newlib = ""
+LINKER_HASH_STYLE:libc-picolibc = ""
 # Fix: ld: unrecognized option '--hash-style=gnu'
 LINKER_HASH_STYLE:libc-baremetal = ""
diff --git a/meta/lib/oeqa/selftest/cases/distrodata.py b/meta/lib/oeqa/selftest/cases/distrodata.py
index ad952c004b..043953757f 100644
--- a/meta/lib/oeqa/selftest/cases/distrodata.py
+++ b/meta/lib/oeqa/selftest/cases/distrodata.py
@@ -55,7 +55,7 @@  but their recipes claim otherwise by setting UPSTREAM_VERSION_UNKNOWN. Please re
             return False
 
         def is_maintainer_exception(entry):
-            exceptions = ["musl", "newlib", "linux-yocto", "linux-dummy", "mesa-gl", "libgfortran", "libx11-compose-data",
+            exceptions = ["musl", "newlib", "picolibc", "linux-yocto", "linux-dummy", "mesa-gl", "libgfortran", "libx11-compose-data",
                           "cve-update-nvd2-native",]
             for i in exceptions:
                  if i in entry:
diff --git a/meta/lib/oeqa/selftest/cases/picolibc.py b/meta/lib/oeqa/selftest/cases/picolibc.py
new file mode 100644
index 0000000000..e40b4fc3d3
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/picolibc.py
@@ -0,0 +1,18 @@ 
+#
+# Copyright OpenEmbedded Contributors
+#
+# SPDX-License-Identifier: MIT
+#
+
+from oeqa.selftest.case import OESelftestTestCase
+from oeqa.utils.commands import bitbake, get_bb_var
+
+class PicolibcTest(OESelftestTestCase):
+
+    def test_picolibc(self):
+        compatible_machines = ['qemuarm', 'qemuarm64', 'qemuriscv32', 'qemuriscv64']
+        machine = get_bb_var('MACHINE')
+        if machine not in compatible_machines:
+            self.skipTest('This test only works with machines : %s' % ' '.join(compatible_machines))
+        self.write_config('TCLIBC = "picolibc"')
+        bitbake("picolibc-helloworld")
diff --git a/meta/recipes-core/picolibc/picolibc-helloworld_git.bb b/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
new file mode 100644
index 0000000000..573a571c24
--- /dev/null
+++ b/meta/recipes-core/picolibc/picolibc-helloworld_git.bb
@@ -0,0 +1,40 @@ 
+require picolibc.inc
+
+# baremetal-image overrides
+BAREMETAL_BINNAME ?= "hello_picolibc_${MACHINE}"
+IMAGE_LINK_NAME ?= "baremetal-picolibc-image-${MACHINE}"
+IMAGE_NAME_SUFFIX ?= ""
+QB_DEFAULT_KERNEL ?= "${IMAGE_LINK_NAME}.elf"
+
+inherit baremetal-image
+
+COMPATIBLE_MACHINE = "qemuarm|qemuarm64|qemuriscv32|qemuriscv64"
+
+# Use semihosting to test via QEMU
+QB_OPT_APPEND:append = " -semihosting-config enable=on"
+
+# picolibc comes with a set of linker scripts, set the file
+# according to the architecture being built.
+PICOLIBC_LINKERSCRIPT:qemuarm64 = "aarch64.ld"
+PICOLIBC_LINKERSCRIPT:qemuarm = "arm.ld"
+PICOLIBC_LINKERSCRIPT:qemuriscv32 = "riscv.ld"
+PICOLIBC_LINKERSCRIPT:qemuriscv64 = "riscv.ld"
+
+# Simple compile function that manually exemplifies usage; as noted,
+# use a custom linker script, the GCC specs provided by picolibc
+# and semihost to be able to test via QEMU's monitor
+do_compile(){
+    ${CC} ${CFLAGS} ${LDFLAGS} --verbose -T${S}/hello-world/${PICOLIBC_LINKERSCRIPT} -specs=picolibc.specs --oslib=semihost -o ${BAREMETAL_BINNAME}.elf ${S}/hello-world/hello-world.c
+    ${OBJCOPY} -O binary ${BAREMETAL_BINNAME}.elf ${BAREMETAL_BINNAME}.bin
+}
+
+do_install(){
+    install -d ${D}/${base_libdir}/firmware
+    install -m 755 ${B}/${BAREMETAL_BINNAME}.elf ${D}/${base_libdir}/firmware/${BAREMETAL_BINNAME}.elf
+    install -m 755 ${B}/${BAREMETAL_BINNAME}.bin ${D}/${base_libdir}/firmware/${BAREMETAL_BINNAME}.bin
+}
+
+FILES:${PN} += " \
+    ${base_libdir}/firmware/${BAREMETAL_BINNAME}.elf \
+    ${base_libdir}/firmware/${BAREMETAL_BINNAME}.bin \
+"
diff --git a/meta/recipes-core/picolibc/picolibc.inc b/meta/recipes-core/picolibc/picolibc.inc
new file mode 100644
index 0000000000..3b380fe7af
--- /dev/null
+++ b/meta/recipes-core/picolibc/picolibc.inc
@@ -0,0 +1,21 @@ 
+SUMMARY = "C Libraries for Smaller Embedded Systems"
+HOMEPAGE = "https://keithp.com/picolibc"
+DESCRIPTION = "Picolibc is a set of standard C libraries, both libc and libm, designed for smaller embedded systems with limited ROM and RAM. Picolibc includes code from Newlib and AVR Libc."
+SECTION = "libs"
+
+# Newlib based code but GPL related bits removed, test/printf-tests.c and test/testcases.c
+# are GPLv2 and GeneratePicolibcCrossFile.sh is AGPL3 but not part of the artifacts.
+LICENSE = "BSD-2-Clause & BSD-3-Clause"
+LIC_FILES_CHKSUM = " \
+		file://COPYING.GPL2;md5=59530bdf33659b29e73d4adb9f9f6552 \
+		file://COPYING.NEWLIB;md5=08ae03456feb75b81cfdb359e0f1ef85 \
+		file://COPYING.picolibc;md5=e50fa9458a40929689861ed472d46bc7 \
+		"
+
+BASEVER = "1.8.6"
+PV = "${BASEVER}+git"
+SRC_URI = "git://github.com/picolibc/picolibc.git;protocol=https;branch=main"
+SRCREV="764ef4e401a8f4c6a86ab723533841f072885a5b"
+
+S = "${WORKDIR}/git"
+B = "${WORKDIR}/build"
diff --git a/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch b/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
new file mode 100644
index 0000000000..da6460c95c
--- /dev/null
+++ b/meta/recipes-core/picolibc/picolibc/avoid_polluting_cross_directories.patch
@@ -0,0 +1,119 @@ 
+Upstream-Status: Pending
+
+Picolibc uses its own specs file: picolibc.specs to facilitate compilation, this
+needs to be passed down to GCC via the -specs argument.
+
+Using this specs file overrides some of the default options our toolchain was
+built with, in this case, they modify the include_dir and lib_dir paths used for
+compilation, their intention was to add support for -picolibc-prefix and
+-picolibc-buildtype arguments via the C preprocessor.
+
+-isystem %{-picolibc-prefix=*:%*/include/; -picolibc-buildtype=*:/usr/include/%*; :/usr/include} %(picolibc_cpp)
+
+This had the unwanted effect of defaulting to /usr/include for include_dir if
+those arguments are not being passed, this works fine for their flow but for us
+it pollutes the include directories with paths from the host. The same effect is
+applicable for lib_dir and for the c runtime file.
+
+Our toolchain relies on --sysroot to avoid using any paths from the host, here we
+manually add support for a third possible argument: -sysroot , if this is passed
+then the paths used by the compiler will be relative to the path passed by the
+--sysroot= cmdline argument, setting back the behavior that we intended in the
+first place.
+
+
+Signed-off-by: Alejandro Enedino Hernandez Samaniego <alejandro@enedino.org>
+
+Index: git/meson.build
+===================================================================
+--- git.orig/meson.build
++++ git/meson.build
+@@ -622,12 +622,13 @@ else
+ #
+ picolibc_prefix_format = '-picolibc-prefix=*:@0@'
+ picolibc_buildtype_format = '-picolibc-buildtype=*:@0@'
++sysroot_format = '-sysroot=*:@0@'
+ gen_format = '@0@'
+ 
+ #
+ # How to glue the three options together
+ #
+-specs_option_format = '%{@0@; @1@; :@2@}'
++specs_option_format = '%{@0@; @1@; @2@; :@3@}'
+ 
+ #
+ # Build the -isystem value
+@@ -639,10 +640,13 @@ isystem_prefix = picolibc_prefix_format.
+ buildtype_include_dir = specs_prefix_format.format(get_option('includedir') / '%*')
+ isystem_buildtype = picolibc_buildtype_format.format(buildtype_include_dir)
+ 
++sysroot_include_dir = '%*'
++isystem_sysroot = sysroot_format.format(sysroot_include_dir)
++
+ gen_include_dir = specs_prefix_format.format(get_option('includedir'))
+ isystem_gen = gen_format.format(gen_include_dir)
+ 
+-specs_isystem = '-isystem ' + specs_option_format.format(isystem_prefix, isystem_buildtype, isystem_gen)
++specs_isystem = '-isystem ' + specs_option_format.format(isystem_prefix, isystem_buildtype, isystem_sysroot, isystem_gen)
+ 
+ #
+ # Build the non-multilib -L value
+@@ -654,10 +658,13 @@ lib_prefix = picolibc_prefix_format.form
+ buildtype_lib_dir = specs_prefix_format.format(get_option('libdir') / '%*')
+ lib_buildtype = picolibc_buildtype_format.format(buildtype_lib_dir)
+ 
++sysroot_lib_dir = '%*'
++lib_sysroot = sysroot_format.format(sysroot_lib_dir)
++
+ gen_lib_dir = specs_prefix_format.format(get_option('libdir'))
+ lib_gen = gen_format.format(gen_lib_dir)
+ 
+-specs_libpath = '-L' + specs_option_format.format(lib_prefix, lib_buildtype, lib_gen)
++specs_libpath = '-L' + specs_option_format.format(lib_prefix, lib_buildtype, lib_sysroot, lib_gen)
+ 
+ #
+ # Build the non-multilib *startfile options
+@@ -669,6 +676,9 @@ crt0_prefix = picolibc_prefix_format.for
+ buildtype_crt0_path = specs_prefix_format.format(get_option('libdir') / '%*' / crt0_expr)
+ crt0_buildtype = picolibc_buildtype_format.format(buildtype_crt0_path)
+ 
++sysroot_crt0_path = '%*' + '/' + get_option('libdir') + '/' + '%*' + '/' + crt0_expr
++crt0_sysroot = picolibc_buildtype_format.format(sysroot_crt0_path)
++
+ gen_crt0_path = specs_prefix_format.format(get_option('libdir') / crt0_expr)
+ crt0_gen = gen_format.format(gen_crt0_path)
+ 
+@@ -686,10 +696,13 @@ if enable_multilib
+   buildtype_multilib_dir = specs_prefix_format.format(get_option('libdir') / '%*/%M')
+   multilib_buildtype = picolibc_buildtype_format.format(buildtype_multilib_dir)
+ 
++  sysroot_multilib_dir = '%*' + '/' + get_option('libdir') + '/' + '%*/%M'
++  multilib_sysroot = sysroot_format.format(sysroot_multilib_dir)
++  
+   gen_multilib_dir = specs_prefix_format.format(get_option('libdir') / '%M')
+   multilib_gen = gen_format.format(gen_multilib_dir)
+ 
+-  specs_multilibpath = '-L' + specs_option_format.format(multilib_prefix, multilib_buildtype, multilib_gen)
++  specs_multilibpath = '-L' + specs_option_format.format(multilib_prefix, multilib_buildtype, multilib_sysroot, multilib_gen)
+ 
+   #
+   # Prepend the multilib -L option to the non-multilib option
+@@ -705,6 +718,9 @@ if enable_multilib
+   buildtype_multilib_crt0_path = specs_prefix_format.format(get_option('libdir') / '%*/%M' / crt0_expr)
+   crt0_buildtype = picolibc_buildtype_format.format(buildtype_multilib_crt0_path)
+ 
++  sysroot_multilib_crt0_path = '%*' + prefix + '/' + get_option('libdir') + '/' + '/%M' + '/' + crt0_expr
++  crt0_sysroot = sysroot_format.format(sysroot_multilib_crt0_path)
++  
+   gen_multilib_crt0_path = specs_prefix_format.format(get_option('libdir') / '%M' / crt0_expr)
+   crt0_gen = gen_format.format(gen_multilib_crt0_path)
+ endif
+@@ -714,7 +730,7 @@ endif
+ # above. As there's only one value, it's either the
+ # multilib path or the non-multilib path
+ #
+-specs_startfile = specs_option_format.format(crt0_prefix, crt0_buildtype, crt0_gen)
++specs_startfile = specs_option_format.format(crt0_prefix, crt0_buildtype, crt0_sysroot, crt0_gen)
+ endif
+ 
+ specs_data = configuration_data()
diff --git a/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross b/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
new file mode 100644
index 0000000000..87bfbad3c5
--- /dev/null
+++ b/meta/recipes-core/picolibc/picolibc/no-early-compiler-checks.cross
@@ -0,0 +1,6 @@ 
+# We need to explicitly bypass mesons sanity check to avoid early compiler errors
+# otherwise meson will try to compile AND run test applications:
+# ../git/meson.build:35:0: ERROR: Executables created by c compiler are not runnable...
+
+[properties]
+skip_sanity_check=true
\ No newline at end of file
diff --git a/meta/recipes-core/picolibc/picolibc_git.bb b/meta/recipes-core/picolibc/picolibc_git.bb
new file mode 100644
index 0000000000..fdb159328f
--- /dev/null
+++ b/meta/recipes-core/picolibc/picolibc_git.bb
@@ -0,0 +1,35 @@ 
+require picolibc.inc
+
+INHIBIT_DEFAULT_DEPS = "1"
+DEPENDS = "virtual/${TARGET_PREFIX}gcc"
+
+PROVIDES += "virtual/libc virtual/libiconv virtual/libintl"
+
+COMPATIBLE_HOST:libc-musl:class-target = "null"
+COMPATIBLE_HOST:libc-glibc:class-target = "null"
+COMPATIBLE_MACHINE = "qemuarm|qemuarm64|qemuriscv32|qemuriscv64"
+
+SRC_URI:append = " file://avoid_polluting_cross_directories.patch"
+SRC_URI:append = " file://no-early-compiler-checks.cross"
+
+# This is being added by picolibc meson files as well to avoid
+# early compiler tests from failing, cant remember why I added it
+# to the newlib recipe but I would assume it was for the same reason
+TARGET_CC_ARCH:append = " -nostdlib"
+
+# When using RISCV64 use medany for both C library and application recipes
+TARGET_CFLAGS:append:qemuriscv64 = " -mcmodel=medany"
+
+inherit meson
+
+MESON_CROSS_FILE:append = " --cross-file=${UNPACKDIR}/no-early-compiler-checks.cross"
+
+PACKAGECONFIG ??= " specsdir"
+# Install GCC specs on libdir
+PACKAGECONFIG[specsdir] = "-Dspecsdir=${libdir},-Dspecsdir=none"
+
+
+FILES:${PN}-dev:append = " ${libdir}/*.specs ${libdir}/*.ld"
+
+# No rpm package is actually created but -dev depends on it, avoid dnf error
+DEV_PKG_DEPENDENCY:libc-picolibc = ""
diff --git a/meta/recipes-devtools/gcc/gcc-cross.inc b/meta/recipes-devtools/gcc/gcc-cross.inc
index 5b0ca15d47..c04177df5a 100644
--- a/meta/recipes-devtools/gcc/gcc-cross.inc
+++ b/meta/recipes-devtools/gcc/gcc-cross.inc
@@ -34,6 +34,7 @@  EXTRA_OECONF += "\
 EXTRA_OECONF:append:libc-baremetal = " --without-headers"
 EXTRA_OECONF:remove:libc-baremetal = "--enable-threads=posix"
 EXTRA_OECONF:remove:libc-newlib = "--enable-threads=posix"
+EXTRA_OECONF:remove:libc-picolibc = "--enable-threads=posix"
 
 EXTRA_OECONF_PATHS = "\
     --with-gxx-include-dir=/not/exist${target_includedir}/c++/${BINV} \
diff --git a/meta/recipes-devtools/gcc/gcc-runtime.inc b/meta/recipes-devtools/gcc/gcc-runtime.inc
index 89b0bebcfb..1fca00f5f0 100644
--- a/meta/recipes-devtools/gcc/gcc-runtime.inc
+++ b/meta/recipes-devtools/gcc/gcc-runtime.inc
@@ -17,6 +17,7 @@  EXTRA_OECONF_PATHS = "\
 EXTRA_OECONF:append:linuxstdbase = " --enable-clocale=gnu"
 EXTRA_OECONF:append = " --cache-file=${B}/config.cache"
 EXTRA_OECONF:append:libc-newlib = " --with-newlib --with-target-subdir"
+EXTRA_OECONF:append:libc-picolibc = " --with-newlib --with-target-subdir"
 EXTRA_OECONF:append:libc-baremetal = " --with-target-subdir"
 
 # Disable ifuncs for libatomic on arm conflicts -march/-mcpu
@@ -27,6 +28,7 @@  DISABLE_STATIC:class-nativesdk ?= ""
 
 # Newlib does not support symbol versioning on libsdtcc++
 SYMVERS_CONF:libc-newlib = ""
+SYMVERS_CONF:libc-picolibc = ""
 
 # Building with thumb enabled on armv6t fails
 ARM_INSTRUCTION_SET:armv6 = "arm"
@@ -47,6 +49,7 @@  RUNTIMETARGET = "${RUNTIMELIBSSP} libstdc++-v3 libgomp libatomic ${RUNTIMELIBITM
 "
 # Only build libstdc++ for newlib
 RUNTIMETARGET:libc-newlib = "libstdc++-v3"
+RUNTIMETARGET:libc-picolibc = "libstdc++-v3"
 
 # libiberty
 # libgfortran needs separate recipe due to libquadmath dependency
diff --git a/meta/recipes-devtools/gcc/libgcc-common.inc b/meta/recipes-devtools/gcc/libgcc-common.inc
index d9084af51a..e3db17d700 100644
--- a/meta/recipes-devtools/gcc/libgcc-common.inc
+++ b/meta/recipes-devtools/gcc/libgcc-common.inc
@@ -53,6 +53,11 @@  do_install:append:libc-newlib () {
 		rmdir ${D}${base_libdir}
 	fi
 }
+do_install:append:libc-picolibc () {
+	if [ "${base_libdir}" != "${libdir}" ]; then
+		rmdir ${D}${base_libdir}
+	fi
+}
 
 # No rpm package is actually created but -dev depends on it, avoid dnf error
 DEV_PKG_DEPENDENCY:libc-baremetal = ""