[Concept,08/10] ulib: Provide an example of how to build with ulib

Message ID 20250905212330.354827-9-sjg@u-boot.org
State New
Headers
Series ulib: Provide examples for building outside the tree |

Commit Message

Simon Glass Sept. 5, 2025, 9:23 p.m. UTC
  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
  

Patch

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;