Sword Windows Cross Build 20241018

TL;DR Just let me download it

I have been trying to come up with a good, reliable way to build executables for Windows from Linux for a long time. One of the longer running problems I have had is that the ground keeps shifting out from under me. Sometimes, you’ve got exactly the set of requirements that you need, and that’s all you want! But, when I have previously used things like the MinGW toolchain from Fedora - I would have had to freeze the exact machine I was building on in order to be able to reproduce the same results as before. But, of course, this is not a feasible thing to do, especially for an open source project that is leveraging CI.

Of course, Nix came along and has largely solved the problem of pinning an entire system of libraries, executables, and compilers. But I had never dived into how to use its pinning power to create a cross compile result. Well, it turns out that it was simpler than I had thought. So I went about compiling my favorite cross-build library for Windows from my Linux host. That library it The SWORD Project, available in NixPkgs as just the package name “sword”.

To build Sword for Linux hosts, all you need to do is go to a Linux machine with Nix already installed (I use NixOS, but it can be installed on basically any distribution of Linux) and invoke the command: nix build "nixpkgs#sword. Provided you have nixpkgs setup as a flake and you have the nix command and flakes enabled (these are pretty common options on systems), you will end up with a symlink in your current directory named result. You can then run any of the tools from SWORD by invoking them like anything else you would call. ./result/bin/diatheke, for instance, gives you the diatheke command from SWORD.

But how do you cross compile it? Well, that is already thought out for you! You just need to invoke nix build "nixpkgs#pkgsCross.mingwW64.sword. pkgsCross has quite a few targets available to you. mingwW64 is the one that corresponds to Windows for x86_64 architectures. It also has an older target for 32-bit Windows machines, as well as other targets for building. If you are interested, trying using nix repl to eplore:

nix repl
>>> :lf nixpkgs
>>> legacyPackages.x86_64-linux.pkgsCross

BUT….

Was it relaly that simple to build SWORD binaries for Windows from my NixOS machine the first time? Of course not. The SWORD package is tagged as only supporting Unix-based or adjacent systems. So I could have compiled for BSDs, Linux on ARM, PPC, RISC-V, and more. But I got an error message the first time I tried to build for Windows, that looked something like this:

error:
       … in the condition of the assert statement

         at /nix/store/lryfc8mhk1czqsa421di2y5nzz5c3b8m-source/lib/customisation.nix:365:17:

          364|     in commonAttrs // {
          365|       drvPath = assert condition; drv.drvPath;
             |                 ^
          366|       outPath = assert condition; drv.outPath;

       … while evaluating the attribute 'handled'

         at /nix/store/lryfc8mhk1czqsa421di2y5nzz5c3b8m-source/pkgs/stdenv/generic/check-meta.nix:507:7:

          506|       # or, alternatively, just output a warning message.
          507|       handled =
             |       ^
          508|         (

       (stack trace truncated; use '--show-trace' to show the full trace)

       error: Package ‘sword-1.9.0’ in /nix/store/lryfc8mhk1czqsa421di2y5nzz5c3b8m-source/pkgs/by-name/sw/sword/package.nix:49 is not available on the requested hostPlatform:
         hostPlatform.config = "x86_64-w64-mingw32"
         package.meta.platforms = [
           "i686-cygwin"
           "x86_64-cygwin"
           "x86_64-darwin"
           "i686-darwin"
           "aarch64-darwin"
           "armv7a-darwin"
           "i686-freebsd"
           "x86_64-freebsd"
           "x86_64-solaris"
           "aarch64-linux"
           "armv5tel-linux"
           "armv6l-linux"
           "armv7a-linux"
           "armv7l-linux"
           "i686-linux"
           "loongarch64-linux"
           "m68k-linux"
           "microblaze-linux"
           "microblazeel-linux"
           "mips-linux"
           "mips64-linux"
           "mips64el-linux"
           "mipsel-linux"
           "powerpc64-linux"
           "powerpc64le-linux"
           "riscv32-linux"
           "riscv64-linux"
           "s390-linux"
           "s390x-linux"
           "x86_64-linux"
           "aarch64-netbsd"
           "armv6l-netbsd"
           "armv7a-netbsd"
           "armv7l-netbsd"
           "i686-netbsd"
           "m68k-netbsd"
           "mipsel-netbsd"
           "powerpc-netbsd"
           "riscv32-netbsd"
           "riscv64-netbsd"
           "x86_64-netbsd"
           "i686-openbsd"
           "x86_64-openbsd"
           "x86_64-redox"
         ]
         package.meta.badPlatforms = [ ]
       , refusing to evaluate.

       a) To temporarily allow packages that are unsupported for this system, you can use an environment variable
          for a single invocation of the nix tools.

            $ export NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1

          Note: When using `nix shell`, `nix build`, `nix develop`, etc with a flake,
                then pass `--impure` in order to allow use of environment variables.

       b) For `nixos-rebuild` you can set
         { nixpkgs.config.allowUnsupportedSystem = true; }
       in configuration.nix to override this.

       c) For `nix-env`, `nix-build`, `nix-shell` or any other Nix command you can add
         { allowUnsupportedSystem = true; }
       to ~/.config/nixpkgs/config.nix.

That’s a WHOLE lot of text to tell me it can’t build for Windows! But, I have opened some pull requests for NixPkgs so that SWORD will be listed as supported. Because, indeed, there isn’t anything inherent in SWORD that requires it to be built for only Unix systems. It supports all manner of embedded, Windows, and other environments in addition to standard Linux/Unix platforms. It only required a few tweaks to the build formula to tell it where to find the options that it wanted.

TLDR

Show me the goods!

OK, if you’re just looking for the compiled binaries. Try this link to get the resulting product. Drop me an email if you have any feedback on it. I haven’t had much of a chance to test things, so it’s very possible some parts of it don’t work. Give me a shout if that’s the case.