[Concept,03/13] examples: ulib: Support both sandbox and linked-in demo

Message ID 20260214021317.816170-4-sjg@u-boot.org
State New
Headers
Series ulib: Support building examples for x86 |

Commit Message

Simon Glass Feb. 14, 2026, 2:12 a.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Refactor demo.c so it builds as a standalone sandbox binary (using
ulib_init/ulib_uninit and os_* helpers) or as an example linked
into U-Boot (providing a strong ulib_has_main() and main()).

Extract demo_run() for the common path and use IS_ENABLED(CONFIG_SANDBOX)
to gate the sandbox-specific initialisation and /proc/version reading.

Update demo_helper.c to use printf() directly when built as part of
U-Boot (CONFIG_ULIB) rather than the u-boot-api shim.

Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 examples/ulib/demo.c        | 87 +++++++++++++++++++++----------------
 examples/ulib/demo_helper.c |  5 +++
 test/py/tests/test_ulib.py  | 10 +++--
 3 files changed, 62 insertions(+), 40 deletions(-)
  

Patch

diff --git a/examples/ulib/demo.c b/examples/ulib/demo.c
index 5077fcda0a6..0dbe5d233f5 100644
--- a/examples/ulib/demo.c
+++ b/examples/ulib/demo.c
@@ -2,66 +2,79 @@ 
 /*
  * Demo program showing U-Boot library functionality
  *
- * This demonstrates using U-Boot library functions in sandbox like os_*
- * from external programs.
+ * This demonstrates using U-Boot library functions from external programs
+ * (sandbox) or as a standalone example linked into U-Boot.
  *
  * Copyright 2025 Canonical Ltd.
  * Written by Simon Glass <simon.glass@canonical.com>
  */
 
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-
 #include <os.h>
+#include <stdio.h>
 #include <u-boot-lib.h>
 #include <version_string.h>
 #include "demo_helper.h"
 
+#ifndef CONFIG_SANDBOX
+bool ulib_has_main(void)
+{
+	return true;
+}
+#endif
+
+static const char *get_version(void)
+{
+	if (IS_ENABLED(CONFIG_SANDBOX))
+		return ulib_get_version();
+	return version_string;
+}
+
+static int demo_run(void)
+{
+	demo_show_banner();
+	printf("U-Boot version: %s\n", get_version());
+	printf("\n");
+
+	demo_add_numbers(42, 13);
+	demo_show_footer();
+
+	return 0;
+}
+
+#ifdef CONFIG_SANDBOX
 int main(int argc, char *argv[])
 {
-	int fd, result, lines = 0;
+	int fd, lines = 0;
 	char line[256];
+	int ret;
 
-	/* Init U-Boot library */
 	if (ulib_init(argv[0]) < 0) {
 		fprintf(stderr, "Failed to initialize U-Boot library\n");
 		return 1;
 	}
 
-	demo_show_banner();
-	printf("U-Boot version: %s\n", ulib_get_version());
-	printf("\n");
+	ret = demo_run();
 
-	/* Use U-Boot's os_open to open a file */
+	/* Also demonstrate using U-Boot's os_* functions to read 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++;
+	if (fd >= 0) {
+		printf("\nSystem version:\n");
+		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);
 	}
 
-	os_close(fd);
-
-	printf("\nRead %d line(s) using U-Boot library functions.\n", lines);
-
-	/* Test the helper function */
-	result = demo_add_numbers(42, 13);
-	printf("Helper function result: %d\n", result);
-
-	demo_show_footer();
-
-	/* Clean up */
 	ulib_uninit();
 
-	return 0;
+	return ret;
+}
+#else
+int main(void)
+{
+	return demo_run();
 }
+#endif
diff --git a/examples/ulib/demo_helper.c b/examples/ulib/demo_helper.c
index e3a2c6bdcfb..167bbd26f64 100644
--- a/examples/ulib/demo_helper.c
+++ b/examples/ulib/demo_helper.c
@@ -6,7 +6,12 @@ 
  * Written by Simon Glass <simon.glass@canonical.com>
  */
 
+#ifndef CONFIG_ULIB
 #include <u-boot-api.h>
+#else
+#include <stdio.h>
+#define ub_printf printf
+#endif
 
 void demo_show_banner(void)
 {
diff --git a/test/py/tests/test_ulib.py b/test/py/tests/test_ulib.py
index 9b8b7097db4..9e46d529c87 100644
--- a/test/py/tests/test_ulib.py
+++ b/test/py/tests/test_ulib.py
@@ -53,18 +53,22 @@  def check_demo_output(ubman, out):
     with open('/proc/version', 'r', encoding='utf-8') as f:
         proc_version = f.read().strip()
 
+    # demo.c uses U-Boot's printf (compiled with U-Boot headers) while
+    # demo_helper.c uses glibc's printf, so their output streams are
+    # buffered separately.  The helper output appears first, then the
+    # U-Boot printf output is flushed at exit.
     expected = [
         'U-Boot Library Demo Helper\r',
         '==========================\r',
-        'System version:helper: Adding 42 + 13 = 55\r',
+        'helper: Adding 42 + 13 = 55\r',
         '=================================\r',
         'Demo complete\r',
-        f'U-Boot version: {ubman.u_boot_version_string}',
+        '\r',
+        f'System version:U-Boot version: {ubman.u_boot_version_string}',
         '',
         f'  {proc_version}',
         '',
         'Read 1 line(s) using U-Boot library functions.',
-        'Helper function result: 55',
         ''
     ]