How to contribute to the µOS++ Intrusive Lists
This page is designed for developers who plan to contribute new features or fix bugs in the µOS++ Intrusive Lists project and provides documentation on how to build and test the package.
The project is written in modern C++ and, for reproducibility reasons, uses 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 carried out on macOS, GNU/Linux and even Windows (although some npm scripts must be executed in a Git Bash terminal).
The prerequisites are:
- git
- node >= 18.0.0
- npm
To run the native tests with the system tools,
a C++ development environment is required.
On macOS install Command Line Tools, on Ubuntu build-essential
.
For details on installing the prerequisites, please read the Prerequisites page.
Get project sources
The project is hosted on GitHub:
Branches
The project uses multiple branches:
master
, not actively usedxpack
, with the latest stable version (default)xpack-development
, with the current development versionwebsite
, with the current content of the website; pushes to this branch automatically trigger publishes the main websitedevelopment
, with the current content of the preview website; pushes to this branch automatically trigger publishes the preview website
All development is done 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 merged
into xpack
.
To clone the stable branch (xpack
), run 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
Or, if the repo was already cloned:
git -C ~/Work/micro-os-plus/utils-lists-xpack.git pull
To contribute Pull Requests, fork the project and be sure the Copy the master branch only is disabled.
Use the xpack-development
branch and be sure you contribute the
Pull Requests back to the xpack-development
branch.
Add links for development
During development, it is convenient to have a writable instance of the library to make 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
Get the writable helper sources (optional, for development purposes)
The project has a dependency to a common helper, that is normally installed
as a read-only dependency; for development purposes, to be able to make
changes to the scripts located inside 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
Or, if the repo was already cloned:
git -C ~/Work/micro-os-plus/build-helper-xpack.git pull
If a writable instance of this library is needed 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
Run the following commands in the project folder:
npm install
npm install -C tests
xpm install -C tests
Language standard compliance
The library is written in modern C++ and should be compiled with -std=c++20
.
Code formatting
As formatting style, the library uses a .clang-format configuration file based on the GNU style.
Code formatting is done using clang-format --style=file
, either manually
from a script, or automatically from Visual Studio Code, or the Eclipse
CppStyle plug-in.
Visual Studio Code can directly utilise the .clang-format
file in the
Format Document command.
Always reformat the source files that were changed 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 can be executed on any of the supported host platforms:
- GNU/Linux (x64 and arm64, GLIBC>=2.28); to run the native
tests, a C++ development environment is required
(on Ubuntu install
build-essential
) - macOS (>= 11.0); as C++ development environment use 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
- run the test applications as native processes on the development machineplatforms/qemu-cortex-m0
- run 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
- run 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
- run 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
- run 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
- run the tests as fully semihosted Cortex-A15 applications on a QEMU virt emulated boardplatforms/qemu-cortex-a72
- run the tests as fully semihosted Cortex-A72 (64-bit) applications on a QEMU virt emulated boardplatforms/qemu-riscv-rv32imac
- run the tests as fully semihosted RISC-V RV32IMAC applications on a QEMU virt emulated boardplatforms/qemu-riscv-rv64imafdc
- run the tests as fully semihosted RISC-V RV64IMAFDC applications on a QEMU virt emulated board
The build configurations use 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 using various toolchains, including multiple versions of the same toolchain.
The following toolchains are used:
- 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 run various tests on the local development machine.
It is recommended to begin by performing some clean-ups (not necessary
after the initial git clone
):
npm install -C ~/Work/micro-os-plus/utils-lists-xpack.git/tests
xpm run deep-clean -C ~/Work/micro-os-plus/utils-lists-xpack.git/tests
During the initial run, the installation step may take a considerable amount of time, as it needs to download the toolchain archives, which can be relatively large, up to several hundred megabytes.
To run 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 run 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 run 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 run 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
Running all tests may require several gigabytes of space.
To clean up the tests folder, use:
npm install -C ~/Work/micro-os-plus/utils-lists-xpack.git/tests
xpm run deep-clean -C ~/Work/micro-os-plus/utils-lists-xpack.git/tests
A considerable amount of space may also be used by the toolchains.
When no longer needed, they can be removed with xpm uninstall
.
xpm clean-ups
For a thorough clean-up, please note that xpm uses only two folders:
- Windows
- macOS
- GNU/Linux
%APPDATA%\Roaming\xPacks
%APPDATA%\Local\Caches\xPacks
${HOME}/Library/xPacks
${HOME}/Library/Caches/xPacks
${HOME}/.local/xPacks
${HOME}/.cache/xPacks
They can be removed at any time and space reclaimed; xpm will recreate them on new installs.
However, projects linking to the user's global xPacks store will fail with broken paths.
Continuous Integration (CI)
The library is CI tested on every push via GitHub Actions, on Ubuntu, macOS, and Windows.
The tests run on 32 and 64-bit bare-metal platforms (Arm Cortex-M0, Cortex-M3, Cortex-M4F, Cortex-M7F, Cortex-A15, Cortex-A72, RISC-V RV32IMAC, RV64IMAFDC), and natively, with GCC and LLVM/clang.
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.
Re-generate the Doxygen pages
Run the doxygen npm script:
npm run doxygen -C website
For the moment the doxygen program must be installed on the host, it is not available as an xpm dependency.
With the current configuration, the static html pages are generated
in the website/static/reference
folder.
Prepare the website
The documentation site is built with Docusaurus and published in the project GitHub Pages.
- switch to the
xpack-development
branch - run the website-generate-commons npm script in the
website/package.json
npm run website-generate-commons -C website
- commit all changes
Build the static website locally
Validate the website content in a local build via the npm build script:
npm run build -C website
Fix any broken links, if any.
Start the local web server
Execute the npm script clean then start in the website sub-project, or run the following in the project folder:
npm run clean -C website
npm run start -C website
Navigate to the Maintainer Info page, the Start the local web server section.