From bf2780ced75501e9f3d4120d37f7cf0718e101f9 Mon Sep 17 00:00:00 2001 From: Peter0x44 Date: Sun, 9 Aug 2026 16:05:29 -0500 Subject: [PATCH 1/2] Add x86 multilib toolchain support Keep x86_64 as the default output while enabling the GCC and mingw-w64 32-bit multilib under lib32. Build 32-bit support archives, CRT libraries, and winpthreads for both the bootstrap and final sysroots so each compiler stage has a complete i686 runtime. Use pentium4 as the 32-bit architecture baseline. Add a GCC specs rule that defaults _WIN32_WINNT to 0x0501 only under -m32 and only when the caller has not supplied a value, preserving the existing x64 default and explicit overrides. Retain the x86_64-w64-mingw32-prefixed tools and add a separate build step for an i686-w64-mingw32 interface. Compiler drivers inject -m32. Target-sensitive binutils select their 32-bit modes explicitly: as uses --32, ld uses -m i386pe, dlltool uses -m i386 with --as-flags=--32, and windres uses --target=pe-i386. Input-driven inspection and archive tools forward without a target override. These forwarding executables provide both prefixed interfaces without duplicating a second binutils installation. They deliberately remain selectors for the underlying x86_64-configured multilib compiler rather than spoofing its configured target identity. Direct, Autoconf, CMake, and Libtool probes using the i686-prefixed interface all produced PE-i386 output. --- Dockerfile | 98 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 89 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 391f9b4..c7d1181 100644 --- a/Dockerfile +++ b/Dockerfile @@ -272,6 +272,8 @@ RUN cat $PREFIX/src/gcc-*.patch | patch -d/dl/gcc -p1 \ && /dl/gcc/configure \ --prefix=/bootstrap \ --with-sysroot=/bootstrap \ + --with-arch-32=pentium4 \ + "--with-specs=%{m32:%{!D_WIN32_WINNT*:-D_WIN32_WINNT=0x0501}}" \ --target=$ARCH \ --enable-static \ --disable-shared \ @@ -285,7 +287,6 @@ RUN cat $PREFIX/src/gcc-*.patch | patch -d/dl/gcc -p1 \ --disable-dependency-tracking \ --disable-nls \ --disable-lto \ - --disable-multilib \ CFLAGS_FOR_TARGET="-O2" \ CXXFLAGS_FOR_TARGET="-O2" \ LDFLAGS_FOR_TARGET="-s" \ @@ -298,13 +299,19 @@ RUN cat $PREFIX/src/gcc-*.patch | patch -d/dl/gcc -p1 \ ENV PATH="/bootstrap/bin:${PATH}" COPY src/libmemory.c src/libchkstk.S $PREFIX/src/ -RUN mkdir -p $PREFIX/lib \ +RUN mkdir -p $PREFIX/lib $PREFIX/lib32 /bootstrap/lib32 \ && CC=$ARCH-gcc AR=$ARCH-ar DESTDIR=$PREFIX/lib/ \ sh $PREFIX/src/libmemory.c \ && ln $PREFIX/lib/libmemory.a /bootstrap/lib/ \ && CC=$ARCH-gcc AR=$ARCH-ar DESTDIR=$PREFIX/lib/ \ sh $PREFIX/src/libchkstk.S \ - && ln $PREFIX/lib/libchkstk.a /bootstrap/lib/ + && ln $PREFIX/lib/libchkstk.a /bootstrap/lib/ \ + && CC="$ARCH-gcc -m32" AR=$ARCH-ar DESTDIR=$PREFIX/lib32/ \ + sh $PREFIX/src/libmemory.c \ + && ln $PREFIX/lib32/libmemory.a /bootstrap/lib32/ \ + && CC="$ARCH-gcc -m32" AR=$ARCH-ar DESTDIR=$PREFIX/lib32/ \ + sh $PREFIX/src/libchkstk.S \ + && ln $PREFIX/lib32/libchkstk.a /bootstrap/lib32/ WORKDIR /x-mingw-crt RUN /dl/mingw/mingw-w64-crt/configure \ @@ -313,7 +320,7 @@ RUN /dl/mingw/mingw-w64-crt/configure \ --host=$ARCH \ --with-default-msvcrt=msvcrt-os \ --disable-dependency-tracking \ - --disable-lib32 \ + --enable-lib32 \ --enable-lib64 \ CFLAGS="-O2" \ LDFLAGS="-s" \ @@ -332,6 +339,20 @@ RUN /dl/mingw/mingw-w64-libraries/winpthreads/configure \ && make -j$(nproc) \ && make install +WORKDIR /x-winpthreads32 +RUN /dl/mingw/mingw-w64-libraries/winpthreads/configure \ + --prefix=/bootstrap \ + --libdir=/bootstrap/lib32 \ + --with-sysroot=/bootstrap \ + --host=$ARCH \ + --enable-static \ + --disable-shared \ + CC="$ARCH-gcc -m32" \ + CFLAGS="-O2" \ + LDFLAGS="-s" \ + && make -j$(nproc) \ + && make install + WORKDIR /x-gcc RUN make -j$(nproc) \ && make install @@ -417,7 +438,7 @@ RUN /dl/mingw/mingw-w64-crt/configure \ --host=$ARCH \ --with-default-msvcrt=msvcrt-os \ --disable-dependency-tracking \ - --disable-lib32 \ + --enable-lib32 \ --enable-lib64 \ CFLAGS="-O2" \ LDFLAGS="-s" \ @@ -428,7 +449,11 @@ COPY src/threads.c $PREFIX/src/ 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 + && $ARCH-ar r $PREFIX/lib/libmingwex.a threads.o \ + && $ARCH-gcc -m32 -c -Oz -I$PREFIX/include/ \ + -ffunction-sections -Wa,--no-pad-sections \ + -o threads32.o $PREFIX/src/threads.c \ + && $ARCH-ar r $PREFIX/lib32/libmingwex.a threads32.o WORKDIR /winpthreads RUN /dl/mingw/mingw-w64-libraries/winpthreads/configure \ @@ -442,6 +467,20 @@ RUN /dl/mingw/mingw-w64-libraries/winpthreads/configure \ && make -j$(nproc) \ && make install +WORKDIR /winpthreads32 +RUN /dl/mingw/mingw-w64-libraries/winpthreads/configure \ + --prefix=$PREFIX \ + --libdir=$PREFIX/lib32 \ + --with-sysroot=$PREFIX \ + --host=$ARCH \ + --enable-static \ + --disable-shared \ + CC="$ARCH-gcc -m32" \ + CFLAGS="-O2" \ + LDFLAGS="-s" \ + && make -j$(nproc) \ + && make install + WORKDIR /gcc COPY src/crossgcc-*.patch $PREFIX/src/ RUN cat $PREFIX/src/crossgcc-*.patch | patch -d/dl/gcc -p1 \ @@ -449,6 +488,8 @@ RUN cat $PREFIX/src/crossgcc-*.patch | patch -d/dl/gcc -p1 \ --prefix=$PREFIX \ --with-sysroot=$PREFIX \ --with-native-system-header-dir=/include \ + --with-arch-32=pentium4 \ + "--with-specs=%{m32:%{!D_WIN32_WINNT*:-D_WIN32_WINNT=0x0501}}" \ --target=$ARCH \ --host=$ARCH \ --enable-static \ @@ -465,7 +506,6 @@ RUN cat $PREFIX/src/crossgcc-*.patch | patch -d/dl/gcc -p1 \ --disable-libstdcxx-verbose \ --disable-dependency-tracking \ --disable-lto \ - --disable-multilib \ --disable-nls \ --disable-win32-registry \ --enable-mingw-wildcard \ @@ -494,9 +534,9 @@ RUN $ARCH-gcc -DEXE=gcc.exe -DCMD=cc \ && $ARCH-gcc -DEXE=gcc.exe -DCMD="cc -ansi" \ -Oz -fno-asynchronous-unwind-tables -Wl,--gc-sections -s -nostdlib \ -o $PREFIX/bin/c89.exe $PREFIX/src/alias.c -lkernel32 \ - && printf '%s\n' addr2line ar as c++filt cpp dlltool dllwrap elfedit g++ \ + && printf '%s\n' addr2line ar as c++filt cpp dlltool dllwrap g++ \ gcc gcc-ar gcc-nm gcc-ranlib gcov gcov-dump gcov-tool gendef gfortran \ - ld nm objcopy objdump ranlib readelf size strings strip uuidgen widl \ + ld nm objcopy objdump ranlib size strings strip uuidgen widl \ windmc windres \ | xargs -I{} -P$(nproc) \ $ARCH-gcc -DEXE={}.exe -DCMD=$ARCH-{} \ @@ -504,6 +544,46 @@ RUN $ARCH-gcc -DEXE=gcc.exe -DCMD=cc \ -Wl,--gc-sections -s -nostdlib \ -o $PREFIX/bin/$ARCH-{}.exe $PREFIX/src/alias.c -lkernel32 +# Create i686 tool aliases +RUN 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 widl windmc \ + | xargs -I{} -P$(nproc) \ + $ARCH-gcc -DEXE={}.exe -DCMD=i686-w64-mingw32-{} \ + -Oz -fno-asynchronous-unwind-tables \ + -Wl,--gc-sections -s -nostdlib \ + -o $PREFIX/bin/i686-w64-mingw32-{}.exe \ + $PREFIX/src/alias.c -lkernel32 \ + && printf '%s\n' cpp gcc g++ gfortran \ + | xargs -I{} -P$(nproc) \ + $ARCH-gcc -DEXE={}.exe -DCMD="i686-w64-mingw32-{} -m32" \ + -Oz -fno-asynchronous-unwind-tables \ + -Wl,--gc-sections -s -nostdlib \ + -o $PREFIX/bin/i686-w64-mingw32-{}.exe \ + $PREFIX/src/alias.c -lkernel32 \ + && $ARCH-gcc -DEXE=g++.exe -DCMD="i686-w64-mingw32-c++ -m32" \ + -Oz -fno-asynchronous-unwind-tables -Wl,--gc-sections -s -nostdlib \ + -o $PREFIX/bin/i686-w64-mingw32-c++.exe \ + $PREFIX/src/alias.c -lkernel32 \ + && $ARCH-gcc -DEXE=as.exe -DCMD="i686-w64-mingw32-as --32" \ + -Oz -fno-asynchronous-unwind-tables -Wl,--gc-sections -s -nostdlib \ + -o $PREFIX/bin/i686-w64-mingw32-as.exe \ + $PREFIX/src/alias.c -lkernel32 \ + && $ARCH-gcc -DEXE=ld.exe -DCMD="i686-w64-mingw32-ld -m i386pe" \ + -Oz -fno-asynchronous-unwind-tables -Wl,--gc-sections -s -nostdlib \ + -o $PREFIX/bin/i686-w64-mingw32-ld.exe \ + $PREFIX/src/alias.c -lkernel32 \ + && $ARCH-gcc -DEXE=dlltool.exe \ + -DCMD="i686-w64-mingw32-dlltool -m i386 --as-flags=--32" \ + -Oz -fno-asynchronous-unwind-tables -Wl,--gc-sections -s -nostdlib \ + -o $PREFIX/bin/i686-w64-mingw32-dlltool.exe \ + $PREFIX/src/alias.c -lkernel32 \ + && $ARCH-gcc -DEXE=windres.exe \ + -DCMD="i686-w64-mingw32-windres --target=pe-i386" \ + -Oz -fno-asynchronous-unwind-tables -Wl,--gc-sections -s -nostdlib \ + -o $PREFIX/bin/i686-w64-mingw32-windres.exe \ + $PREFIX/src/alias.c -lkernel32 + # Build some extra development tools FROM cross AS build-gendef From a70f4913c2c030a86bae1aa82c06d3145e625465 Mon Sep 17 00:00:00 2001 From: Peter0x44 Date: Sun, 9 Aug 2026 18:56:42 -0500 Subject: [PATCH 2/2] Default x86 Windows target version in headers --- Dockerfile | 2 -- src/mingw-default-win32-winnt.patch | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 src/mingw-default-win32-winnt.patch diff --git a/Dockerfile b/Dockerfile index c7d1181..b6efd3b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -273,7 +273,6 @@ RUN cat $PREFIX/src/gcc-*.patch | patch -d/dl/gcc -p1 \ --prefix=/bootstrap \ --with-sysroot=/bootstrap \ --with-arch-32=pentium4 \ - "--with-specs=%{m32:%{!D_WIN32_WINNT*:-D_WIN32_WINNT=0x0501}}" \ --target=$ARCH \ --enable-static \ --disable-shared \ @@ -489,7 +488,6 @@ RUN cat $PREFIX/src/crossgcc-*.patch | patch -d/dl/gcc -p1 \ --with-sysroot=$PREFIX \ --with-native-system-header-dir=/include \ --with-arch-32=pentium4 \ - "--with-specs=%{m32:%{!D_WIN32_WINNT*:-D_WIN32_WINNT=0x0501}}" \ --target=$ARCH \ --host=$ARCH \ --enable-static \ diff --git a/src/mingw-default-win32-winnt.patch b/src/mingw-default-win32-winnt.patch new file mode 100644 index 0000000..eb75943 --- /dev/null +++ b/src/mingw-default-win32-winnt.patch @@ -0,0 +1,19 @@ +headers: default 32-bit x86 to Windows XP + +The x86_64 multilib toolchain shares one header tree between its 64-bit +and 32-bit targets. Keep the configured mingw-w64 default for x86_64 and +other architectures, but preserve w64devkit's Windows XP default when +the compiler targets i686. An explicit user definition still takes +precedence through the existing outer guard. + +--- a/mingw-w64-headers/crt/_mingw.h.in ++++ b/mingw-w64-headers/crt/_mingw.h.in +@@ -255,3 +255,7 @@ + #ifndef _WIN32_WINNT +-#define _WIN32_WINNT @DEFAULT_WIN32_WINNT@ ++# if defined(__i386__) ++# define _WIN32_WINNT 0x0501 ++# else ++# define _WIN32_WINNT @DEFAULT_WIN32_WINNT@ ++# endif + #endif