From 75ee239be7c904c912bfec9edca198f4ed2bf270 Mon Sep 17 00:00:00 2001 From: Christopher Wellons Date: Fri, 8 May 2026 14:24:52 -0400 Subject: [PATCH] Add NSIS 3.12 (makensis only) Adds a CLI-only NSIS install for compiling .nsi scripts. Skips the GUI wizards (makensisw, the NSIS installer creator) and documentation. Path-resolution problem: makensis at $PREFIX/bin/makensis.exe would auto-detect NSISDIR=$PREFIX (parent dir of bin), so NSIS would look for $PREFIX/{Include,Stubs,Plugins,...} -- collides with w64devkit's own $PREFIX/include on Windows's case-insensitive filesystem. Solve by installing the real makensis under $PREFIX/share/nsis/bin/, where auto-detection lands correctly on $PREFIX/share/nsis. A small alias EXE at $PREFIX/bin/makensis.exe (built from the existing alias.c) exec's it. Fully relocatable, no env vars. New stages: dl-nsis, build-nsis. SCons + python3 only inside build-nsis (not base) to avoid cache invalidation. TARGET_ARCH derived from $ARCH at build time so the same Dockerfile works for x64 and x86 -- no variant-x86.patch hunk needed. Co-Authored-By: Claude Opus 4.6 --- Dockerfile | 48 +++++++++++++++++- README.md | 2 + src/nsis-cross-makensis.patch | 96 +++++++++++++++++++++++++++++++++++ src/variant-x86.patch | 27 ++++++---- 4 files changed, 161 insertions(+), 12 deletions(-) create mode 100644 src/nsis-cross-makensis.patch diff --git a/Dockerfile b/Dockerfile index f04076f..b8aabaa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,8 @@ ARG PREFIX ENV PREFIX=$PREFIX RUN apt-get update && apt-get install --yes --no-install-recommends \ - build-essential cmake curl libgmp-dev libmpc-dev libmpfr-dev m4 p7zip-full + build-essential cmake curl libgmp-dev libmpc-dev libmpfr-dev m4 p7zip-full \ + python3 scons COPY src/w64devkit.ico src/alias.c $PREFIX/src/ @@ -213,6 +214,16 @@ RUN curl --insecure --location --remote-name-all --remote-header-name \ && mkdir aas-sign \ && tar xzf aas-sign-$AAS_SIGN_VERSION.tar.gz -C aas-sign --strip-components=1 +FROM base AS dl-nsis +ARG NSIS_VERSION=3.12 \ + NSIS_SHA256=f3ed7a8e4aa2cf4e8cf47d3b563a02559e0cb4934db2662b2f9661b824e2b186 +WORKDIR /dl +RUN curl --insecure --location --remote-name-all --remote-header-name \ + https://downloads.sourceforge.net/project/nsis/NSIS%203/$NSIS_VERSION/nsis-$NSIS_VERSION-src.tar.bz2 \ + && printf '%s %s\n' $NSIS_SHA256 nsis-$NSIS_VERSION-src.tar.bz2 | sha256sum -c \ + && mkdir nsis \ + && tar xjf nsis-$NSIS_VERSION-src.tar.bz2 -C nsis --strip-components=1 + # Build cross-compiler FROM dl-cross AS cross @@ -380,6 +391,14 @@ RUN /dl/mpc/configure \ && make -j$(nproc) \ && make install +WORKDIR /zlib +RUN /dl/binutils/zlib/configure \ + --host=$ARCH \ + CFLAGS="-O2" \ + && make -j$(nproc) libz.a \ + && cp libz.a /deps/lib/ \ + && cp /dl/binutils/zlib/zlib.h /dl/binutils/zlib/zconf.h /deps/include/ + WORKDIR /mingw-headers RUN /dl/mingw/mingw-w64-headers/configure \ --prefix=$PREFIX \ @@ -822,6 +841,28 @@ RUN cmake -B /aas-sign-build -S /dl/aas-sign -DCMAKE_BUILD_TYPE=Release \ && mkdir -p /out/usr/local/bin \ && cp /aas-sign-build/aas-sign /out/usr/local/bin/ +FROM cross AS build-nsis +COPY --from=dl-nsis /dl/nsis /dl/nsis +COPY src/nsis-*.patch $PREFIX/src/ +WORKDIR /dl/nsis +# Source/build.cpp ships with CRLF line endings; everything else in +# the tree is LF. Strip the carriage returns so our LF patch applies. +RUN sed -i 's/\r$//' Source/build.cpp \ + && cat $PREFIX/src/nsis-*.patch | patch -p1 \ + && scons -j$(nproc) \ + XGCC_W32_PREFIX=$ARCH- \ + TARGET_ARCH=amd64 \ + NSIS_CONFIG_CONST_DATA_PATH=no \ + PREFIX=$PREFIX \ + PREFIX_BIN=$PREFIX/share/nsis/bin \ + PREFIX_DATA=$PREFIX/share/nsis \ + PREFIX_DEST=/out \ + SKIPDOC=all \ + SKIPUTILS="NSIS Menu,Makensisw,VPatch/Source/GenPat,MakeLangId,zip2exe" \ + ZLIB_W32=/deps \ + install-compiler install-stubs install-includes install-plugins \ + install-contrib install-utils + # Collect source tarballs FROM base AS source COPY --from=dl-cross /dl/*.* /source/ @@ -837,6 +878,7 @@ COPY --from=dl-ninja /dl/*.* /source/ COPY --from=dl-cmake /dl/*.* /source/ COPY --from=dl-dcmake /dl/*.* /source/ COPY --from=dl-7z /dl/*.* /source/ +COPY --from=dl-nsis /dl/*.* /source/ # Pack up a release @@ -856,6 +898,7 @@ COPY --from=build-ninja /out/ $PREFIX/ COPY --from=build-dcmake /out/ $PREFIX/ COPY --from=build-cmake /out$PREFIX/ $PREFIX/ COPY --from=build-7z /dl/7z/7z.sfx /7z/ +COPY --from=build-nsis /out$PREFIX/ $PREFIX/ COPY src $PREFIX/src COPY etc $PREFIX/etc @@ -892,6 +935,9 @@ RUN printf "id ICON \"$PREFIX/src/w64devkit.ico\"" >w64devkit.rc \ && $ARCH-gcc -DEXE=pkg-config.exe -DCMD=pkg-config \ -Oz -fno-asynchronous-unwind-tables -Wl,--gc-sections -s -nostdlib \ -o $PREFIX/bin/$ARCH-pkg-config.exe $PREFIX/src/alias.c -lkernel32 \ + && $ARCH-gcc -DEXE=../share/nsis/bin/makensis.exe -DCMD=makensis \ + -Oz -fno-asynchronous-unwind-tables -Wl,--gc-sections -s -nostdlib \ + -o $PREFIX/bin/makensis.exe $PREFIX/src/alias.c -lkernel32 \ && sed -i s/'\'/$ARCH/g $PREFIX/etc/profile \ && mkdir -p $PREFIX/lib/pkgconfig \ && cp /dl/mingw/COPYING.MinGW-w64-runtime/COPYING.MinGW-w64-runtime.txt \ diff --git a/README.md b/README.md index 6ed43a8..e473d3a 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Included tools: * [Vim][vim] : powerful text editor * [Universal Ctags][ctags] : source navigation * [Ccache][ccache] : compiler cache +* [NSIS][nsis] : Windows installer compiler (`makensis`) It is an MSVCRT toolchain with pthreads, C++11 threads, and OpenMP. All included runtime components are static. **Docker is not required to use @@ -244,6 +245,7 @@ binaries. [make]: https://www.gnu.org/software/make/ [names]: https://learn.microsoft.com/en-us/cpp/build/reference/decorated-names [ninja]: https://ninja-build.org/ +[nsis]: https://nsis.sourceforge.io/ [san2]: https://groups.google.com/forum/#!topic/address-sanitizer/q0e5EBVKZT4 [san]: http://mingw-w64.org/doku.php/contribute#sanitizers_asan_tsan_usan [vim]: https://www.vim.org/ diff --git a/src/nsis-cross-makensis.patch b/src/nsis-cross-makensis.patch new file mode 100644 index 0000000..ba157fa --- /dev/null +++ b/src/nsis-cross-makensis.patch @@ -0,0 +1,96 @@ +Fix some NSIS bugs and add cross-compile support + +NSIS's SCons setup applies cross_env (the mingw cross-compile tool) to +stub_env, plugin_env, and util_env, but NOT to makensis_env. makensis is +built natively for the host (Linux) regardless of XGCC_W32_PREFIX. NSIS +users typically build makensis natively on Windows and cross-compile the +stubs/plugins/utilities when producing Windows installers from a Linux +build host. + +w64devkit ships a Windows toolchain, so we need a Windows makensis.exe +specifically. Apply cross_env(makensis_env) so makensis cross-compiles +too, pin makensis's C++ standard to gnu++14, unconditionally link the +version library, force the makensis zlib check onto its win32 branch, +accept a plain libz.a alongside the import-lib variants in ZLIB_W32 +lookup so makensis can static-link zlib like the rest of w64devkit, and +skip the Source/Tests SConscript. + +--- a/SCons/Config/gnu ++++ b/SCons/Config/gnu +@@ -122,6 +122,8 @@ + ### makensis environment + + makensis_env = tdefenv.Clone() ++cross_env(makensis_env) ++makensis_env.Append(CXXFLAGS = ['-std=gnu++14']) + + makensis_env.Append(CPPPATH = ['#$BUILD_CONFIG']) + +--- a/Source/build.cpp ++++ b/Source/build.cpp +@@ -3744,3 +3744,5 @@ + size_t io[] = { false, (size_t) path, pathcap }, cb; +- TinyGrowBuf inputbuf((IGrowBuf::size_type) (cb = FIELD_OFFSET(PROMPT_FILEPATH_DATA, Path[pathcap]))); ++ TinyGrowBuf inputbuf((IGrowBuf::size_type) (cb = ++ FIELD_OFFSET(PROMPT_FILEPATH_DATA, Path) ++ + pathcap * sizeof(((PROMPT_FILEPATH_DATA*)0)->Path[0]))); + PROMPT_FILEPATH_DATA *p = (PROMPT_FILEPATH_DATA*) inputbuf.get(); +@@ -4189,3 +4191,5 @@ + { +- postbuild_cmd *p = (postbuild_cmd*) (new BYTE[FIELD_OFFSET(postbuild_cmd, cmd[_tcsclen(cmdstr)+!0])]); ++ postbuild_cmd *p = (postbuild_cmd*) (new BYTE[ ++ FIELD_OFFSET(postbuild_cmd, cmd) ++ + (_tcsclen(cmdstr)+1) * sizeof(((postbuild_cmd*)0)->cmd[0])]); + p->next = NULL, _tcscpy(p->cmd, cmdstr); + +--- a/Source/SConscript ++++ b/Source/SConscript +@@ -65,12 +65,11 @@ + + ##### Use available libraries + +-if env['PLATFORM'] == 'win32': +- # XXX will cause problems if makensis is cross compiled +- # on freebsd, libversion.a exists and gives trouble if linked +- libs += ['version'] ++# w64devkit cross-compile: makensis is always built for Windows, so ++# always link the version library. ++libs += ['version'] + + AddAvailableLibs(env, libs) +-AddZLib(env, env['PLATFORM'], 'install-compiler') ++AddZLib(env, 'win32', 'install-compiler') + + ##### Defines + +--- a/SConstruct ++++ b/SConstruct +@@ -541,4 +541,4 @@ + )) + # Search for import library of zlib for mingw or VisualC +- for importlib in ['libzdll.a', 'libz.dll.a', 'zdll.lib']: ++ for importlib in ['libzdll.a', 'libz.dll.a', 'libz.a', 'zdll.lib']: + defenv['ZLIB_W32_LIB'] = os.path.dirname(str( +@@ -929,19 +929,12 @@ + ####### Tests ### + ###################################################################### + +-# test code ++# w64devkit cross-compile: tests removed. Source/Tests/SConscript ++# expects a host-runtime zlib that we don't supply, and we don't run ++# NSIS's self-tests anyway. + + build_dir = '$BUILD_PREFIX/tests' + exports = {'env' : test_env.Clone()} +- +-defenv.SConscript( +- dirs = 'Source/Tests', +- duplicate = False, +- exports = exports, +- variant_dir = build_dir +-) +- +-defenv.Ignore('$BUILD_PREFIX', '$BUILD_PREFIX/tests') + + # test scripts + diff --git a/src/variant-x86.patch b/src/variant-x86.patch index a3c0855..2558de9 100644 --- a/src/variant-x86.patch +++ b/src/variant-x86.patch @@ -1,55 +1,60 @@ --- a/Dockerfile +++ b/Dockerfile -@@ -208,3 +208,3 @@ +@@ -229,3 +229,3 @@ FROM dl-cross AS cross -ARG ARCH=x86_64-w64-mingw32 +ARG ARCH=i686-w64-mingw32 ENV ARCH=$ARCH -@@ -239,2 +239,3 @@ +@@ -260,2 +260,3 @@ --with-default-msvcrt=msvcrt-os \ + --with-default-win32-winnt=0x0501 \ && make -j$(nproc) \ -@@ -251,2 +252,3 @@ +@@ -272,2 +273,3 @@ --with-sysroot=/bootstrap \ + --with-arch=pentium4 \ --target=$ARCH \ -@@ -291,4 +293,4 @@ +@@ -313,4 +315,4 @@ --disable-dependency-tracking \ - --disable-lib32 \ - --enable-lib64 \ + --enable-lib32 \ + --disable-lib64 \ CFLAGS="-O2" \ -@@ -377,2 +379,3 @@ +@@ -399,2 +401,3 @@ --with-default-msvcrt=msvcrt-os \ + --with-default-win32-winnt=0x0501 \ && make -j$(nproc) \ -@@ -387,4 +390,4 @@ +@@ -409,4 +412,4 @@ --disable-dependency-tracking \ - --disable-lib32 \ - --enable-lib64 \ + --enable-lib32 \ + --disable-lib64 \ CFLAGS="-O2" \ -@@ -415,2 +418,3 @@ +@@ -437,2 +440,3 @@ --with-native-system-header-dir=/include \ + --with-arch=pentium4 \ --target=$ARCH \ -@@ -433,2 +437,3 @@ +@@ -456,2 +460,3 @@ --disable-win32-registry \ + --disable-win32-utf8-manifest \ --enable-mingw-wildcard \ -@@ -576,3 +581,3 @@ +@@ -605,3 +610,3 @@ RUN cat $PREFIX/src/busybox-*.patch | patch -p1 \ - && make mingw64u_defconfig \ + && make mingw64_defconfig \ && sed -ri 's/^(CONFIG_AR)=y/\1=n/' .config \ -@@ -666,3 +671,3 @@ +@@ -699,3 +704,3 @@ RUN make -j$(nproc) -C programs zstd \ - CC=$ARCH-gcc CFLAGS="-O2" LDFLAGS="-s" EXT=.exe \ + CC=$ARCH-gcc CFLAGS="-O2" LDFLAGS="-s" EXT=.exe HAVE_THREAD=0 \ && mkdir -p /out/bin \ -@@ -765,2 +771,3 @@ +@@ -798,2 +803,3 @@ -DCMAKE_EXE_LINKER_FLAGS="-s" \ + -DCMAKE_CXX_FLAGS="-O2 -D_WIN32_WINNT=0x0601" \ -DCMAKE_INSTALL_PREFIX=$PREFIX \ +@@ -840,3 +846,3 @@ + XGCC_W32_PREFIX=$ARCH- \ +- TARGET_ARCH=amd64 \ ++ TARGET_ARCH=x86 \ + PREFIX=$PREFIX \