[PATCH 00/10] ulib: Provide examples for building outside the tree

From: Simon Glass <sjg@chromium.org> The ulib tests are built within the U-Boot build system, so make use of various settings which are provided. When using ulib outside the U-Boot tree (and outside its build environment), things are a little more tricky. This series provides a few simple examples to illustrate how to make it work. An example Makefile is provided as well. The same Makefile is used from CI just to ensure that it continues to work as expected. Simon Glass (10): CI: Tidy up the template for the 'make check' items sandbox: Make use of PLATFORM_LIBS for ulib_test Kconfig: Split the EXAMPLES option into its own file Kconfig: Provide an option for the standalone directory sandbox: Avoid use of ulong in os.h examples: Allow compilation of examples on sandbox sandbox: Enable building examples ulib: Provide an example of how to build with ulib CI: ulib: Test building examples separately doc: ulib: Provide some documentation on the ulib examples .gitlab-ci.yml | 26 +++++++++++++- Kconfig | 2 ++ Makefile | 19 +++++++++- configs/sandbox_defconfig | 1 + doc/develop/ulib.rst | 3 ++ examples/Kconfig | 19 ++++++++++ examples/Makefile | 2 +- examples/ulib/Makefile | 73 ++++++++++++++++++++++++++++++++++++++ examples/ulib/README | 74 +++++++++++++++++++++++++++++++++++++++ examples/ulib/demo.c | 61 ++++++++++++++++++++++++++++++++ examples/ulib/static.lds | 19 ++++++++++ include/os.h | 2 +- legacy_api/Kconfig | 8 ----- 13 files changed, 297 insertions(+), 12 deletions(-) create mode 100644 examples/Kconfig create mode 100644 examples/ulib/Makefile create mode 100644 examples/ulib/README create mode 100644 examples/ulib/demo.c create mode 100644 examples/ulib/static.lds -- 2.43.0 base-commit: 8f58832f29b90702d7f56c3f34823616ac81b2d3 branch: ulie

From: Simon Glass <sjg@chromium.org> These tests run as part of the test.py phase, since they will fail if there is a problem there. Fix up the logic at the start to use this phase, supporting the same options as the other tests. Signed-off-by: Simon Glass <sjg@chromium.org> --- .gitlab-ci.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bced2874d2d..59bcd798d6f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -343,7 +343,11 @@ Check packing of Python tools: rules: - if: $LAB_ONLY == "1" when: never - - if: $TEST_SUITES == "1" + - if: $TEST_PY == "1" + when: always + - if: $TEST_PY == $CI_JOB_NAME + when: always + - if: $TEST_PY == $TEST_PY_BD when: always - when: never before_script: -- 2.43.0

From: Simon Glass <sjg@chromium.org> Rather than specifying the sandbox-specific arguments in the main Makefile, make use of PLATFORM_LIBS which has (more than) what we need. Signed-off-by: Simon Glass <sjg@chromium.org> --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e3b95290384..2e2f276eee6 100644 --- a/Makefile +++ b/Makefile @@ -1905,7 +1905,7 @@ quiet_cmd_ulib_test_static = HOSTCC $@ -I$(srctree)/arch/sandbox/include -o $@ $< \ -Wl,-T,$(LIB_STATIC_LDS) \ -Wl,--whole-archive $(obj)/libu-boot.a -Wl,--no-whole-archive \ - -lpthread -ldl -lSDL2 -lrt -Wl,-z,noexecstack + -ldl $(PLATFORM_LIBS) -Wl,-z,noexecstack test/ulib/ulib_test_static: test/ulib/ulib_test.o libu-boot.a \ $(LIB_STATIC_LDS) FORCE -- 2.43.0

From: Simon Glass <sjg@chromium.org> We want to build examples for things other than the legacy API. As a first step, create a Kconfig file in examples/ and move CONFIG_EXAMPLES into it. Signed-off-by: Simon Glass <sjg@chromium.org> --- Kconfig | 2 ++ examples/Kconfig | 11 +++++++++++ legacy_api/Kconfig | 8 -------- 3 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 examples/Kconfig diff --git a/Kconfig b/Kconfig index bf30179db93..76cfa74dc8b 100644 --- a/Kconfig +++ b/Kconfig @@ -733,6 +733,8 @@ config LDR_CPU source "legacy_api/Kconfig" +source "examples/Kconfig" + endmenu # General setup source "boot/Kconfig" diff --git a/examples/Kconfig b/examples/Kconfig new file mode 100644 index 00000000000..62ae2ffab2c --- /dev/null +++ b/examples/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2017 Emmanuel Vadot <manu@bidouilliste.com> + +config EXAMPLES + bool "Compile legacy API examples" + depends on !SANDBOX + default y if ARCH_QEMU_ARM + help + U-Boot provides an legacy API for standalone applications. Examples + are provided in directory examples/. diff --git a/legacy_api/Kconfig b/legacy_api/Kconfig index 6dc96455ff0..7e5725a7202 100644 --- a/legacy_api/Kconfig +++ b/legacy_api/Kconfig @@ -15,14 +15,6 @@ config SYS_MMC_MAX_DEVICE int "Maximum number of MMC devices exposed via the legacy API" default 1 -config EXAMPLES - bool "Compile legacy API examples" - depends on !SANDBOX - default y if ARCH_QEMU_ARM - help - U-Boot provides an legacy API for standalone applications. Examples - are provided in directory examples/. - config STANDALONE_LOAD_ADDR depends on EXAMPLES hex "Address in memory to link standalone applications to" -- 2.43.0

From: Simon Glass <sjg@chromium.org> Rather than using CONFIG_EXAMPLES to control the inclusion of this directory, create a separate option. This will allow examples to be added which don't relate to the legacy API. Signed-off-by: Simon Glass <sjg@chromium.org> --- examples/Kconfig | 8 ++++++++ examples/Makefile | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/Kconfig b/examples/Kconfig index 62ae2ffab2c..4d5a2a9c8dd 100644 --- a/examples/Kconfig +++ b/examples/Kconfig @@ -9,3 +9,11 @@ config EXAMPLES help U-Boot provides an legacy API for standalone applications. Examples are provided in directory examples/. + +config EXAMPLES_STANDALONE + bool "Compile standalone examples" + depends on EXAMPLES + default y + help + Build the various examples in the standalone/directory for use with + the legacy API. diff --git a/examples/Makefile b/examples/Makefile index bf51f1a5018..50bef4e6157 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -6,6 +6,6 @@ ifdef FTRACE subdir-ccflags-y += -finstrument-functions -DFTRACE endif -subdir-y += standalone +subdir-$(EXAMPLES_STANDALONE) += standalone subdir-$(CONFIG_LEGACY_API) += api endif -- 2.43.0

From: Simon Glass <sjg@chromium.org> This header file is useful outside U-Boot, for the ulib examples. Also it is supposed to be a system-facing header. So using U-Boot types is not a good idea. Replace the sole use of 'ulong' with 'unsigned long'. Signed-off-by: Simon Glass <sjg@chromium.org> --- include/os.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/os.h b/include/os.h index e5c524c57a4..dfd6e3c7692 100644 --- a/include/os.h +++ b/include/os.h @@ -291,7 +291,7 @@ struct os_dirent_node { /** * @size: size of file in bytes */ - ulong size; + unsigned long size; /** * @type: type of entry */ -- 2.43.0

From: Simon Glass <sjg@chromium.org> The 'standalone' legacy-API examples don't work with sandbox, but the forthcoming ulib ones will. Adjust the !SANDBOX restriction to apply only to the former. Signed-off-by: Simon Glass <sjg@chromium.org> --- examples/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Kconfig b/examples/Kconfig index 4d5a2a9c8dd..5738d555d22 100644 --- a/examples/Kconfig +++ b/examples/Kconfig @@ -4,7 +4,6 @@ config EXAMPLES bool "Compile legacy API examples" - depends on !SANDBOX default y if ARCH_QEMU_ARM help U-Boot provides an legacy API for standalone applications. Examples @@ -12,6 +11,7 @@ config EXAMPLES config EXAMPLES_STANDALONE bool "Compile standalone examples" + depends on !SANDBOX depends on EXAMPLES default y help -- 2.43.0

From: Simon Glass <sjg@chromium.org> Allow the 'sandbox' board (only) to build examples. This will be used for ulib examples. Signed-off-by: Simon Glass <sjg@chromium.org> --- configs/sandbox_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 673afdf93ba..d10b029f540 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -11,6 +11,7 @@ CONFIG_PCI=y CONFIG_DEBUG_UART=y CONFIG_SYS_MEMTEST_START=0x00100000 CONFIG_SYS_MEMTEST_END=0x00101000 +CONFIG_EXAMPLES=y CONFIG_EFI_SECURE_BOOT=y CONFIG_EFI_RT_VOLATILE_STORE=y CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add an example Makefile which shows how to build against U-Boot from outside the U-Boot source tree. Signed-off-by: Simon Glass <sjg@chromium.org> --- Makefile | 17 +++++++++ examples/ulib/Makefile | 73 +++++++++++++++++++++++++++++++++++++++ examples/ulib/README | 74 ++++++++++++++++++++++++++++++++++++++++ examples/ulib/demo.c | 61 +++++++++++++++++++++++++++++++++ examples/ulib/static.lds | 19 +++++++++++ 5 files changed, 244 insertions(+) create mode 100644 examples/ulib/Makefile create mode 100644 examples/ulib/README create mode 100644 examples/ulib/demo.c create mode 100644 examples/ulib/static.lds diff --git a/Makefile b/Makefile index 2e2f276eee6..8d082d1ae81 100644 --- a/Makefile +++ b/Makefile @@ -1048,6 +1048,9 @@ ifneq ($(cc-name),clang) ifeq ($(NO_LIBS),) INPUTS-$(CONFIG_ULIB) += libu-boot.so test/ulib/ulib_test INPUTS-$(CONFIG_ULIB) += libu-boot.a test/ulib/ulib_test_static +ifdef CONFIG_EXAMPLES +INPUTS-$(CONFIG_ULIB) += examples_ulib +endif endif endif endif @@ -1911,6 +1914,18 @@ test/ulib/ulib_test_static: test/ulib/ulib_test.o libu-boot.a \ $(LIB_STATIC_LDS) FORCE $(call if_changed,ulib_test_static) +PHONY += examples_ulib +examples_ulib: libu-boot.a libu-boot.so FORCE + $(Q)$(MAKE) -C $(srctree)/examples/ulib \ + UBOOT_BUILD=$(abspath $(obj)) \ + EXAMPLE_DIR=. \ + OUTDIR=$(abspath $(obj)/examples/ulib) \ + srctree="$(srctree)" \ + CC="$(CC)" \ + CFLAGS="$(CFLAGS)" \ + PLATFORM_LIBS="$(PLATFORM_LIBS)" \ + LIB_STATIC_LDS="$(LIB_STATIC_LDS)" + quiet_cmd_sym ?= SYM $@ cmd_sym ?= $(OBJDUMP) -t $< > $@ u-boot.sym: u-boot FORCE @@ -2339,6 +2354,8 @@ $(clean-dirs): clean: $(clean-dirs) $(call cmd,rmdirs) $(call cmd,rmfiles) + @$(MAKE) -C $(srctree)/examples/ulib clean \ + OUTDIR=$(abspath $(obj)/examples/ulib) @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \ \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \ -o -name '*.ko.*' -o -name '*.su' -o -name '*.pyc' \ diff --git a/examples/ulib/Makefile b/examples/ulib/Makefile new file mode 100644 index 00000000000..da788e5792f --- /dev/null +++ b/examples/ulib/Makefile @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Standalone Makefile for U-Boot library examples +# +# Copyright 2025 Canonical +# Written by Simon Glass <simon.glass@canonical.com> + +# This Makefile can be used to build the examples. See doc/develop/ulib.rst +# +# Usage: cd examples/ulib; make UBOOT_BUILD=/tmp/b/sandbox/ srctree=../.. +# +# This Makefile is also called from the main U-Boot Makefile when CONFIG_ULIB +# and CONFIG_EXAMPLES are enabled. It receives these variables, many of which +# are needed to ensure that the output goes to the right place: +# +# UBOOT_BUILD - Build directory (e.g., /tmp/b/sandbox) +# EXAMPLE_DIR - Source tree path for these examples +# OUTDIR - Output directory for object files and executables +# srctree - U-Boot source tree +# +# Also these may be provided: +# CC - C compiler +# CFLAGS - C compiler flags +# SDL_CONFIG - Name of sdl2-config program +# PLATFORM_LIBS - Platform-specific libraries +# LIB_STATIC_LDS - Linker script for static library + +# For standalone builds, provide default values +EXAMPLE_DIR ?= . +OUTDIR ?= . +CC ?= gcc +SDL_CONFIG ?= sdl2-config +PLATFORM_LIBS ?= $(shell $(SDL_CONFIG) --libs) +LIB_STATIC_LDS ?= static.lds +# The main Makefile passes in Q=@ for quiet output +Q ?= + +DEMO_SRC := $(EXAMPLE_DIR)/demo.c +DEMO_BINS := $(OUTDIR)/demo $(OUTDIR)/demo_static + +# Default target builds both programs +all: $(DEMO_BINS) + @echo "Build complete: demo and demo_static in $(OUTDIR)" + +# Create the output directory if it doesn't exist +$(OUTDIR): + @mkdir -p $@ + +# The U-Boot library must be built before we can link against it. This is +# signalled by the presence of the $(UBOOT_BUILD)/examples/ulib directory. +# This is an order-only prerequisite, so it does not trigger a rebuild if the +# timestamp of the directory changes. +$(DEMO_BINS): | $(UBOOT_BUILD)/examples/ulib $(OUTDIR) + +# Build demo (dynamically linked with libu-boot.so) +$(OUTDIR)/demo: $(DEMO_SRC) + $(CC) $(CFLAGS) \ + -idirafter$(srctree)/include -o $@ $< \ + -L$(UBOOT_BUILD) -lu-boot \ + -Wl,-rpath,$(UBOOT_BUILD) + +# Build demo_static (statically linked with libu-boot.a) +$(OUTDIR)/demo_static: $(DEMO_SRC) + $(CC) $(CFLAGS) \ + -idirafter$(srctree)/include -o $@ $< \ + -Wl,-T,$(LIB_STATIC_LDS) \ + -Wl,--whole-archive $(UBOOT_BUILD)/libu-boot.a -Wl,--no-whole-archive \ + -lpthread -ldl $(PLATFORM_LIBS) -Wl,-z,noexecstack + +clean: + $(Q)rm -f $(DEMO_BINS) + +.PHONY: all clean diff --git a/examples/ulib/README b/examples/ulib/README new file mode 100644 index 00000000000..e6f48bf79cd --- /dev/null +++ b/examples/ulib/README @@ -0,0 +1,74 @@ +U-Boot Library Example +====================== + +This directory contains example programs showing how to use the U-Boot library +(libu-boot.so) in external C programs. + +Building U-Boot Library +----------------------- + +First, build U-Boot with library support: + + make O=/tmp/b/sandbox -j$(nproc) sandbox_defconfig all + +This creates: +- /tmp/b/sandbox/libu-boot.so (shared library) +- /tmp/b/sandbox/libu-boot.a (static library) + +Example Programs +---------------- + +The examples are built automatically as part of the U-Boot build. So far there +is only one. + +**demo.c** - Demonstrates using U-Boot library functions + +- Shows how to init the library with ulib_init() +- Uses U-Boot's OS functions (os_open(), os_fgets(), os_close()) +- Reads and displays system information +- Shows the U-Boot version + +Building Examples +----------------- + +The examples are built automatically when U-Boot has these options enabled:: + + CONFIG_ULIB=y + CONFIG_EXAMPLES=y + +To build manually: + + # From this directory examples/ulib + make UBOOT_BUILD=/tmp/b/sandbox/ srctree=../.. + +Running Examples +---------------- + + # Run the demo + LD_LIBRARY_PATH=/tmp/b/sandbox ./demo + + # Run the demo (static version) + ./demo_static + +Key Points +---------- + +- Avoid including U-Boot headers that conflict with system headers. This + Makefile gives priority to the system headers +- Use ulib_init() to init the library +- Use ulib_uninit() to clean up +- Set LD_LIBRARY_PATH when running dynamically linked programs + +Copying for External Use +------------------------- + +This directory can be copied elsewhere and used independently: + + cp -r examples/ulib ~/my-project/ + cd ~/my-project/ulib + make UBOOT_BUILD=/path/to/u-boot-build srctree=/path/to/u-boot-source + +License +------- + +All examples are licensed under GPL-2.0+ diff --git a/examples/ulib/demo.c b/examples/ulib/demo.c new file mode 100644 index 00000000000..4b12e91b17e --- /dev/null +++ b/examples/ulib/demo.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Demo program showing U-Boot library functionality + * + * This demonstrates using U-Boot library functions in sandbox like os_* + * from external programs. + * + * Copyright 2025 Canonical + * Written by Simon Glass <simon.glass@canonical.com> + */ + +#include <inttypes.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> + +#include <os.h> +#include <u-boot-lib.h> +#include <version_string.h> + +int main(int argc, char *argv[]) +{ + int fd, lines = 0; + char line[256]; + + /* Init U-Boot library */ + if (ulib_init(argv[0]) < 0) { + fprintf(stderr, "Failed to initialize U-Boot library\n"); + return 1; + } + + printf("1U-Boot Library Demo\n"); + printf("================================\n"); + printf("U-Boot version: %s\n", version_string); + printf("\n"); + + /* Use U-Boot's os_open to open a file */ + fd = os_open("/proc/version", 0); + if (fd < 0) { + fprintf(stderr, "Failed to open /proc/version\n"); + ulib_uninit(); + return 1; + } + + printf("System version:\n"); + + /* Use U-Boot's os_fgets to read lines */ + while (os_fgets(line, sizeof(line), fd)) { + printf(" %s", line); + lines++; + } + + os_close(fd); + + printf("\nRead %d line(s) using U-Boot library functions.\n", lines); + + /* Clean up */ + ulib_uninit(); + + return 0; +} diff --git a/examples/ulib/static.lds b/examples/ulib/static.lds new file mode 100644 index 00000000000..c400fba4f2b --- /dev/null +++ b/examples/ulib/static.lds @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Linker script for ulib_test_static binary + * + * This ensures proper alignment for linker-lists when linking with libu-boot.a + */ + +SECTIONS +{ + /* Ensure proper alignment for linker lists */ + . = ALIGN(32); + __u_boot_list : { + __u_boot_list_start = .; + KEEP(*(SORT(__u_boot_list*))); + __u_boot_list_end = .; + } +} + +INSERT AFTER .rodata; -- 2.43.0

From: Simon Glass <sjg@chromium.org> Check that it is possible to build the ulib examples separately from the U-Boot build. Signed-off-by: Simon Glass <sjg@chromium.org> --- .gitlab-ci.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 59bcd798d6f..e4e86801fdc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -337,6 +337,26 @@ Check packing of Python tools: script: - make pip +Examples: + extends: .test_suites + script: + - git config --global user.name "GitLab CI Runner"; + git config --global user.email trini@konsulko.com; + git config --global --add safe.directory "${CI_PROJECT_DIR}"; + export USER=gitlab; + export UBOOT_TRAVIS_BUILD_DIR=/tmp/sandbox; + set +e; + ./tools/buildman/buildman -T0 -o ${UBOOT_TRAVIS_BUILD_DIR} -w + --board sandbox; + set -e; + - echo "Building examples"; + cd examples/ulib; + make UBOOT_BUILD=${UBOOT_TRAVIS_BUILD_DIR} srctree=../.. + - echo "Running static"; + ./demo_static + - echo "Running dynamic"; + LD_LIBRARY_PATH=${UBOOT_TRAVIS_BUILD_DIR} ./demo + # Template for running the 'make check' tools .python_check_template: stage: test.py -- 2.43.0

From: Simon Glass <sjg@chromium.org> Update the documentation to point to the examples. Signed-off-by: Simon Glass <sjg@chromium.org> --- doc/develop/ulib.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/develop/ulib.rst b/doc/develop/ulib.rst index 559f170ce42..8df3a6f99bc 100644 --- a/doc/develop/ulib.rst +++ b/doc/develop/ulib.rst @@ -88,6 +88,9 @@ u-boot-lib.h you will have problems, as described in the following sections. This will be addressed with future work. +With that caveat, see example/ulib/README for instructions on how to use the +provided example. + Including U-Boot header files from outside ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- 2.43.0
participants (1)
-
Simon Glass