Skip to main content

How to contribute to the µOS++ Intrusive Lists

GitHub package.json version NPM Version license GitHub issues GitHub pulls CI on Push license

This page is designed for developers who intend to contribute new features or resolve bugs within the µOS++ Intrusive Lists project and provides documentation on building and testing the package.

The project is written in modern C++ and, for reproducibility reasons, utilises the xPack Framework tools during development.

Prerequisites

@micro-os-plus/utils-lists is an xpm package that provides a C++ source code library; development can be conducted on macOS, GNU/Linux and Windows (although some npm scripts must be executed within a Git Bash terminal).

The prerequisites are:

  • git
  • node >= 18.0.0
  • npm

To execute the native tests with the system tools, a C++ development environment is required. On macOS, install Command Line Tools; on Ubuntu, install build-essential.

For details on installing the prerequisites, please refer to the Prerequisites page.

Obtain project sources

The project is hosted on GitHub:

Branches

This project utilises multiple branches:

  • master, not actively used
  • xpack, containing the latest stable version (default)
  • xpack-development, containing the current development version
  • website, containing the current website content; pushes to this branch automatically trigger publication of the main website
  • development, containing the current preview website content; pushes to this branch automatically trigger publication of the preview website

All development is conducted in the xpack-development branch, and contributions via Pull Requests should be directed to this branch.

When new releases are published, the xpack-development branch is rebased onto xpack.

To clone the stable branch (xpack), execute the following commands in a terminal (on Windows use the Git Bash console):

rm -rf ~/Work/micro-os-plus/utils-lists-xpack.git && \
mkdir -p ~/Work/micro-os-plus && \
git clone \
--branch xpack \
https://github.com/micro-os-plus/utils-lists-xpack.git \
~/Work/micro-os-plus/utils-lists-xpack.git
For development purposes, clone the xpack-development branch.
rm -rf ~/Work/micro-os-plus/utils-lists-xpack.git && \
mkdir -p ~/Work/micro-os-plus && \
git clone \
--branch xpack-development \
https://github.com/micro-os-plus/utils-lists-xpack.git \
~/Work/micro-os-plus/utils-lists-xpack.git

Alternatively, if the repository has already been cloned:

git -C ~/Work/micro-os-plus/utils-lists-xpack.git pull
tip

To contribute Pull Requests, fork the project and ensure the Copy the master branch only is disabled.

Utilise the xpack-development branch and ensure you contribute the Pull Requests back to the xpack-development branch.

During development, it is convenient to maintain a writable instance of the library to enable changes in parallel with the parent project.

To facilitate the use of a writable instance of this library in other projects, add a link from the user's global xPacks store to this local development folder:

xpm link -C ~/Work/micro-os-plus/utils-lists-xpack.git

And in the projects referring it:

xpm link @micro-os-plus/utils-lists
Obtain the writable helper sources (optional, for development purposes)

The project has a dependency on a common helper, which is normally installed as a read-only dependency; for development purposes, to enable modifications to the scripts located within the helper, clone the xpack-development branch and link it to the user's global xPacks store:

rm -rf ~/Work/micro-os-plus/build-helper-xpack.git && \
mkdir -p ~/Work/micro-os-plus && \
git clone \
--branch xpack-development \
https://github.com/micro-os-plus/build-helper-xpack.git \
~/Work/micro-os-plus/build-helper-xpack.git

Alternatively, if the repository has already been cloned:

git -C ~/Work/micro-os-plus/build-helper-xpack.git pull

If a writable instance of this library is required in another project, add a link from the user's global xPacks store to it:

xpm link -C ~/Work/micro-os-plus/build-helper-xpack.git

Satisfy dependencies

Navigate to the project folder:

cd ~/Work/xpack/micro-os-plus/utils-lists-xpack.git

and execute the following commands:

npm install
npm --prefix tests install
xpm install -C tests

Language standard compliance

The library is written in modern C++ and should be compiled with -std=c++20.

Code formatting

For formatting style, the library employs a .clang-format configuration file based on the GNU style.

Code formatting is performed using clang-format --style=file, either manually via a script, or automatically through Visual Studio Code, or the Eclipse CppStyle plug-in.

info

Visual Studio Code can directly utilise the .clang-format file within the Format Document command.

tip

Always reformat the source files that have been modified before committing them to the repository.

Tests

The µOS++ testing strategy involves compiling the sources with as many toolchains as possible and executing them on a wide range of platforms.

Host Platforms

The tests may be executed on any of the supported host platforms:

  • GNU/Linux (x64 and arm64, GLIBC>=2.28); to execute the native tests, a C++ development environment is required (on Ubuntu install build-essential)
  • macOS (>= 11.0); as C++ development environment utilise Command Line Tools
  • Windows 7 with the Universal C Runtime (UCRT), Windows 8, Windows 10, Windows 11

Target Platforms

The supported target test platforms are:

  • platforms/native - execute the test applications as native processes on the development machine
  • platforms/qemu-cortex-m0 - execute the tests as fully semihosted Cortex-M0 applications on a QEMU mps2-an385 emulated board (an Arm Cortex-M3 development board)
  • platforms/qemu-cortex-m3 - execute the tests as fully semihosted Cortex-M3 applications on a QEMU mps2-an385 emulated board (an Arm Cortex-M3 development board)
  • platforms/qemu-cortex-m4f - execute the tests as fully semihosted Cortex-M4 applications on a QEMU mps2-an386 emulated board (an Arm Cortex-M4 development board)
  • platforms/qemu-cortex-m7f - execute the tests as fully semihosted Cortex-M7 applications on a QEMU mps2-an500 emulated board (an Arm Cortex-M7 development board)
  • platforms/qemu-cortex-a15 - execute the tests as fully semihosted Cortex-A15 applications on a QEMU virt emulated board
  • platforms/qemu-cortex-a72 - execute the tests as fully semihosted Cortex-A72 (64-bit) applications on a QEMU virt emulated board
  • platforms/qemu-riscv-rv32imac - execute the tests as fully semihosted RISC-V RV32IMAC applications on a QEMU virt emulated board
  • platforms/qemu-riscv-rv64imafdc - execute the tests as fully semihosted RISC-V RV64IMAFDC applications on a QEMU virt emulated board

The build configurations utilise exactly the same source files on all platforms, without changes.

Semihosting

On embedded platforms, the applications interact with the host via the Arm semihosting mechanism.

Toolchains

To enhance source code portability, the builds are repeatedly conducted utilising various toolchains, including multiple versions of the same toolchain.

The following toolchains are utilised:

  • gcc (native)
  • clang (native)
  • arm-none-eabi-gcc (Cortex-M, AArch32)
  • aarch64-none-elf-gcc (AArch64)
  • risc-none-elf-gcc (RISC-V 32/64)

Tests details

sample-test

The sample-test.cpp file is a simple application to demonstrate how to call the few primitives available in the library.

A typical run looks like:

test 1
Start 1: sample-test

1: Test command: /Users/ilg/MyProjects/micro-os-plus.github/xPacks/utils-lists-xpack.git/tests/build/native-cmake-sys-debug/platform-bin/sample-test "one" "two"
1: Working Directory: /Users/ilg/MyProjects/micro-os-plus.github/xPacks/utils-lists-xpack.git/tests/build/native-cmake-sys-debug/platform-bin
1: Test timeout computed to be: 10000000
1: micro_os_plus::trace::initialize()
1:
1: All kids:
1: - Mary
1: - Bob
1: - Sally
1: - Doug
1:
1: Bob is gone...
1: - Mary
1: - Sally
1: - Doug
1:
1: School kids:
1: - Sally
1: - Doug
1:
1: Done.
1/2 Test #1: sample-test ...................... Passed 0.00 sec

unit-test

The unit-test.cpp file is an exhaustive test trying to validate that all the library functions work as expected. It uses the µTest++ testing framework.

A typical run looks like:

test 2
Start 2: unit-test

2: Test command: /Users/ilg/MyProjects/micro-os-plus.github/xPacks/utils-lists-xpack.git/tests/build/native-cmake-sys-debug/platform-bin/unit-test
2: Working Directory: /Users/ilg/MyProjects/micro-os-plus.github/xPacks/utils-lists-xpack.git/tests/build/native-cmake-sys-debug/platform-bin
2: Test timeout computed to be: 10000000
2: micro_os_plus::trace::initialize()
2: micro_os_plus::micro_test_plus::test_suite_base::test_suite_base(const char *)
2: micro_os_plus::micro_test_plus::test_suite::test_suite(const char *, Callable_T &&, Args_T &&...) [Callable_T = void (&)(), Args_T = <>]
2: micro_os_plus::micro_test_plus::test_suite_base::test_suite_base(const char *)
2: micro_os_plus::micro_test_plus::test_suite::test_suite(const char *, Callable_T &&, Args_T &&...) [Callable_T = void (&)(), Args_T = <>]
2: micro_os_plus::micro_test_plus::test_suite_base::test_suite_base(const char *)
2: micro_os_plus::micro_test_plus::test_suite::test_suite(const char *, Callable_T &&, Args_T &&...) [Callable_T = void (&)(), Args_T = <>]
2: micro_os_plus::micro_test_plus::test_suite_base::test_suite_base(const char *)
2: micro_os_plus::micro_test_plus::test_suite::test_suite(const char *, Callable_T &&, Args_T &&...) [Callable_T = void (&)(), Args_T = <>]
2: micro_os_plus::micro_test_plus::test_suite_base::test_suite_base(const char *)
2: micro_os_plus::micro_test_plus::test_suite::test_suite(const char *, Callable_T &&, Args_T &&...) [Callable_T = void (&)(), Args_T = <>]
2: micro_os_plus::micro_test_plus::test_suite_base::test_suite_base(const char *)
2: micro_os_plus::micro_test_plus::test_suite::test_suite(const char *, Callable_T &&, Args_T &&...) [Callable_T = void (&)(), Args_T = <>]
2: micro_os_plus::micro_test_plus::test_suite_base::test_suite_base(const char *)
2: micro_os_plus::micro_test_plus::test_suite::test_suite(const char *, Callable_T &&, Args_T &&...) [Callable_T = void (&)(), Args_T = <>]
2: micro_os_plus::micro_test_plus::test_suite_base::test_suite_base(const char *)
2: micro_os_plus::micro_test_plus::test_suite::test_suite(const char *, Callable_T &&, Args_T &&...) [Callable_T = void (&)(), Args_T = <>]
2: micro_os_plus::micro_test_plus::test_suite_base::test_suite_base(const char *)
2: micro_os_plus::micro_test_plus::test_suite::test_suite(const char *, Callable_T &&, Args_T &&...) [Callable_T = void (&)(), Args_T = <>]
2: micro_os_plus::micro_test_plus::test_suite_base::test_suite_base(const char *)
2: micro_os_plus::micro_test_plus::test_suite::test_suite(const char *, Callable_T &&, Args_T &&...) [Callable_T = void (&)(), Args_T = <>]
2: micro_os_plus::micro_test_plus::test_suite_base::test_suite_base(const char *)
2: micro_os_plus::micro_test_plus::test_suite::test_suite(const char *, Callable_T &&, Args_T &&...) [Callable_T = void (&)(), Args_T = <>]
2: micro_os_plus::micro_test_plus::test_runner::test_runner()
2: void micro_os_plus::micro_test_plus::initialize(int, char **, const char *)
2: void micro_os_plus::micro_test_plus::test_runner::initialize(int, char **, const char *)
2: argv['/Users/ilg/MyProjects/micro-os-plus.github/xPacks/utils-lists-xpack.git/tests/build/native-cmake-sys-debug/platform-bin/unit-test']
2: Built with clang Apple LLVM 16.0.0 (clang-1600.0.26.6), with exceptions, with MICRO_OS_PLUS_DEBUG.
2: micro_os_plus::micro_test_plus::test_suite_base::test_suite_base(const char *)
2:
2: • Static double list links destructor - test suite started
2:
2: ✓ Static - test case passed (4 checks)
2:
2: ✓ Static double list links destructor - test suite passed (4 checks in 1 test case)
2:
2: • Static double list links - test suite started
2:
2: ✓ Initial - test case passed (6 checks)
2: ✓ Link - test case passed (3 checks)
2: ✓ Unlink - test case passed (3 checks)
2:
2: ✓ Static double list links - test suite passed (12 checks in 3 test cases)
2:
2: • Double list links - test suite started
2:
2: ✓ Initial - test case passed (3 checks)
2: ✓ Link - test case passed (3 checks)
2: ✓ Unlink - test case passed (3 checks)
2: ✓ Allocated on stack - test case passed (1 check)
2:
2: ✓ Double list links - test suite passed (10 checks in 4 test cases)
2:
2: • Static double list - test suite started
2:
2: ✓ Uninitialized - test case passed (3 checks)
2: ✓ Empty - test case passed (2 checks)
2: ✓ Link One - test case passed (7 checks)
2: ✓ Link Two - test case passed (8 checks)
2: ✓ Unlink One - test case passed (6 checks)
2: ✓ Unlink Two - test case passed (3 checks)
2: ✓ Link One again - test case passed (2 checks)
2: ✓ Clear - test case passed (2 checks)
2:
2: ✓ Static double list - test suite passed (33 checks in 8 test cases)
2:
2: • Static double list with static elements - test suite started
2:
2: ✓ Uninitialized - test case passed (3 checks)
2: ✓ Empty - test case passed (2 checks)
2: ✓ Link One - test case passed (7 checks)
2: ✓ Link Two - test case passed (8 checks)
2: ✓ Unlink One - test case passed (6 checks)
2: ✓ Unlink Two - test case passed (3 checks)
2: ✓ Link One again - test case passed (2 checks)
2: ✓ Clear - test case passed (2 checks)
2:
2: ✓ Static double list with static elements - test suite passed (33 checks in 8 test cases)
2:
2: • Double list - test suite started
2:
2: ✓ Uninitialized - test case passed (3 checks)
2: ✓ Empty - test case passed (2 checks)
2: ✓ Link One - test case passed (7 checks)
2: ✓ Link Two - test case passed (8 checks)
2: ✓ Unlink One - test case passed (6 checks)
2: ✓ Unlink Two - test case passed (3 checks)
2: ✓ Link One again - test case passed (2 checks)
2: ✓ Clear - test case passed (2 checks)
2: ✓ Allocated on stack - test case passed (2 checks)
2:
2: ✓ Double list - test suite passed (35 checks in 9 test cases)
2:
2: • Double list with static elements - test suite started
2:
2: ✓ Uninitialized - test case passed (3 checks)
2: ✓ Empty - test case passed (2 checks)
2: ✓ Link One - test case passed (7 checks)
2: ✓ Link Two - test case passed (8 checks)
2: ✓ Unlink One - test case passed (6 checks)
2: ✓ Unlink Two - test case passed (3 checks)
2: ✓ Link One again - test case passed (2 checks)
2: ✓ Clear - test case passed (2 checks)
2: ✓ Allocated on stack - test case passed (2 checks)
2:
2: ✓ Double list with static elements - test suite passed (35 checks in 9 test cases)
2:
2: • Static intrusive list2 - test suite started
2:
2: ✓ Empty - test case passed (3 checks)
2: ✓ Link Mary - test case passed (4 checks)
2: ✓ Link Bob - test case passed (6 checks)
2: ✓ Link Sally - test case passed (8 checks)
2: ✓ Unlink Bob - test case passed (6 checks)
2: ✓ Unlink Mary - test case passed (4 checks)
2: ✓ Link Mary at head - test case passed (6 checks)
2: ✓ Unlink Mary - test case passed (4 checks)
2: ✓ Unlink Sally - test case passed (2 checks)
2: ✓ Link Mary again - test case passed (2 checks)
2: ✓ Clear - test case passed (2 checks)
2:
2: ✓ Static intrusive list2 - test suite passed (47 checks in 11 test cases)
2:
2: • Static intrusive list static nodes - test suite started
2:
2: ✓ Empty - test case passed (3 checks)
2: ✓ Link Mary - test case passed (4 checks)
2: ✓ Link Bob - test case passed (6 checks)
2: ✓ Link Sally - test case passed (8 checks)
2: ✓ Unlink Bob - test case passed (6 checks)
2: ✓ Unlink Mary - test case passed (4 checks)
2: ✓ Link Mary at head - test case passed (6 checks)
2: ✓ Unlink Mary - test case passed (4 checks)
2: ✓ Unlink Sally - test case passed (2 checks)
2: ✓ Link Mary again - test case passed (2 checks)
2: ✓ Clear - test case passed (2 checks)
2:
2: ✓ Static intrusive list static nodes - test suite passed (47 checks in 11 test cases)
2:
2: • Intrusive list2 - test suite started
2:
2: ✓ Empty - test case passed (3 checks)
2: ✓ Link Mary - test case passed (4 checks)
2: ✓ Link Bob - test case passed (6 checks)
2: ✓ Link Sally - test case passed (8 checks)
2: ✓ Unlink Bob - test case passed (6 checks)
2: ✓ Unlink Mary - test case passed (4 checks)
2: ✓ Link Mary at head - test case passed (6 checks)
2: ✓ Unlink Mary - test case passed (4 checks)
2: ✓ Unlink Sally - test case passed (2 checks)
2: ✓ Link Mary again - test case passed (2 checks)
2: ✓ Clear - test case passed (2 checks)
2: ✓ Allocated on stack - test case passed (2 checks)
2:
2: ✓ Intrusive list2 - test suite passed (49 checks in 12 test cases)
2:
2: • Intrusive list static nodes - test suite started
2:
2: ✓ Empty - test case passed (3 checks)
2: ✓ Link Mary - test case passed (4 checks)
2: ✓ Link Bob - test case passed (6 checks)
2: ✓ Link Sally - test case passed (8 checks)
2: ✓ Unlink Bob - test case passed (6 checks)
2: ✓ Unlink Mary - test case passed (4 checks)
2: ✓ Link Mary at head - test case passed (6 checks)
2: ✓ Unlink Mary - test case passed (4 checks)
2: ✓ Unlink Sally - test case passed (2 checks)
2: ✓ Link Mary again - test case passed (2 checks)
2: ✓ Clear - test case passed (2 checks)
2: ✓ Allocated on stack - test case passed (2 checks)
2:
2: ✓ Intrusive list static nodes - test suite passed (49 checks in 12 test cases)
2: virtual micro_os_plus::micro_test_plus::test_suite::~test_suite()
2: virtual micro_os_plus::micro_test_plus::test_suite::~test_suite()
2: virtual micro_os_plus::micro_test_plus::test_suite::~test_suite()
2: virtual micro_os_plus::micro_test_plus::test_suite::~test_suite()
2: virtual micro_os_plus::micro_test_plus::test_suite::~test_suite()
2: virtual micro_os_plus::micro_test_plus::test_suite::~test_suite()
2: virtual micro_os_plus::micro_test_plus::test_suite::~test_suite()
2: virtual micro_os_plus::micro_test_plus::test_suite::~test_suite()
2: virtual micro_os_plus::micro_test_plus::test_suite::~test_suite()
2: virtual micro_os_plus::micro_test_plus::test_suite::~test_suite()
2: virtual micro_os_plus::micro_test_plus::test_suite::~test_suite()
2/2 Test #2: unit-test ........................ Passed 0.29 sec

Manual tests

There are predefined xpm actions available to manually execute various tests on the local development machine.

It is recommended to commence by performing some clean-ups (not necessary following the initial git clone):

npm --prefix ~/Work/micro-os-plus/utils-lists-xpack.git/tests install
xpm run deep-clean -C ~/Work/micro-os-plus/utils-lists-xpack.git/tests
tip

During the initial execution, the installation step may require a considerable amount of time, as it needs to download the toolchain archives, which can be relatively large, up to several hundred megabytes.

To execute the tests with the system compiler (usually not available on Windows):

xpm run install -C ~/Work/micro-os-plus/utils-lists-xpack.git/tests
xpm run test -C ~/Work/micro-os-plus/utils-lists-xpack.git/tests

To execute a selection of tests with the latest versions of toolchains:

xpm run install-selected -C ~/Work/micro-os-plus/utils-lists-xpack.git/tests
xpm run test-selected -C ~/Work/micro-os-plus/utils-lists-xpack.git/tests

To execute all tests with the latest versions of toolchains:

xpm run install-latest -C ~/Work/micro-os-plus/utils-lists-xpack.git/tests
xpm run test-latest -C ~/Work/micro-os-plus/utils-lists-xpack.git/tests

To execute all tests with all toolchain versions:

xpm run install-all -C ~/Work/micro-os-plus/utils-lists-xpack.git/tests
xpm run test-all -C ~/Work/micro-os-plus/utils-lists-xpack.git/tests

Clean-ups

Executing all tests may require several gigabytes of space.

To clean up the tests folder, utilise:

npm --prefix ~/Work/micro-os-plus/utils-lists-xpack.git/tests install
xpm run deep-clean -C ~/Work/micro-os-plus/utils-lists-xpack.git/tests

A considerable amount of space may also be utilised by the toolchains. When no longer required, they can be removed with xpm uninstall.

xpm clean-ups

For a comprehensive clean-up, please note that xpm utilises only two folders:

  • %APPDATA%\Roaming\xPacks
  • %APPDATA%\Local\Caches\xPacks

They can be removed at any time and space reclaimed; xpm will recreate them during new installations.

However, projects linking to the user's global xPacks store will fail with broken paths.

Continuous Integration (CI)

The library is subject to continuous integration (CI) testing with every push utilising GitHub Actions. This ensures compatibility and stability across Ubuntu, macOS, and Windows operating systems.

Testing is conducted on both 32-bit and 64-bit bare-metal platforms, including Arm Cortex-M0, Cortex-M3, Cortex-M4F, Cortex-M7F, Cortex-A15, Cortex-A72, RISC-V RV32IMAC, and RV64IMAFDC. Additionally, native testing is performed utilising GCC and LLVM/clang compilers, ensuring comprehensive validation across various environments.

The website

The project includes the source files for its website. The main pages are generated with Docusaurus, and the reference pages are generated with Doxygen.

Regenerate the Doxygen pages

Execute the doxygen npm script:

npm --prefix ~/Work/micro-os-plus/utils-lists-xpack.git/website run doxygen

At present, the doxygen programme must be installed on the host, as it is not available as an xpm dependency.

With the current configuration, the static HTML pages are generated within the website/static/doxygen folder.

Prepare the website

The documentation site is built using Docusaurus and published on the project GitHub Pages.

  • Switch to the xpack-development branch
  • Execute the website-generate-commons npm script in the website/package.json
    npm --prefix ~/Work/micro-os-plus/utils-lists-xpack.git/website run website-generate-commons
  • Commit all changes

Build the static website locally

Validate the website content by performing a local build using the npm build script:

npm --prefix ~/Work/micro-os-plus/utils-lists-xpack.git/website run build

Resolve any broken links that may be identified during the build process.

Start the local web server

Execute the npm script clear followed by start in the website sub-project, or execute the following within the project folder:

npm --prefix ~/Work/micro-os-plus/utils-lists-xpack.git/website run clear
npm --prefix ~/Work/micro-os-plus/utils-lists-xpack.git/website run start

Navigate to the Maintainer Info page, the Start the local web server section.