Skip to content

Compile and pack on images chosen for the job - #13

Open
henrikottesorensen wants to merge 1 commit into
Notalib:mainfrom
henrikottesorensen:build/llvm-mingw-image
Open

Compile and pack on images chosen for the job#13
henrikottesorensen wants to merge 1 commit into
Notalib:mainfrom
henrikottesorensen:build/llvm-mingw-image

Conversation

@henrikottesorensen

Copy link
Copy Markdown
Collaborator

dotnet appears exactly once in the native build, at build/common.sh:94, to pack an already-compiled binary into a .nupkg. Everything else is gcc and clang. Building C on a dotnet/sdk image therefore meant apt-getting a toolchain onto an image picked for something else, and pulling in packages the build never uses — which is how a 404 on linux-libc-dev, a dependency of build-essential, failed CI on #6.

Stage Image Installs
gcc-build ubuntu:noble the cross toolchains
llvm-build mstorsjo/llvm-mingw:20260616 nothing
pack dotnet/sdk:10.0-noble nothing

The base stage is gone. build-essential now comes from an image chosen for compiling, and the SDK image does dotnet pack and nothing else.

win-arm64 comes from the toolchain author's own image

Ubuntu ships no aarch64 mingw-w64 gcc, so this target used a hand-downloaded, SHA-256 pinned llvm-mingw tarball. It now uses the image its own author publishes, pinned to the same dated release. That image already carries make, m4, curl and the toolchain on PATH, so the stage installs nothing, and it removes an 82 MB download from every uncached build plus a pair of values that had to be bumped together.

Keeping it a separate stage from the gcc targets remains load bearing: llvm-mingw also ships i686-w64-mingw32-gcc and x86_64-w64-mingw32-gcc, and having those on PATH alongside the Ubuntu cross compilers silently takes over win-x86 and win-x64. That is not hypothetical — it happened, and it broke win-x86.

Splitting compile from pack

The toolchain images have no SDK, so SKIP_PACK=1 leaves binaries staged and a later stage packs them. build/pack_runtime_packages.sh packs whatever is staged rather than a list kept beside it, so it cannot fall out of step with the RIDs the build stages actually produce. Finding nothing staged is an error — a stage that copied no binaries would otherwise produce an empty package set and look like a success.

Two smaller things

The pack stage moves to the .NET 10 SDK. Which SDK does the packing barely affects the output — these are netstandard2.0 metadata around an already-compiled binary, with IncludeBuildOutput off — but .NET 8 goes out of support in November 2026. This is the change that was dropped from #7, which is now purely multi-targeting.

The Dockerfile is excluded from the build context. It is not needed inside any image, and excluding it means editing the build definition no longer invalidates every COPY . /source and forces a full recompile of all six targets. I hit that while developing this: changing only the final stage's base image triggered a complete rebuild.

Verified

All six RIDs build, and all pass the binary verification from #6 unchanged — same architectures, same 18 exported P/Invoke symbols, same dependency allowlists, same glibc floor. Packed 6 runtime package(s) confirms the discovery found exactly what the toolchain stages staged.

Note on #6

#6's verification runs inside pack_runtime_package, which now executes in the SDK stage — and that stage deliberately installs nothing, so it has no readelf, nm or llvm-readobj. Whichever of these merges second needs to resolve that. The better resolution is moving verification into the toolchain stages, where those tools already exist, so a binary is checked where it was made rather than after crossing a stage boundary.

🤖 Generated with Claude Code

dotnet appears exactly once in the native build, to pack an
already-compiled binary into a .nupkg. Everything else is gcc and clang.
Building C on a dotnet/sdk image therefore meant apt-getting a toolchain
onto an image picked for something else, and pulling in packages the
build never uses - which is how a 404 on linux-libc-dev, a dependency of
build-essential, once failed CI.

Now:

  gcc-build    ubuntu:noble             installs the cross toolchains
  llvm-build   mstorsjo/llvm-mingw      installs nothing
  pack         dotnet/sdk:10.0-noble    installs nothing

win-arm64 comes from the image llvm-mingw's own author publishes, pinned
to a dated release, rather than downloading and checksumming the tarball
by hand. That image already has make, m4, curl and the toolchain on PATH,
so it needs no apt at all, and it removes an 82MB download from every
uncached build along with a pair of values that had to be bumped
together.

The toolchain images have no SDK, so compiling and packing had to split:
SKIP_PACK leaves binaries staged, and pack_runtime_packages.sh packs
whatever is staged rather than a list kept alongside it, which cannot
then fall out of step with the RIDs the build stages produce. Finding
nothing staged is an error, since a stage that copied no binaries would
otherwise look like a success.

The pack stage moves to the .NET 10 SDK. Which SDK does the packing
barely affects the output - netstandard2.0 metadata around an
already-compiled binary - but .NET 8 goes out of support in November
2026.

The Dockerfile is excluded from the build context. It is not needed
inside any image, and excluding it means editing the build definition no
longer invalidates every COPY . /source and forces a full recompile.

All six RIDs build and verify unchanged.

Co-Authored-By: Claude Opus 5 <[email protected]>
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.

2 participants