Skip to content

⚡ Add mp_units.si, a module with only SI, ISQ and angular - #5

Merged
kammce merged 1 commit into
libhal-2.6from
si-module
Oct 18, 2026
Merged

kammce merged 1 commit into
libhal-2.6from
si-module

Conversation

@kammce

@kammce kammce commented Oct 18, 2026

Copy link
Copy Markdown
Member

Adds mp_units.si, a module with only SI, the ISQ and angular units. mp_units.systems now imports and re-exports it, so all of mp-units stays available, and code that only needs SI can import much less.

Why

With C++ modules, CMake rebuilds the interface of every imported module in each consumer's build. mp_units.systems includes all 16 unit systems and is the slowest of these rebuilds. In libhal's Cortex-M deploys it's rebuilt for every architecture × build type, twice each counting the test_package (libhal/ci#132).

Compiling the module interface with LLVM 23, using the same command CMake generates:

Module contents Time BMI size
all 16 systems (mp_units.systems today) 12.3 s 161 MB
SI + ISQ + angular (mp_units.si) 3.7 s ~80 MB

Changes

  • New module: src/systems/mp-units-si.cpp defines mp_units.si (angular, isq, isq_angle, si), with CMake target mp-units::si.

  • mp_units.systems: does export import mp_units.si; and defines MP_UNITS_SI_MODULE_IMPORTED, instead of including the SI, ISQ and angular headers itself. The two modules can be imported together, because each declaration is attached to only one of them.

    Simply including the SI headers in both modules would break that: Clang rejects it with "declaration 'x' attached to named module 'b' cannot be attached to other modules". I confirmed that with a minimal two-module test.

  • Header guards: 18 headers of the other systems (cgs, iau, codata, hep, iec, natural, typographic, yard_pound, astronomy) skip their SI, ISQ and angular includes when MP_UNITS_SI_MODULE_IMPORTED is defined. That follows the existing pattern of skipping framework.h when MP_UNITS_IN_MODULE_INTERFACE is defined. Header-only builds are unchanged.

  • Targets: the 26 SI-set headers move from the systems target to the new si target, which systems links. The Conan recipe gets an si component.

Testing

  • Local build: conan create with libhal's options (freestanding, cxx_modules, no std_format, no import_std, contracts none, no RTTI) and LLVM 23 passes, including the test_package. The test_package imports the full mp_units umbrella, which brings in mp_units.systems and mp_units.si together.
  • Not tested: header-only builds, other compilers, and other option combinations. The fork's CI covers those.

Follow-up

For libhal to benefit, it would import mp_units.core plus mp_units.si and link mp-units::core mp-units::si, instead of mp_units and mp-units::mp-units. That's a separate libhal change.

mp_units.systems includes all 16 unit systems. Most code only uses SI,
yet every consumer pays for the whole module: with C++ modules, CMake
rebuilds each imported module's interface in every consumer build, and
mp_units.systems is the slowest one. Compiling it with LLVM 23 takes
12.3 s and makes a 161 MB BMI; SI, ISQ and angular alone take 3.7 s.

mp_units.si holds SI, the ISQ and angular units, and mp_units.systems
now imports and re-exports it instead of including those headers itself.
Code that only needs SI links mp-units::si and imports mp_units.si. The
two modules can be imported together, because each declaration is
attached to only one of them.

Headers of the other systems include SI headers. They now skip those
includes when MP_UNITS_SI_MODULE_IMPORTED is defined, which
mp_units.systems does after importing mp_units.si, the same way the
headers already skip framework.h inside a module interface. Header-only
builds are unchanged.

The SI headers move from the systems target to the new si target, and
the Conan recipe gets an "si" component.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant