This document outlines a complete strategy to enable selectable debug and release build variants for packages built with pixi-build. The approach is rooted in a modular compiler architecture and is controlled by a custom build variant (profile) in the pixi.toml configuration.
This design centralizes the build configuration logic within the workspace, keeps individual recipe.yaml files clean and declarative, and guarantees ABI compatibility across the entire dependency tree.
Before the build tool can select variants, a modular package structure must exist. This involves separating the compiler toolchain into distinct components and creating special "token" packages to enforce build consistency.
To prevent a debug library from being linked against a release dependency, we create two variants of an empty package profile
and they are conflicting with each other. Their only purpose is to act as a lock, ensuring an environment is exclusively one mode. You'd select packages with the build string.
The core principle is to refactor the monolithic compiler package into composable pieces:
-
gcc_impl_linux-64
(Unchanged): Contains the raw compiler binaries, libraries, and headers, with no activation logic. -
gcc-core-activation_linux-64
(New): A package containing only an activation script that sets up the essential environment (PATH, CC, CXX, etc.) to run the compiler, but without setting any optimization or debug flags. -
gcc_linux-64
in debug variant (New): A package containing an activation script that applies debug flags (-g, -O0, -D_DEBUG). Has a strong run_export onprofile
of variantdebug
. -
gcc_linux-64
(New): A package containing an activation script that applies the standard release flags (-O2, -DNDEBUG). Has a strong run_export onprofile
of variantrelease
.
When pixi-build encounters compilers = ["c"]
in a recipe, it will automatically use the correct variant of the compiler: gcc_release_linux-64
for release mode and gcc_debug_linux-64
for dev mode. It does that by adding a constraint on profile
or profile
on the build environment.
The selected compiler automatically uses run_exports to inject the correct mutex dependency into the run dependencies of the final package, guaranteeing a consistent dependency tree.