From 031e38170b778493f06732b537def05ad3f4a854 Mon Sep 17 00:00:00 2001 From: Romain PELLETANT Date: Thu, 15 Oct 2026 12:19:36 +0200 Subject: [PATCH 1/3] env: add zephyr support - Add zephyr support as external module - Tests and samples are located in zephyr folder to avoid propagation Signed-off-by: Romain PELLETANT --- west.yml | 26 ++++++ zephyr/CMakeLists.txt | 42 ++++++++++ zephyr/Kconfig | 40 +++++++++ zephyr/README.md | 63 ++++++++++++++ zephyr/config.h.in | 19 +++++ zephyr/module.yml | 19 +++++ zephyr/samples/basic/CMakeLists.txt | 19 +++++ zephyr/samples/basic/README.md | 22 +++++ zephyr/samples/basic/prj.conf | 14 ++++ zephyr/samples/basic/sample.yaml | 23 +++++ zephyr/samples/basic/src/main.c | 125 ++++++++++++++++++++++++++++ zephyr/tests/CMakeLists.txt | 42 ++++++++++ zephyr/tests/prj.conf | 16 ++++ zephyr/tests/src/main.c | 66 +++++++++++++++ zephyr/tests/testcase.yaml | 20 +++++ zephyr/version.cmake | 32 +++++++ 16 files changed, 588 insertions(+) create mode 100644 west.yml create mode 100644 zephyr/CMakeLists.txt create mode 100644 zephyr/Kconfig create mode 100644 zephyr/README.md create mode 100644 zephyr/config.h.in create mode 100644 zephyr/module.yml create mode 100644 zephyr/samples/basic/CMakeLists.txt create mode 100644 zephyr/samples/basic/README.md create mode 100644 zephyr/samples/basic/prj.conf create mode 100644 zephyr/samples/basic/sample.yaml create mode 100644 zephyr/samples/basic/src/main.c create mode 100644 zephyr/tests/CMakeLists.txt create mode 100644 zephyr/tests/prj.conf create mode 100644 zephyr/tests/src/main.c create mode 100644 zephyr/tests/testcase.yaml create mode 100644 zephyr/version.cmake diff --git a/west.yml b/west.yml new file mode 100644 index 0000000..63db83c --- /dev/null +++ b/west.yml @@ -0,0 +1,26 @@ +# +# West manifest for developing and testing Mini-XML on Zephyr. +# +# Copyright © 2026 by Romain Pelletant. +# +# Licensed under Apache License v2.0. See the file "LICENSE" for more +# information. +# +# SPDX-License-Identifier: Apache-2.0 +# + +manifest: + self: + path: mxml + + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + + projects: + - name: zephyr + remote: zephyrproject-rtos + revision: v4.4.0 + import: + name-allowlist: + - cmsis_6 diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt new file mode 100644 index 0000000..8e04ed8 --- /dev/null +++ b/zephyr/CMakeLists.txt @@ -0,0 +1,42 @@ +# +# CMakeLists for building Mini-XML as a Zephyr module. +# +# Copyright © 2026 by Romain Pelletant. +# +# Licensed under Apache License v2.0. See the file "LICENSE" for more +# information. +# +# SPDX-License-Identifier: Apache-2.0 +# + +if(CONFIG_MXML) + set(MXML_ROOT ${CMAKE_CURRENT_LIST_DIR}/..) + set(MXML_GENERATED_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/include) + + include(${CMAKE_CURRENT_LIST_DIR}/version.cmake) + if(CONFIG_POSIX_THREADS) + set(HAVE_PTHREAD_H 1) + endif() + + configure_file( + ${CMAKE_CURRENT_LIST_DIR}/config.h.in + ${MXML_GENERATED_INCLUDE_DIR}/config.h + ) + + zephyr_library() + zephyr_library_compile_definitions(_POSIX_C_SOURCE=200809L) + zephyr_library_sources( + ${MXML_ROOT}/mxml-attr.c + ${MXML_ROOT}/mxml-file.c + ${MXML_ROOT}/mxml-get.c + ${MXML_ROOT}/mxml-index.c + ${MXML_ROOT}/mxml-node.c + ${MXML_ROOT}/mxml-options.c + ${MXML_ROOT}/mxml-private.c + ${MXML_ROOT}/mxml-search.c + ${MXML_ROOT}/mxml-set.c + ) + zephyr_include_directories(${MXML_ROOT}) + zephyr_library_include_directories(${MXML_GENERATED_INCLUDE_DIR}) +endif() + diff --git a/zephyr/Kconfig b/zephyr/Kconfig new file mode 100644 index 0000000..996c34c --- /dev/null +++ b/zephyr/Kconfig @@ -0,0 +1,40 @@ +# +# Kconfig options for Mini-XML on Zephyr. +# +# Copyright © 2026 by Romain Pelletant. +# +# Licensed under Apache License v2.0. See the file "LICENSE" for more +# information. +# +# SPDX-License-Identifier: Apache-2.0 +# + +menuconfig MXML + bool "Mini-XML library" + select COMMON_LIBC_MALLOC + select COMMON_LIBC_CALLOC + select POSIX_C_LIB_EXT + help + Enable Mini-XML, a small XML parsing and serialization library. + Mini-XML dynamically allocates its options, nodes, attributes, and + strings. Enabling this option therefore also enables the common libc + allocator and provides a default 4-KiB malloc arena. Applications can + override CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE when needed. + + Mini-XML uses POSIX thread-local storage when CONFIG_POSIX_THREADS is + enabled. Otherwise, string allocator callbacks are shared globally. + +config MXML_FILE_IO + bool "File-based XML input/output" + depends on MXML + depends on POSIX_FILE_SYSTEM + depends on FAT_FILESYSTEM_ELM || FILE_SYSTEM_LITTLEFS + help + Declare support for mxmlLoadFilename(), mxmlSaveFilename(), + mxmlLoadFile(), and mxmlSaveFile(). This option is available when the + POSIX file-system layer and a LittleFS or FAT backend are enabled. The + application must mount the file system before accessing XML files. + +config COMMON_LIBC_MALLOC_ARENA_SIZE + default 4096 if MXML + diff --git a/zephyr/README.md b/zephyr/README.md new file mode 100644 index 0000000..28ccbf1 --- /dev/null +++ b/zephyr/README.md @@ -0,0 +1,63 @@ +# Mini-XML Zephyr (as external module) + +## Zephyr integration: Getting started + +Add this project as an external module by appending it to your `west.yml` +project file: + +```yaml +manifest: + remotes: + - ... + - name: michaelrsweet + url-base: https://github.com/michaelrsweet + + projects: + - ... + - name: mxml + remote: michaelrsweet + revision: master + path: modules/lib/mxml +``` + +Then update your Zephyr workspace: + +```console +west update +``` + +## How to use Mini-XML in your Zephyr application + +Enable the library in the application configuration: + +```kconfig +CONFIG_MXML=y +``` + +Applications can then include the public API with `#include `. +Enabling Mini-XML also enables the libc allocator with a default 4-KiB malloc +arena. Applications can adjust it with +`CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE` according to their XML workload. + +When `CONFIG_POSIX_THREADS=y`, Mini-XML keeps its string allocator callbacks +in POSIX thread-local storage. Without POSIX threads, those callbacks are +shared globally. + +## File input/output + +To use `mxmlLoadFilename()`, `mxmlSaveFilename()`, or the `FILE`-based APIs, +enable a supported Zephyr file system and the optional integration: + +```kconfig +CONFIG_FILE_SYSTEM=y +CONFIG_FILE_SYSTEM_LITTLEFS=y +CONFIG_POSIX_API=y +CONFIG_MXML_FILE_IO=y +``` + +FAT can be selected with `CONFIG_FAT_FILESYSTEM_ELM=y` instead of LittleFS. +The application must configure and mount the selected backend before accessing +XML files. + +A sample application is located in `zephyr/samples/basic` and the Zephyr test +suite is located in `zephyr/tests` (wrapper to the Mini-XML test suite). diff --git a/zephyr/config.h.in b/zephyr/config.h.in new file mode 100644 index 0000000..a2854fc --- /dev/null +++ b/zephyr/config.h.in @@ -0,0 +1,19 @@ +// +// Configuration file for Mini-XML on Zephyr. +// +// Copyright © 2026 by Romain Pelletant. +// +// Licensed under Apache License v2.0. See the file "LICENSE" for more +// information. +// +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef MXML_CONFIG_H +# define MXML_CONFIG_H + +# define MXML_VERSION "@MXML_VERSION@" + +#cmakedefine HAVE_PTHREAD_H 1 + +#endif // !MXML_CONFIG_H diff --git a/zephyr/module.yml b/zephyr/module.yml new file mode 100644 index 0000000..e0fb081 --- /dev/null +++ b/zephyr/module.yml @@ -0,0 +1,19 @@ +# +# Zephyr module metadata for Mini-XML. +# +# Copyright © 2026 by Romain Pelletant. +# +# Licensed under Apache License v2.0. See the file "LICENSE" for more +# information. +# +# SPDX-License-Identifier: Apache-2.0 +# +name: mxml +build: + cmake: zephyr + kconfig: zephyr/Kconfig + +security: + external-references: + - cpe:2.3:a:msweet:mini-xml:4.0.6:*:*:*:*:*:*:* + - pkg:github/michaelrsweet/mxml@v4.0.6 diff --git a/zephyr/samples/basic/CMakeLists.txt b/zephyr/samples/basic/CMakeLists.txt new file mode 100644 index 0000000..4cce355 --- /dev/null +++ b/zephyr/samples/basic/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# CMakeLists for basic sample program for Zephyr. +# +# https://www.msweet.org/mxml +# +# Copyright © 2026 by Romain Pelletant. +# +# Licensed under Apache License v2.0. See the file "LICENSE" for more +# information. +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(mxml_basic) + +target_sources(app PRIVATE src/main.c) + diff --git a/zephyr/samples/basic/README.md b/zephyr/samples/basic/README.md new file mode 100644 index 0000000..d9b8e02 --- /dev/null +++ b/zephyr/samples/basic/README.md @@ -0,0 +1,22 @@ +# Mini-XML basic sample + +## Overview + +This sample parses an XML document stored in memory, looks up and modifies the +`value` element, adds a `status` element, and prints the serialized XML. + +## Building and running + +From a west workspace containing this module, run: + +```console +west build -b qemu_cortex_m3 mxml/zephyr/samples/basic +west build -t run +``` + +## Expected output + +```console +Mini-XML parsed value: 42 +Modified XML: zephyr84updated +``` diff --git a/zephyr/samples/basic/prj.conf b/zephyr/samples/basic/prj.conf new file mode 100644 index 0000000..208f6ae --- /dev/null +++ b/zephyr/samples/basic/prj.conf @@ -0,0 +1,14 @@ +# +# Configuration for the Mini-XML Zephyr sample. +# +# Copyright © 2026 by Romain Pelletant. +# +# Licensed under Apache License v2.0. See the file "LICENSE" for more +# information. +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_MXML=y +CONFIG_MAIN_STACK_SIZE=2048 + diff --git a/zephyr/samples/basic/sample.yaml b/zephyr/samples/basic/sample.yaml new file mode 100644 index 0000000..5dec818 --- /dev/null +++ b/zephyr/samples/basic/sample.yaml @@ -0,0 +1,23 @@ +# +# Twister metadata for the Mini-XML Zephyr sample. +# +# Copyright © 2026 by Romain Pelletant. +# +# Licensed under Apache License v2.0. See the file "LICENSE" for more +# information. +# +# SPDX-License-Identifier: Apache-2.0 +# + +sample: + name: Mini-XML basic example + description: Parse an XML string with the Mini-XML Zephyr module +tests: + sample.modules.mxml.basic: + tags: + - mxml + - xml + platform_allow: + - native_sim + - qemu_cortex_m3 + diff --git a/zephyr/samples/basic/src/main.c b/zephyr/samples/basic/src/main.c new file mode 100644 index 0000000..a2fb8be --- /dev/null +++ b/zephyr/samples/basic/src/main.c @@ -0,0 +1,125 @@ +// +// Sample code for Mini-XML, read and modify XML documents. +// +// https://www.msweet.org/mxml +// +// Copyright © 2026 by Romain Pelletant. +// +// Licensed under Apache License v2.0. See the file "LICENSE" for more +// information. +// +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include + +#include + +// +// 'do_type_value()' - Determine the value type for an XML element. +// +// This function determines the type to use when parsing the value of an +// XML node. +// + +static mxml_type_t // O - Value type +do_type_value(void *cbdata, // I - Callback data + mxml_node_t *node) // I - Current XML node +{ + const char *element = mxmlGetElement(node); // Current element name + + (void)cbdata; + + if ((element != NULL) && (strcmp(element, "value") == 0)) + return (MXML_TYPE_INTEGER); + + return (MXML_TYPE_OPAQUE); +} + + +// +// 'main()' - Main entry for sample program. +// + +int +main(void) +{ + static const char document[] = // XML document to parse + "" + "zephyr" + "42" + ""; + mxml_options_t *options; // Load and save options + mxml_node_t *tree; // Parsed XML tree + mxml_node_t *value; // Value element + mxml_node_t *status; // Status element + char output[256]; // Serialized XML document + size_t output_len; // Length of serialized XML + int ret = 0; // Return value + + // Create the parser options and load the XML document... + options = mxmlOptionsNew(); + if (options == NULL) + { + fprintf(stderr, "Unable to allocate Mini-XML options\n"); + return (1); + } + + mxmlOptionsSetTypeCallback(options, do_type_value, NULL); + tree = mxmlLoadString(NULL, options, document); + if (tree == NULL) + { + fprintf(stderr, "Unable to parse the XML document\n"); + ret = 1; + goto out_options; + } + + // Find and update the integer value + value = mxmlFindPath(tree, "value"); + if (value == NULL) + { + fprintf(stderr, "Unable to find the value element\n"); + ret = 1; + goto out_tree; + } + + printf("Mini-XML parsed value: %ld\n", mxmlGetInteger(value)); + + // Set value to 84 + if (!mxmlSetInteger(value, 84)) + { + fprintf(stderr, "Unable to update the value element\n"); + ret = 1; + goto out_tree; + } + + // Add a status element to the document + status = mxmlNewElement(tree, "status"); + if ((status == NULL) || (mxmlNewOpaque(status, "updated") == NULL)) + { + fprintf(stderr, "Unable to add the status element\n"); + ret = 1; + goto out_tree; + } + + // Serialize and print the modified document + mxmlOptionsSetWrapMargin(options, 0); + output_len = mxmlSaveString(tree, options, output, sizeof(output)); + if ((output_len == 0) || (output_len >= sizeof(output))) + { + fprintf(stderr, "Unable to serialize the XML document\n"); + ret = 1; + goto out_tree; + } + + printf("Modified XML: %s\n", output); + +out_tree: + mxmlDelete(tree); +out_options: + mxmlOptionsDelete(options); + + return (ret); +} + diff --git a/zephyr/tests/CMakeLists.txt b/zephyr/tests/CMakeLists.txt new file mode 100644 index 0000000..b4b7633 --- /dev/null +++ b/zephyr/tests/CMakeLists.txt @@ -0,0 +1,42 @@ +# +# CMakeLists for wrapping the Mini-XML test program for Zephyr. +# +# https://www.msweet.org/mxml +# +# Copyright © 2026 by Romain Pelletant. +# +# Licensed under Apache License v2.0. See the file "LICENSE" for more +# information. +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(mxml_smoke) + +set(MXML_ROOT ${CMAKE_CURRENT_LIST_DIR}/../..) +set(MXML_UPSTREAM_TEST ${MXML_ROOT}/testmxml.c) +set(MXML_TEST_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/include) + +include(${CMAKE_CURRENT_LIST_DIR}/../version.cmake) +if(CONFIG_POSIX_THREADS) + set(HAVE_PTHREAD_H 1) +endif() +configure_file( + ${CMAKE_CURRENT_LIST_DIR}/../config.h.in + ${MXML_TEST_INCLUDE_DIR}/config.h +) + +target_sources(app PRIVATE + src/main.c + ${MXML_UPSTREAM_TEST} +) +target_include_directories(app PRIVATE ${MXML_TEST_INCLUDE_DIR}) + +# Keep the upstream test source unchanged and expose its entry point to Ztest. +set_source_files_properties( + ${MXML_UPSTREAM_TEST} + PROPERTIES COMPILE_DEFINITIONS "main=testmxml_main" +) + diff --git a/zephyr/tests/prj.conf b/zephyr/tests/prj.conf new file mode 100644 index 0000000..ebb7cb8 --- /dev/null +++ b/zephyr/tests/prj.conf @@ -0,0 +1,16 @@ +# +# Configuration for the Mini-XML Zephyr tests. +# +# Copyright © 2026 by Romain Pelletant. +# +# Licensed under Apache License v2.0. See the file "LICENSE" for more +# information. +# +# SPDX-License-Identifier: Apache-2.0 +# + +CONFIG_MXML=y +CONFIG_ZTEST=y +CONFIG_POSIX_API=y +CONFIG_ZTEST_STACK_SIZE=20480 +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=16384 diff --git a/zephyr/tests/src/main.c b/zephyr/tests/src/main.c new file mode 100644 index 0000000..f710256 --- /dev/null +++ b/zephyr/tests/src/main.c @@ -0,0 +1,66 @@ +// +// Zephyr test suite wrapped to testmxml.c. +// +// https://www.msweet.org/mxml +// +// Copyright © 2026 by Romain Pelletant. +// +// Licensed under Apache License v2.0. See the file "LICENSE" for more +// information. +// +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include +#include + +extern int testmxml_main(int argc, char *argv[]); + +// +// 'test_parse_string()' - Test parsing an XML string. Smoke test. +// + +ZTEST(mxml, test_parse_string) +{ + mxml_options_t *options = mxmlOptionsNew(); // Load options + mxml_node_t *tree; // Parsed XML tree + mxml_node_t *answer; // Answer element + + // Parse an integer value from a small XML document... + zassert_not_null(options, "failed to allocate Mini-XML options"); + mxmlOptionsSetTypeValue(options, MXML_TYPE_INTEGER); + + tree = mxmlLoadString(NULL, options, "42"); + zassert_not_null(tree, "failed to parse XML"); + + answer = mxmlFindPath(tree, "answer"); + zassert_not_null(answer, "failed to find parsed element"); + zassert_equal(mxmlGetInteger(answer), 42, "unexpected parsed value"); + + mxmlDelete(tree); + mxmlOptionsDelete(options); +} + +// +// 'test_upstream_suite()' - Run the upstream test program. +// + +ZTEST(mxml, test_upstream_suite) +{ + static char document[] = // XML test document + "" + "42"; + char *argv[] = // Test program arguments + { + "testmxml", + document, + }; + + // Run the upstream tests using the in-memory document + zassert_equal(testmxml_main(ARRAY_SIZE(argv), argv), 0, + "upstream testmxml suite failed"); +} + +ZTEST_SUITE(mxml, NULL, NULL, NULL, NULL, NULL); + diff --git a/zephyr/tests/testcase.yaml b/zephyr/tests/testcase.yaml new file mode 100644 index 0000000..dfbe741 --- /dev/null +++ b/zephyr/tests/testcase.yaml @@ -0,0 +1,20 @@ +# +# Twister metadata for the Mini-XML Zephyr tests. +# +# Copyright © 2026 by Romain Pelletant. +# +# Licensed under Apache License v2.0. See the file "LICENSE" for more +# information. +# +# SPDX-License-Identifier: Apache-2.0 +# + +tests: + libraries.mxml: + tags: + - mxml + - xml + platform_allow: + - native_sim + - qemu_cortex_m3 + diff --git a/zephyr/version.cmake b/zephyr/version.cmake new file mode 100644 index 0000000..8d87aa9 --- /dev/null +++ b/zephyr/version.cmake @@ -0,0 +1,32 @@ +# +# Version extraction for Mini-XML on Zephyr. +# +# Copyright © 2026 by Romain Pelletant. +# +# Licensed under Apache License v2.0. See the file "LICENSE" for more +# information. +# +# SPDX-License-Identifier: Apache-2.0 +# + +if(NOT DEFINED MXML_ROOT) + set(MXML_ROOT ${CMAKE_CURRENT_LIST_DIR}/..) +endif() + +file(STRINGS ${MXML_ROOT}/configure.ac MXML_AC_INIT + REGEX "^AC_INIT\\(\\[Mini-XML\\], \\[[0-9]+\\.[0-9]+\\.[0-9]+\\]" + LIMIT_COUNT 1 +) + +if(NOT MXML_AC_INIT) + message(FATAL_ERROR "Unable to read the Mini-XML version from configure.ac") +endif() + +string(REGEX REPLACE + "^AC_INIT\\(\\[Mini-XML\\], \\[([^]]+)\\].*" + "\\1" + MXML_PACKAGE_VERSION + "${MXML_AC_INIT}" +) +set(MXML_VERSION "Mini-XML v${MXML_PACKAGE_VERSION}") + From 9f679edf767f8cfd0740b76888751548e0bf772f Mon Sep 17 00:00:00 2001 From: Romain PELLETANT Date: Thu, 15 Oct 2026 12:27:59 +0200 Subject: [PATCH 2/3] ci: add zephyr build and test - Add zephyr build in common build ci workflow Signed-off-by: Romain PELLETANT --- .github/workflows/build.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8a8a899..875ad8e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -60,3 +60,26 @@ jobs: uses: microsoft/setup-msbuild@v1.0.2 - name: Build Mini-XML run: msbuild vcnet\mxml.sln + + build-zephyr: + + runs-on: ubuntu-latest + + steps: + - name: Checkout Mini-XML sources + uses: actions/checkout@v4 + with: + path: mxml + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Set up Zephyr project + uses: zephyrproject-rtos/action-zephyr-setup@v1 + with: + app-path: mxml + toolchains: arm-zephyr-eabi + - name: Build Mini-XML sample + run: west build -b qemu_cortex_m3 mxml/zephyr/samples/basic + - name: Test Mini-XML + run: west twister -T mxml/zephyr/tests -p qemu_cortex_m3 --inline-logs From 5838e3f9195c00b1f0d47993f29283c41fa58500 Mon Sep 17 00:00:00 2001 From: Romain PELLETANT Date: Thu, 15 Oct 2026 17:34:55 +0200 Subject: [PATCH 3/3] rel: ensure cpe/purl version are updated - Add two checks for version update in zephyr/module.yml Signed-off-by: Romain PELLETANT --- makesrcdist | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/makesrcdist b/makesrcdist index a76ac50..42532f3 100755 --- a/makesrcdist +++ b/makesrcdist @@ -78,6 +78,16 @@ if test "$(grep MXML_VERSION xcode/config.h | awk '{print $5}')" != "v$version\" status=1 fi +if ! grep -Fq "cpe:2.3:a:msweet:mini-xml:$version:" zephyr/module.yml; then + echo "Update CPE version in zephyr/module.yml." + status=1 +fi + +if ! grep -Fq "pkg:github/michaelrsweet/mxml@v$version" zephyr/module.yml; then + echo "Update PURL version in zephyr/module.yml." + status=1 +fi + if test $status = 1; then exit 1 fi