A decade away
In 2016 my daughter was born, and like many things in life, my contributions to Mageia Linux quietly went on hold. I had been an active packager — maintaining packages, triaging bugs, helping with release coordination — but fatherhood rightly took the front seat.
Ten years later, I'm back. And what better way to return than by tackling one of the most requested and technically challenging packages the distribution has never shipped: .NET 8.
The unexpected setup: Mageia on WSL
This comeback came with an unusual twist. All the packaging work — the spec tweaking, the 30-hour source builds, the trial-and-error debugging — happened on Mageia Cauldron running inside WSL on Windows 11.
There's no official Mageia WSL image, so I built one myself. I started with
a VirtualBox virtual machine running Mageia Cauldron, got it configured as a
clean build environment with iurt, mgarepo, and all the packaging tools,
then exported the filesystem and imported it into WSL. A bit of kernel tuning,
some systemd shimming, and suddenly I had a native Mageia terminal sitting
alongside PowerShell — Linux package builds ticking away in one window, Windows
desktop in the other. It's not the setup I would have imagined in 2016, but it
works surprisingly well.
The 8 GB RAM ceiling wasn't a WSL limitation — it's what the laptop has. Those 20 virtual CPUs, though? That's WSL sharing the host's cores, and it made the difference between "impossible" and "just barely possible."
Why packaging matters
It's tempting to take the easy route. Microsoft provides official install
scripts — a few commands and you have dotnet on your system. Container
images are readily available. Why spend weeks wrestling with RPM specs?
Because free and open source software isn't just about the license. It's about the ecosystem.
When you install upstream binaries, you lose:
- Integration. Packages installed through the distribution's package manager respect system paths, shared libraries, and conventions. Upstream binaries drop files wherever the vendor decided and may conflict with system components.
- Security updates. A packaged application gets patched when the distribution ships a fix for a shared library it depends on. An upstream binary bundles its own copies of everything — and you won't know when any of them are vulnerable.
- Reproducibility. Source-built packages can be audited, verified, and rebuilt by anyone. Binary blobs are trust-me boxes.
- Community ownership. When a package lives in Mageia's repositories, it belongs to the community. Bugs get reported, fixes get contributed, and the package evolves with the distribution — not at the vendor's pace.
Packaging .NET for Mageia isn't just about convenience. It's about making the .NET ecosystem a first-class citizen of the free software world, built from source, by the community, for the community.
The plan: bootstrap from Fedora
Mageia had never shipped .NET. Starting from absolute zero — no spec files, no patches, no build infrastructure — would have taken months. So I took the pragmatic approach: start from Fedora's excellent packaging work.
Fedora's dotnet-sig, led by Omair Majid and team, has maintained .NET packages since version 5.0. Their spec file is battle-tested across multiple release cycles. My cardinal rule: never modify the upstream source tarball. Every change goes through spec scripts, patches, and separate source files — keeping the package auditable and making future rebases straightforward.
The goal was to build .NET 8.0.28 with SDK 8.0.128, producing native RPM packages for Mageia 11 (Cauldron).
The bootstrap problem
.NET is written in .NET. To compile the C# compiler, you need a working .NET SDK. To produce that SDK from source, you need a pre-existing SDK to compile it with.
The solution is a bootstrap build: use Fedora's pre-compiled SDK binaries to compile everything from source. The output becomes the new Mageia-native SDK, and subsequent builds use that instead.
Fedora binary SDK ──► Compile runtime, Roslyn, ASP.NET Core
(previously-built) Compile SDK itself ◄────── The hard part
When you build .NET from source, the build system orchestrates 28 separate repositories in a specific order, with outputs flowing as NuGet packages from one stage to the next. Each of those repositories brought its own surprises.
Four walls I had to climb
Wall 1: Runtime Identifier mismatch
The bootstrap SDK from Fedora 43 reports its RID as fedora.43-x64. But the
pre-built NuGet packages from Fedora 45 are tagged fedora.45-x64. Package
restore fails immediately — NuGet has never heard of fedora.43-x64.
Fix: A Python script that clones each runtime.fedora.45-x64.*.nupkg with
the RID replaced, creating runtime.fedora.43-x64.* aliases. It runs
automatically during the build's init phase. A classic bootstrapping hack, and
one that will be unnecessary once Mageia-built artifacts exist.
Wall 2: Memory
On a machine with 8 GB RAM, the build hits OOM repeatedly. Each sub-project spawns MSBuild nodes, Roslyn compiler processes, and various tools that quickly exhaust available memory. Exit code 137 — the kernel's way of saying "not today."
Fix: Disable the Roslyn compiler server, limit MSBuild parallelism to
/m:2, and cap compiler processes at DOTNET_PROCESSOR_COUNT=2.
Conservative, but stable.
Wall 3: The SDK inner build
The SDK project has a peculiarity: it runs an inner build that copies its
source tree to a temporary location and compiles there. This inner build runs
MSBuild directly, bypassing normal SDK initialization. The result: tasks like
ProcessFrameworkReferences and ResolveAppHosts fail because the Fedora
SDK doesn't recognize mageia.11-x64.
After many iterations, I made the pragmatic call: skip rebuilding the SDK from source in the bootstrap build. The SDK inner build fundamentally can't work with a bootstrap SDK targeting an unrecognized RID. Instead, the bootstrap build produces the runtime, ASP.NET Core, Roslyn compiler, MSBuild engine, and all infrastructure packages from source — but uses the Fedora bootstrap SDK's binaries for the SDK package itself. Once Mageia-built artifacts exist in the repository, subsequent non-bootstrap builds will compile the SDK from source correctly.
Wall 4: XLF localization processing
Every project with localizable strings processes 13 translation files (cs, de,
es, fr, it, ja, ko, pl, pt-BR, ru, tr, zh-Hans, zh-Hant) through resgen.exe.
For the SDK alone, that's over 650 resource processing steps, each taking
seconds. After 30 hours of build time, the output had barely advanced — the
build was spending more than 70% of its time running resgen.exe.
Fix: Set XlfLanguages= (empty string) to skip all XLF processing. For
a bootstrap build that runs once, losing 13 language localizations is an
acceptable tradeoff. The next build from Mageia artifacts can restore them.
The result: 13 binary RPMs
After resolving all the issues, the build produces 13 binary RPMs for Mageia 11:
| RPM | Source |
|---|---|
dotnet-host |
Source-built runtime |
dotnet-hostfxr-8.0 |
Source-built runtime |
dotnet-runtime-8.0 |
Source-built runtime |
dotnet-runtime-dbg-8.0 |
Source-built runtime |
aspnetcore-runtime-8.0 |
Source-built ASP.NET Core |
aspnetcore-runtime-dbg-8.0 |
Source-built ASP.NET Core |
dotnet-targeting-pack-8.0 |
Source-built runtime |
aspnetcore-targeting-pack-8.0 |
Source-built ASP.NET Core |
dotnet-apphost-pack-8.0 |
Source-built runtime |
dotnet-templates-8.0 |
Bootstrap SDK (Fedora) |
dotnet-sdk-8.0 |
Bootstrap SDK (Fedora) |
dotnet-sdk-dbg-8.0 |
Bootstrap SDK (Fedora) |
dotnet-sdk-8.0-source-built-artifacts |
All source-built packages |
The runtime, ASP.NET Core, Roslyn, and MSBuild are all compiled from source on Mageia. The SDK package itself is the only piece still coming from the Fedora bootstrap — and that changes with the next rebuild.
What I learned
- Fedora's packaging is an excellent upstream. Don't reinvent the wheel when a well-maintained spec already exists.
- Source-build is humbling. Twenty-eight repositories, each with their own build quirks. Patience and incremental debugging win the day.
- RID aliasing is the bootstrap's secret sauce. Every NuGet package and directory path that references the bootstrap SDK's RID needs an alias pointing to the target distribution's RID.
- Memory is the real constraint. .NET source-build wants 16+ GB. With 8 GB, aggressive limits are non-negotiable.
- XLF processing is the hidden tax. Disabling it saves over 70% of build time — and for a one-shot bootstrap, that's a tradeoff worth making.
What's next
The packages are ready, but the journey isn't over. Here's the roadmap:
- Bootstrap into Cauldron. Send the SRPM to Mageia's build system with
--with bootstrap, letiurtdo its thing, and verify the binary RPMs —dotnet --infomust report cleanly on a Mageia system. - Close the loop. If the bootstrap build succeeds, install the resulting
dotnet-sdk-8.0anddotnet-sdk-8.0-source-built-artifactspackages into the Cauldron repositories, then rebuild with--without bootstrap. This time the SDK compiles itself — natively, on Mageia, with no Fedora binaries in the loop. That's the real milestone. - Port .NET 10, then .NET 9. A bit of dogfooding: I work with the .NET stack every day across Windows and Linux, so having the latest tooling on Mageia matters. .NET 10 first — it's the current preview and where the ecosystem is heading — then backfill .NET 9 for broader LTS coverage.
The complete spec, patches, and build scripts are available in the Mageia packages repository.
Coming home
Coming back to Mageia after ten years feels familiar and new at the same time.
The tools have evolved — mgarepo, iurt, bm — but the community spirit is
the same one I left in 2016. Packaging is still the quiet, essential work that
makes a distribution tick. One package at a time, built from source, for everyone.
If you're a Mageia user who's been waiting for .NET, these packages are for you. And if you're a free software developer wondering whether packaging is worth the effort — it absolutely is. Because every package built from source, tested in the distribution's build system, and shipped through official repositories makes the free software ecosystem a little bit stronger.
It's good to be back.
Built with dotnet build and a lot of patience — running on Mageia Cauldron 11,
kernel 6.6, with 8 GB RAM and 20 virtual CPUs.