diff --git a/content/posts/sword-cross-20241018.md b/content/posts/sword-cross-20241018.md new file mode 100644 index 0000000..b094eeb --- /dev/null +++ b/content/posts/sword-cross-20241018.md @@ -0,0 +1,158 @@ +--- +title: "Sword Windows Cross Build 20241018" +date: 2024-10-18T11:05:36-05:00 +draft: false +--- +*[TL;DR](#tldr)* 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](https://sourceforge.net/projects/mingw-w64/) +toolchain from [Fedora](https://fedoraproject.org/) - 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](https://nixos.org) 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](https://www.crosswire.org/sword), 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](../sword-nixbuild-win64-20241018.tar.xz) +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. diff --git a/content/posts/sword-nixbuild-win64-20241018.tar.xz b/content/posts/sword-nixbuild-win64-20241018.tar.xz new file mode 100644 index 0000000..9c47a31 Binary files /dev/null and b/content/posts/sword-nixbuild-win64-20241018.tar.xz differ