From 2e424d7941dd712cbc49a496b5d77b97d2f189bc Mon Sep 17 00:00:00 2001 From: Peter0x44 Date: Sat, 29 Aug 2026 18:10:31 -0500 Subject: [PATCH] Replace variant arguments with build profiles Replace the loosely coordinated collection of x86 build arguments with a single VARIANT selector. Define x64, x86, and multilib configuration stages, then select the requested stage as the common cross-compiler base. This keeps each supported configuration closed and prevents callers from combining incompatible architecture settings. Make x64 the default standalone profile. It targets x86_64-w64-mingw32, disables GCC multilib support, builds only the 64-bit CRT, and omits the secondary 32-bit libraries and aliases. Keep the standalone x86 behavior in its own profile. It targets i686-w64-mingw32, retains the Pentium 4 default, enables only the 32-bit CRT, preserves the Windows XP header default and manifest behavior, selects the 32-bit BusyBox and NSIS configurations, disables zstd threading, and raises _WIN32_WINNT only while building CMake. CMake and its bundled curl require at least Windows Vista APIs, so the C and C++ flags continue to target Windows 7 without changing the XP-oriented default of the installed toolchain. Define multilib as an x86_64 compiler with GCC multilib enabled, both CRT library sets installed, and the existing i686 forwarding aliases. Use a dedicated EXTRA_32 setting for the secondary lib32 libraries, winpthreads builds, thread support object, and aliases instead of inferring that work from the spelling of a GCC configure option. Expose independent CRT_LIB32 and CRT_LIB64 settings so each profile selects exactly the runtime libraries it needs. Pass the profile's CMake C and C++ flags directly rather than building an optional argument list through shell positional parameters. Keep all other profile-specific values next to the selected base stage, including GCC architecture and manifest flags, BusyBox configuration, zstd options, and NSIS target architecture. Simplify multibuild.sh to pass only VARIANT to Docker. Add -m for the multilib flavor, make -a build all three profiles, and remove the old argument-file and Dockerfile-patch fallback paths. Update unsigned and signed CI builds to select x64 or x86 directly, remove the obsolete variant-x86.args bundle, and document the new build interface. Verify all three profiles with docker build --check and complete cross toolchain builds. Smoke-test x64 and x86 compilation, plus both the 64-bit compiler and i686 alias in the multilib profile. Also build the x64 and x86 CMake targets to exercise both the empty and Windows 7 CMake flag configurations. --- .github/workflows/build.yml | 24 ++-------- Dockerfile | 91 +++++++++++++++++++++++-------------- README.md | 8 ++++ multibuild.sh | 36 +++++---------- src/variant-x86.args | 10 ---- 5 files changed, 80 insertions(+), 89 deletions(-) delete mode 100644 src/variant-x86.args diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b51f990..6cddf41 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,6 +40,7 @@ jobs: uses: docker/build-push-action@v7 with: context: . + build-args: VARIANT=x64 tags: w64devkit:${{ env.ARCH }} load: true cache-from: type=gha,scope=w64devkit-${{ env.ARCH }} @@ -97,15 +98,6 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - - name: Load x86 build args - id: variant - run: | - { - echo 'args<> "$GITHUB_OUTPUT" - - name: Generate archive name and version string id: filename run: | @@ -118,7 +110,7 @@ jobs: uses: docker/build-push-action@v7 with: context: . - build-args: ${{ steps.variant.outputs.args }} + build-args: VARIANT=x86 tags: w64devkit:${{ env.ARCH }} load: true cache-from: type=gha,scope=w64devkit-${{ env.ARCH }} @@ -166,6 +158,7 @@ jobs: uses: docker/build-push-action@v7 with: context: . + build-args: VARIANT=x64 target: signed tags: w64devkit:x64-signed load: true @@ -182,20 +175,11 @@ jobs: > w64devkit-x64-${{ steps.filename.outputs.version }}.7z.exe ls -lh w64devkit-x64-${{ steps.filename.outputs.version }}.7z.exe - - name: Load x86 build args - id: variant - run: | - { - echo 'args<> "$GITHUB_OUTPUT" - - name: Build signed image (x86) uses: docker/build-push-action@v7 with: context: . - build-args: ${{ steps.variant.outputs.args }} + build-args: VARIANT=x86 target: signed tags: w64devkit:x86-signed load: true diff --git a/Dockerfile b/Dockerfile index 6a743ca..61af5e9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,6 @@ ARG VERSION=2.9.1 \ PREFIX=/w64devkit +ARG VARIANT=x64 FROM debian:trixie-slim AS base ARG PREFIX @@ -207,30 +208,52 @@ RUN mkdir nsis \ # Build cross-compiler -FROM dl-cross AS cross +FROM dl-cross AS variant-x64 +ENV ARCH=x86_64-w64-mingw32 \ + ARCH_FLAGS="" \ + MULTILIB=--disable-multilib \ + CRT_LIB32=--disable-lib32 \ + CRT_LIB64=--enable-lib64 \ + WINNT_FLAGS="" \ + MANIFEST_FLAGS="" \ + EXTRA_32=0 \ + BUSYBOX_CONFIG=mingw64u_defconfig \ + ZSTD_FLAGS="" \ + CMAKE_C_FLAGS="" \ + CMAKE_CXX_FLAGS="" \ + NSIS_ARCH=amd64 -# Variant configuration. The defaults produce the x64 kit, and a variant -# is a coherent set of overrides (see src/variant-x86.args). Stages -# before this point are shared between variants. -ARG ARCH=x86_64-w64-mingw32 -ARG MULTILIB=--enable-multilib -ARG ARCH_FLAGS=--with-arch-32=pentium4 -# Not named "LIB64": mingw-w64-crt's configure tests whether a shell -# variable LIB64 (or LIB32) is set, and ARGs leak into the environment -# of every RUN, which would force the Win64 runtime on regardless of -# the --{enable,disable}-lib64 flag. -ARG CRT_LIB64=--enable-lib64 -ARG WINNT_FLAGS= -ARG MANIFEST_FLAGS= -ARG BUSYBOX_CONFIG=mingw64u_defconfig -ARG ZSTD_FLAGS= -ARG CMAKE_WINNT= -ARG NSIS_ARCH=amd64 -ENV ARCH=$ARCH \ - BUSYBOX_CONFIG=$BUSYBOX_CONFIG \ - ZSTD_FLAGS=$ZSTD_FLAGS \ - CMAKE_WINNT=$CMAKE_WINNT \ - NSIS_ARCH=$NSIS_ARCH +FROM dl-cross AS variant-x86 +ENV ARCH=i686-w64-mingw32 \ + ARCH_FLAGS=--with-arch=pentium4 \ + MULTILIB=--disable-multilib \ + CRT_LIB32=--enable-lib32 \ + CRT_LIB64=--disable-lib64 \ + WINNT_FLAGS=--with-default-win32-winnt=0x0501 \ + MANIFEST_FLAGS=--disable-win32-utf8-manifest \ + EXTRA_32=0 \ + BUSYBOX_CONFIG=mingw32w_defconfig \ + ZSTD_FLAGS=HAVE_THREAD=0 \ + CMAKE_C_FLAGS="-O2 -D_WIN32_WINNT=0x0601" \ + CMAKE_CXX_FLAGS="-O2 -D_WIN32_WINNT=0x0601" \ + NSIS_ARCH=x86 + +FROM dl-cross AS variant-multilib +ENV ARCH=x86_64-w64-mingw32 \ + ARCH_FLAGS=--with-arch-32=pentium4 \ + MULTILIB=--enable-multilib \ + CRT_LIB32=--enable-lib32 \ + CRT_LIB64=--enable-lib64 \ + WINNT_FLAGS="" \ + MANIFEST_FLAGS="" \ + EXTRA_32=1 \ + BUSYBOX_CONFIG=mingw64u_defconfig \ + ZSTD_FLAGS="" \ + CMAKE_C_FLAGS="" \ + CMAKE_CXX_FLAGS="" \ + NSIS_ARCH=amd64 + +FROM variant-${VARIANT} AS cross WORKDIR /dl/binutils COPY src/binutils-*.patch $PREFIX/src/ @@ -309,7 +332,7 @@ RUN mkdir -p $PREFIX/lib \ && CC=$ARCH-gcc AR=$ARCH-ar DESTDIR=$PREFIX/lib/ \ sh $PREFIX/src/libchkstk.S \ && ln $PREFIX/lib/libchkstk.a /bootstrap/lib/ \ - && if [ "$MULTILIB" = --enable-multilib ]; then \ + && if [ "$EXTRA_32" = 1 ]; then \ mkdir -p $PREFIX/lib32 /bootstrap/lib32 \ && CC="$ARCH-gcc -m32" AR=$ARCH-ar DESTDIR=$PREFIX/lib32/ \ sh $PREFIX/src/libmemory.c \ @@ -326,7 +349,7 @@ RUN /dl/mingw/mingw-w64-crt/configure \ --host=$ARCH \ --with-default-msvcrt=msvcrt-os \ --disable-dependency-tracking \ - --enable-lib32 \ + $CRT_LIB32 \ $CRT_LIB64 \ CFLAGS="-O2" \ LDFLAGS="-s" \ @@ -346,7 +369,7 @@ RUN /dl/mingw/mingw-w64-libraries/winpthreads/configure \ && make install WORKDIR /x-winpthreads32 -RUN if [ "$MULTILIB" = --enable-multilib ]; then \ +RUN if [ "$EXTRA_32" = 1 ]; then \ /dl/mingw/mingw-w64-libraries/winpthreads/configure \ --prefix=/bootstrap \ --libdir=/bootstrap/lib32 \ @@ -447,7 +470,7 @@ RUN /dl/mingw/mingw-w64-crt/configure \ --host=$ARCH \ --with-default-msvcrt=msvcrt-os \ --disable-dependency-tracking \ - --enable-lib32 \ + $CRT_LIB32 \ $CRT_LIB64 \ CFLAGS="-O2" \ LDFLAGS="-s" \ @@ -459,7 +482,7 @@ COPY src/threads.h $PREFIX/include/ RUN $ARCH-gcc -c -Oz -I$PREFIX/include/ \ -ffunction-sections -Wa,--no-pad-sections $PREFIX/src/threads.c \ && $ARCH-ar r $PREFIX/lib/libmingwex.a threads.o \ - && if [ "$MULTILIB" = --enable-multilib ]; then \ + && if [ "$EXTRA_32" = 1 ]; then \ $ARCH-gcc -m32 -c -Oz -I$PREFIX/include/ \ -ffunction-sections -Wa,--no-pad-sections \ -o threads32.o $PREFIX/src/threads.c \ @@ -479,7 +502,7 @@ RUN /dl/mingw/mingw-w64-libraries/winpthreads/configure \ && make install WORKDIR /winpthreads32 -RUN if [ "$MULTILIB" = --enable-multilib ]; then \ +RUN if [ "$EXTRA_32" = 1 ]; then \ /dl/mingw/mingw-w64-libraries/winpthreads/configure \ --prefix=$PREFIX \ --libdir=$PREFIX/lib32 \ @@ -559,7 +582,7 @@ RUN $ARCH-gcc -DEXE=gcc.exe -DCMD=cc \ -o $PREFIX/bin/$ARCH-{}.exe $PREFIX/src/alias.c -lkernel32 # Create i686 tool aliases -RUN if [ "$MULTILIB" = --enable-multilib ]; then \ +RUN if [ "$EXTRA_32" = 1 ]; then \ printf '%s\n' addr2line ar c++filt gcc-ar gcc-nm gcc-ranlib gcov \ gcov-dump gcov-tool gendef nm objcopy objdump ranlib size strings \ strip uuidgen windmc \ @@ -904,11 +927,9 @@ COPY --from=build-pdcurses /deps/include/curses.h /deps/include/ WORKDIR /cmake COPY src/cmake-*.patch $PREFIX/src/ RUN cat $PREFIX/src/cmake-*.patch | patch -d/dl/cmake -p1 \ - && if [ -n "$CMAKE_WINNT" ]; then \ - set -- -DCMAKE_C_FLAGS="-O2 -D_WIN32_WINNT=$CMAKE_WINNT" \ - -DCMAKE_CXX_FLAGS="-O2 -D_WIN32_WINNT=$CMAKE_WINNT" ; \ - fi \ - && cmake "$@" -DCMAKE_BUILD_TYPE=Release \ + && cmake -DCMAKE_C_FLAGS="$CMAKE_C_FLAGS" \ + -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS" \ + -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_SYSTEM_NAME=Windows \ -DCMAKE_C_COMPILER=$ARCH-gcc \ -DCMAKE_CXX_COMPILER=$ARCH-g++ \ diff --git a/README.md b/README.md index 46d1c39..d3a8fa4 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,14 @@ Build the image, then run it to produce a self-extracting 7z archive: docker build -t w64devkit . docker run --rm w64devkit >w64devkit-x64.exe +The default variant is `x64`. Select a standalone x86 or combined multilib +toolchain with a build argument: + + docker build --build-arg VARIANT=x86 -t w64devkit . + docker build --build-arg VARIANT=multilib -t w64devkit . + +`multibuild.sh -a` builds all three variants. + This takes about 15 minutes on modern systems. You will need an internet connection during the first few minutes of the build. **Note:** Do not use PowerShell because it lacks file redirection. diff --git a/multibuild.sh b/multibuild.sh index 8232859..953dab9 100755 --- a/multibuild.sh +++ b/multibuild.sh @@ -8,27 +8,29 @@ # $ ./multibuild.sh -as "$(git describe | tr v -)" set -e -arch= +variants= dryrun= suffix="$(git describe --exact-match 2>/dev/null | tr v - || true)" usage() { cat </dev/null || true } trap cleanup EXIT -for variant in $arch; do - if [ -e "src/variant-$variant.args" ]; then - $dryrun docker build \ - $(sed 's/^/--build-arg /' "src/variant-$variant.args") \ - -t $target . - elif [ -e "src/variant-$variant.patch" ]; then - tmp=$(mktemp -d) - $dryrun cp Dockerfile "$tmp/" - $dryrun patch "$tmp/Dockerfile" "src/variant-$variant.patch" - $dryrun docker build -f "$tmp/Dockerfile" -t $target . - rm -rf -- "$tmp" - else - $dryrun docker build -t $target . - fi +for variant in $variants; do + $dryrun docker build --build-arg VARIANT=$variant -t $target . out="w64devkit-$variant$suffix.7z.exe" if [ -n "$dryrun" ]; then $dryrun docker run --rm $target ">$out" diff --git a/src/variant-x86.args b/src/variant-x86.args deleted file mode 100644 index 06ad08c..0000000 --- a/src/variant-x86.args +++ /dev/null @@ -1,10 +0,0 @@ -ARCH=i686-w64-mingw32 -MULTILIB=--disable-multilib -ARCH_FLAGS=--with-arch=pentium4 -CRT_LIB64=--disable-lib64 -WINNT_FLAGS=--with-default-win32-winnt=0x0501 -MANIFEST_FLAGS=--disable-win32-utf8-manifest -BUSYBOX_CONFIG=mingw32w_defconfig -ZSTD_FLAGS=HAVE_THREAD=0 -CMAKE_WINNT=0x0601 -NSIS_ARCH=x86