Skip to content

Where the C++ optimisation flags come from, 2026-08-11

Verdict: pixi run build passes -DCMAKE_BUILD_TYPE=Release, and it changes nothing measurable. An empty CMAKE_BUILD_TYPE in build/*/CMakeCache.txt looks like an unoptimised robot and is not one — which is the thing worth recording here.

Empty means CMake appends no CMAKE_CXX_FLAGS_<CONFIG>; it does not mean -O0, because CMAKE_CXX_FLAGS is seeded from the environment's CXXFLAGS and the conda compiler packages export one — -O2 on linux-64, -O3 on linux-aarch64. mote-01's real compile lines carried -O3 before this change. kinematic_icp was never in question either: its own CMakeLists does set(CMAKE_BUILD_TYPE Release) (ros/CMakeLists.txt:26), shadowing the cache, so its objects already had -O3 -DNDEBUG.

So the flag adds -DNDEBUG on the robot and takes linux-64 from -O2 to -O3. Its point is that the level is now stated by the repo rather than inherited from whichever toolchain the solve picked, and survives a build outside pixi. Not RelWithDebInfo: config flags are appended after CXXFLAGS, so its -O2 would beat the Pi's -O3 and lower optimisation.

Measured

Replaying mapping bag 20260729_160009 into localization_launch.py (use_sim_time:=true) drives the real ICP at the recorded 10.0 Hz, identical input each run, so only the binary differs. Container utime + stime over a 120 s window, 3 reps a side, rebuild between:

mean CPU-s / 120 s mean ms per scan
before 2.207 1.837
after 2.200 1.831

−0.3% against a ±0.7% within-group spread: no effect, as expected from flags that barely moved. Also worth knowing: the whole container costs 1.8% of one core, so it is not where a nav mission's load goes.

-ffp-contract=off survives Release

odom_tf_relay's bit-identity against the Python it replaced depends on that flag (mote_nav/CMakeLists.txt:60), and Release now stacks -O3 over it. Target options are emitted last, so it still wins — counted in the shipped aarch64 objects, not inferred: libodom_tf_relay_component.so holds 0 fused multiply-adds before and after, while libicp_odom_gate_component.so (same -O3, no flag) holds 11 both times, so the zero is the flag and not a target without FMA. test_odom_tf_relay.cpp cannot catch this — it compares the relay against reference arithmetic in the same TU, under the same flag.