From c804b1f6639bfe5f9e9cfddee5dac3b940f2d943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFs?= <49660929+SailorSnoW@users.noreply.github.com> Date: Sat, 23 May 2026 15:20:45 +0200 Subject: [PATCH] Rework nix flake for offline multi-platform builds (#1601) * Rework flake.nix for offline multi-platform builds (Linux & macOS) * fix typo + fmt --- flake.lock | 6 +- flake.nix | 535 ++++++++++++++++++++++++++++++++++------------------- 2 files changed, 348 insertions(+), 193 deletions(-) diff --git a/flake.lock b/flake.lock index 8ec14d2852..08dc0f458c 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1775710090, - "narHash": "sha256-ar3rofg+awPB8QXDaFJhJ2jJhu+KqN/PRCXeyuXR76E=", + "lastModified": 1778869304, + "narHash": "sha256-30sZNZoA1cqF5JNO9fVX+wgiQYjB7HJqqJ4ztCDeBZE=", "owner": "nixos", "repo": "nixpkgs", - "rev": "4c1018dae018162ec878d42fec712642d214fdfa", + "rev": "d233902339c02a9c334e7e593de68855ad26c4cb", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 29c99b10a5..90c0d21533 100644 --- a/flake.nix +++ b/flake.nix @@ -1,219 +1,374 @@ { - inputs = { - nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; - }; - outputs = { self, nixpkgs }: + description = "Dusklight — native PC port of the Twilight Princess decompilation"; + + inputs.nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + + outputs = + { self, nixpkgs }: let + inherit (nixpkgs) lib; + supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; - forAllSystems = nixpkgs.lib.genAttrs supportedSystems; - pkgsFor = system: import nixpkgs { inherit system; }; + forAllSystems = lib.genAttrs supportedSystems; - # Dependencies that are not packaged in nixpkgs (used by the Linux package build): - buildSources = pkgs: { - dawn-src = pkgs.fetchzip { - url = "https://github.com/encounter/dawn-build/releases/download/v20260423.175430/dawn-linux-x86_64.tar.gz"; + dawnVersion = "v20260423.175430"; + nodVersion = "v2.0.0-alpha.8"; + versionSuffix = "nix-" + (self.shortRev or self.dirtyShortRev or "dirty"); + + dawnInfo = { + "x86_64-linux" = { + triple = "linux-x86_64"; hash = "sha256-HXfKTLHtMPwupnFnaflCARtXVPuS/0PoCePXidjE5xs="; - stripRoot = false; }; - nod-src = pkgs.fetchzip { - url = "https://github.com/encounter/nod/releases/download/v2.0.0-alpha.8/libnod-linux-x86_64.tar.gz"; - hash = "sha256-mUqvLsbsqaZ+HAjMmHYPYO+MgtanGRTw7Gzn5uXR5rE="; - stripRoot = false; + "aarch64-linux" = { + triple = "linux-aarch64"; + hash = "sha256-34yyFpfqBZUwoFXQ41F0AwAU78FaNihOSY0oriwn6B0="; }; - # The version of imgui on nixpkgs does not map cleanly. - imgui-src = pkgs.fetchFromGitHub { - owner = "ocornut"; - repo = "imgui"; - rev = "v1.91.9b-docking"; - hash = "sha256-mQOJ6jCN+7VopgZ61yzaCnt4R1QLrW7+47xxMhFRHLQ="; + "aarch64-darwin" = { + triple = "darwin-arm64"; + hash = "sha256-eQnzrBp6gjiBek1VYQ9A5W13ClYWrDDKjIqv/7eNTR4="; }; - sqlite-src = pkgs.fetchzip { - url = "https://sqlite.org/2026/sqlite-amalgamation-3510300.zip"; - hash = "sha256-pNMR8zxaaqfAzQ0AQBOXMct4usdjey1Q0Gnitg06UhM="; - }; - rmlui-src = pkgs.fetchzip { - url = "https://github.com/mikke89/RmlUi/archive/f9b8c9e2935d5df2c7dff2c190d3968e99b0c3dc.tar.gz"; - hash = "sha256-g4O/JZUrrcseOz8o2QJRt+2CeuiLnVeuDJc906xvuIg="; + "x86_64-darwin" = { + triple = "darwin-x86_64"; + hash = "sha256-QGWiGdxiI9kci3NPXH6QFFirxn16851zB/w3jqhIBJ4="; }; }; - # Dusklight Actual (Linux x86_64 only — relies on prebuilt dawn/nod binaries) - mkDusklight = pkgs: - let srcs = buildSources pkgs; - versionSuffix = if self ? shortRev && self.shortRev != null - then "nix-${self.shortRev}" - else "nix-dirty"; - in - pkgs.stdenv.mkDerivation { - name = "dusklight"; - src = ./.; - postUnpack = '' - sed -i '/add_subdirectory(tests)/d' $sourceRoot/extern/aurora/CMakeLists.txt - ''; - # Remove last line to re-enable tests - cmakeFlags = [ - "-DDUSK_VERSION_OVERRIDE=${versionSuffix}" - "-DFETCHCONTENT_FULLY_DISCONNECTED=ON" - "-DFETCHCONTENT_SOURCE_DIR_CXXOPTS=${pkgs.cxxopts.src}" - "-DFETCHCONTENT_SOURCE_DIR_JSON=${pkgs.nlohmann_json.src}" - "-DFETCHCONTENT_SOURCE_DIR_DAWN_PREBUILT=${srcs.dawn-src}" - "-DFETCHCONTENT_SOURCE_DIR_XXHASH=${pkgs.xxHash.src}" - "-DFETCHCONTENT_SOURCE_DIR_FMT=${pkgs.fmt.src}" - "-DFETCHCONTENT_SOURCE_DIR_TRACY=${pkgs.tracy.src}" - "-DAURORA_SDL3_PROVIDER=system" - "-DFETCHCONTENT_SOURCE_DIR_NOD_PREBUILT=${srcs.nod-src}" - "-DAURORA_NOD_PROVIDER=package" - "-DFETCHCONTENT_SOURCE_DIR_FREETYPE=${pkgs.freetype.src}" - "-DFETCHCONTENT_SOURCE_DIR_ZSTD=${pkgs.zstd.src}" - "-DFETCHCONTENT_SOURCE_DIR_SQLITE3=${srcs.sqlite-src}" - "-DFETCHCONTENT_SOURCE_DIR_IMGUI=${srcs.imgui-src}" - "-DFETCHCONTENT_SOURCE_DIR_RMLUI=${srcs.rmlui-src}" - "-DCMAKE_CROSSCOMPILING=ON" # Tests are not working as I didn't want to work through getting google's test suite working as well. This is the only guard I could find to disable it. - ]; - installPhase = '' - mkdir -p $out/bin - cp dusklight $out/bin/dusklight - cp -r ./res $out/bin/res + nodPrebuiltInfo = { + "x86_64-linux" = { + triple = "linux-x86_64"; + hash = "sha256-mUqvLsbsqaZ+HAjMmHYPYO+MgtanGRTw7Gzn5uXR5rE="; + }; + "aarch64-darwin" = { + triple = "macos-arm64"; + hash = "sha256-UPy1ywCcv0K6VJOU3uUelJuUdBh3UNaPRlyP5LOBeDw="; + }; + }; - mkdir -p $out/share/applications - cp $src/platforms/freedesktop/dusklight.desktop $out/share/applications/dusklight.desktop + perSystem = + system: + let + pkgs = import nixpkgs { inherit system; }; + inherit (pkgs.stdenv.hostPlatform) isDarwin; + hasNodPrebuilt = nodPrebuiltInfo ? ${system}; - for size in 16 32 48 64 128 256 512 1024; do - install -Dm644 $src/platforms/freedesktop/''${size}x''${size}/apps/dusklight.png \ - $out/share/icons/hicolor/''${size}x''${size}/apps/dusklight.png - done - ''; - nativeBuildInputs = [ + aurora = pkgs.fetchFromGitHub { + owner = "encounter"; + repo = "aurora"; + rev = "10006618ee493f248b8597e4dfa1d2871d76a1d9"; + hash = "sha256-lY2xuVyB7aPJ9+2wwLRB3F5U/BuPSxdSpegdG+qNd9o="; + }; + + dawn = pkgs.fetchzip { + url = "https://github.com/encounter/dawn-build/releases/download/${dawnVersion}/dawn-${dawnInfo.${system}.triple}.tar.gz"; + hash = dawnInfo.${system}.hash; + stripRoot = false; + }; + + corrosion = pkgs.fetchFromGitHub { + owner = "corrosion-rs"; + repo = "corrosion"; + rev = "v0.6.1"; + hash = "sha256-ppuDNObfKhneD9AlnPAvyCRHKW3BidXKglD1j/LE9CM="; + }; + + nodFromSource = pkgs.stdenv.mkDerivation (finalAttrs: { + pname = "nod"; + version = nodVersion; + src = pkgs.fetchFromGitHub { + owner = "encounter"; + repo = "nod"; + rev = nodVersion; + hash = "sha256-+zrtVzjo0+X/6uMcNUn1+FaSR+jOhrcQSDNBFjw0NDs="; + }; + cargoDeps = pkgs.rustPlatform.importCargoLock { + lockFile = "${finalAttrs.src}/Cargo.lock"; + }; + postPatch = '' + substituteInPlace CMakeLists.txt \ + --replace-warn "add_subdirectory(nod-ffi/examples)" "" + ''; + nativeBuildInputs = [ + pkgs.cmake + pkgs.ninja + pkgs.rustPlatform.cargoSetupHook + pkgs.cargo + pkgs.rustc + ]; + CARGO_NET_OFFLINE = "true"; + cmakeFlags = [ + "-DFETCHCONTENT_FULLY_DISCONNECTED=ON" + "-DFETCHCONTENT_SOURCE_DIR_CORROSION=${corrosion}" + "-DNOD_ENABLE_INSTALL=ON" + "-DBUILD_SHARED_LIBS=OFF" + ]; + doCheck = false; + }); + + nod = + if hasNodPrebuilt then + pkgs.fetchzip { + url = "https://github.com/encounter/nod/releases/download/${nodVersion}/libnod-${ + nodPrebuiltInfo.${system}.triple + }.tar.gz"; + hash = nodPrebuiltInfo.${system}.hash; + stripRoot = false; + } + else + nodFromSource; + + fetchContentDirs = { + DAWN_PREBUILT = dawn; + NOD_PREBUILT = nod; + CXXOPTS = pkgs.cxxopts.src; + JSON = pkgs.nlohmann_json.src; + XXHASH = pkgs.xxHash.src; + ZSTD = pkgs.zstd.src; + FMT = pkgs.fetchzip { + url = "https://github.com/fmtlib/fmt/archive/refs/tags/11.1.4.tar.gz"; + hash = "sha256-sUbxlYi/Aupaox3JjWFqXIjcaQa0LFjclQAOleT+FRA="; + }; + TRACY = pkgs.fetchzip { + url = "https://github.com/wolfpld/tracy/archive/a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz"; + hash = "sha256-hbNGOsGeyGSvCJ2No8RkwOib1lX2on3vNZSzyVkZdXw="; + }; + IMGUI = pkgs.fetchFromGitHub { + owner = "ocornut"; + repo = "imgui"; + rev = "v1.91.9b-docking"; + hash = "sha256-mQOJ6jCN+7VopgZ61yzaCnt4R1QLrW7+47xxMhFRHLQ="; + }; + SQLITE3 = pkgs.fetchzip { + url = "https://sqlite.org/2026/sqlite-amalgamation-3510300.zip"; + hash = "sha256-pNMR8zxaaqfAzQ0AQBOXMct4usdjey1Q0Gnitg06UhM="; + }; + RMLUI = pkgs.fetchzip { + url = "https://github.com/mikke89/RmlUi/archive/f9b8c9e2935d5df2c7dff2c190d3968e99b0c3dc.tar.gz"; + hash = "sha256-g4O/JZUrrcseOz8o2QJRt+2CeuiLnVeuDJc906xvuIg="; + }; + }; + + dusklight = pkgs.stdenv.mkDerivation { + pname = "dusklight"; + version = versionSuffix; + src = ./.; + + postUnpack = '' + chmod -R u+w "$sourceRoot" + rm -rf "$sourceRoot/extern/aurora" + mkdir -p "$sourceRoot/extern" + cp -r ${aurora} "$sourceRoot/extern/aurora" + chmod -R u+w "$sourceRoot/extern/aurora" + substituteInPlace "$sourceRoot/extern/aurora/CMakeLists.txt" \ + --replace-warn "add_subdirectory(tests)" "" + ''; + + nativeBuildInputs = [ + pkgs.cmake + pkgs.ninja + pkgs.pkg-config + pkgs.python3 + pkgs.python3Packages.markupsafe + ] + ++ lib.optionals (!isDarwin) [ pkgs.autoPatchelfHook ]; + + buildInputs = [ + pkgs.sdl3 + pkgs.freetype + pkgs.zstd + pkgs.cxxopts + pkgs.nlohmann_json + pkgs.xxHash + pkgs.abseil-cpp + pkgs.zlib + pkgs.libpng + pkgs.libjpeg_turbo + pkgs.curl + pkgs.openssl + ] + ++ lib.optionals isDarwin [ + pkgs.apple-sdk_15 + pkgs.libiconv + ] + ++ lib.optionals (!isDarwin) [ + pkgs.libGL + pkgs.libGLU + pkgs.libglvnd + pkgs.vulkan-loader + pkgs.libX11 + pkgs.libxcb + pkgs.libXcursor + pkgs.libxi + pkgs.libxrandr + pkgs.libxscrnsaver + pkgs.libxtst + pkgs.libxinerama + pkgs.libxkbcommon + pkgs.wayland + pkgs.libdecor + pkgs.alsa-lib + pkgs.libpulseaudio + pkgs.pipewire + pkgs.dbus + pkgs.udev + pkgs.libusb1 + pkgs.libunwind + pkgs.gtk3 + ]; + + cmakeBuildType = "RelWithDebInfo"; + ninjaFlags = [ "dusklight" ]; + + cmakeFlags = [ + "-DDUSK_VERSION_OVERRIDE=${versionSuffix}" + "-DFETCHCONTENT_FULLY_DISCONNECTED=ON" + "-DAURORA_DAWN_PROVIDER=package" + "-DAURORA_DAWN_LINKAGE=static" + "-DAURORA_NOD_PROVIDER=package" + "-DAURORA_NOD_LINKAGE=static" + "-DAURORA_SDL3_PROVIDER=system" + ] + ++ lib.mapAttrsToList (key: src: "-DFETCHCONTENT_SOURCE_DIR_${key}=${src}") fetchContentDirs; + + installPhase = + if isDarwin then + '' + runHook preInstall + mkdir -p "$out/Applications" + cp -r Dusklight.app "$out/Applications/Dusklight.app" + runHook postInstall + '' + else + '' + runHook preInstall + install -Dm755 dusklight "$out/bin/dusklight" + cp -r "$src/res" "$out/bin/res" + install -Dm644 "$src/platforms/freedesktop/dusklight.desktop" \ + "$out/share/applications/dusklight.desktop" + for size in 16 32 48 64 128 256 512 1024; do + install -Dm644 "$src/platforms/freedesktop/''${size}x''${size}/apps/dusklight.png" \ + "$out/share/icons/hicolor/''${size}x''${size}/apps/dusklight.png" + done + runHook postInstall + ''; + + dontStrip = true; + + meta = { + description = "Dusklight — native PC port of the Twilight Princess decompilation"; + homepage = "https://github.com/zeldaret/tp"; + platforms = supportedSystems; + mainProgram = "dusklight"; + }; + }; + + # Tooling common to every supported host (Linux and macOS). + commonDevTools = [ pkgs.cmake + pkgs.ninja pkgs.pkg-config - pkgs.wayland + pkgs.git + pkgs.python3 + pkgs.python3Packages.markupsafe + pkgs.rustc + pkgs.cargo + pkgs.sccache ]; - buildInputs = [ - pkgs.libGL - pkgs.libX11 - pkgs.libXcursor - pkgs.libxi - pkgs.libxcb - pkgs.libxrandr - pkgs.libxscrnsaver - pkgs.libxtst - pkgs.libjpeg8 - pkgs.libxkbcommon - pkgs.libglvnd + + # Linux-only system libraries — mirrors the apt deps from .github/workflows/build.yml + # so the cmake presets resolve the same set of headers as CI. + linuxDevDeps = [ + # Compilers / linkers + pkgs.clang + pkgs.lld + # C/C++ utilities + pkgs.curl + pkgs.openssl + pkgs.zlib + pkgs.libpng + pkgs.libjpeg_turbo + pkgs.freetype + pkgs.zstd + pkgs.fmt + pkgs.tracy pkgs.cxxopts pkgs.abseil-cpp pkgs.sdl3 - pkgs.fmt - pkgs.tracy - pkgs.freetype - pkgs.zstd + pkgs.ncurses + pkgs.libunwind + pkgs.libusb1 + pkgs.fuse + # Wayland / display server + pkgs.wayland + pkgs.wayland-protocols + pkgs.libxkbcommon + pkgs.libdecor + # OpenGL / Vulkan + pkgs.libGL + pkgs.libGLU + pkgs.libglvnd + pkgs.vulkan-headers + pkgs.vulkan-loader + # X11 + pkgs.libX11 + pkgs.libxcb + pkgs.libXcursor + pkgs.libxi + pkgs.libxrandr + pkgs.libxscrnsaver + pkgs.libxtst + pkgs.libxinerama + # Audio + pkgs.alsa-lib + pkgs.libpulseaudio + pkgs.pipewire + # System integration + pkgs.dbus + pkgs.udev + pkgs.gtk3 ]; + + # On macOS we deliberately avoid pulling Nix's cc-wrapper so CMake picks up + # Apple Clang and the Xcode SDK directly, matching the macOS CI workflow. + darwinShell = pkgs.mkShellNoCC { + packages = commonDevTools; + shellHook = '' + echo "Dusklight dev shell (macOS)" + echo "Requires Xcode Command Line Tools for Apple Clang and the macOS SDK." + echo "Configure: cmake --preset macos-default-relwithdebinfo" + echo "Build: cmake --build --preset macos-default-relwithdebinfo" + ''; + }; + + linuxShell = pkgs.mkShell { + packages = commonDevTools ++ linuxDevDeps; + shellHook = '' + echo "Dusklight dev shell (Linux)" + echo "Configure: cmake --preset linux-default-relwithdebinfo" + echo " cmake --preset linux-clang-relwithdebinfo" + echo "Build: cmake --build --preset " + ''; + }; + in + { + packages = { + default = dusklight; + dusklight = dusklight; + } + // lib.optionalAttrs (!hasNodPrebuilt) { nod = nodFromSource; }; + + devShells.default = if isDarwin then darwinShell else linuxShell; }; - # Tooling common to every supported host (Linux and macOS). - commonDevTools = pkgs: [ - pkgs.cmake - pkgs.ninja - pkgs.pkg-config - pkgs.git - pkgs.python3 - pkgs.python3Packages.markupsafe - pkgs.rustc - pkgs.cargo - pkgs.sccache - ]; - - # Linux-only system libraries — mirrors the apt deps from .github/workflows/build.yml - # so the cmake presets resolve the same set of headers as CI. - linuxDevDeps = pkgs: [ - # Compilers / linkers - pkgs.clang - pkgs.lld - # C/C++ utilities - pkgs.curl - pkgs.openssl - pkgs.zlib - pkgs.libpng - pkgs.libjpeg_turbo - pkgs.freetype - pkgs.zstd - pkgs.fmt - pkgs.tracy - pkgs.cxxopts - pkgs.abseil-cpp - pkgs.sdl3 - pkgs.ncurses - pkgs.libunwind - pkgs.libusb1 - pkgs.fuse - # Wayland / display server - pkgs.wayland - pkgs.wayland-protocols - pkgs.libxkbcommon - pkgs.libdecor - # OpenGL / Vulkan - pkgs.libGL - pkgs.libGLU - pkgs.libglvnd - pkgs.vulkan-headers - pkgs.vulkan-loader - # X11 - pkgs.libX11 - pkgs.libxcb - pkgs.libXcursor - pkgs.libxi - pkgs.libxrandr - pkgs.libxscrnsaver - pkgs.libxtst - pkgs.libxinerama - # Audio - pkgs.alsa-lib - pkgs.libpulseaudio - pkgs.pipewire - # System integration - pkgs.dbus - pkgs.udev - pkgs.gtk3 - ]; - - # On macOS we deliberately avoid pulling Nix's cc-wrapper so CMake picks up - # Apple Clang and the Xcode SDK directly, matching the macOS CI workflow. - mkDarwinShell = pkgs: - pkgs.mkShellNoCC { - packages = commonDevTools pkgs; - shellHook = '' - echo "Dusklight dev shell (macOS)" - echo "Requires Xcode Command Line Tools for Apple Clang and the macOS SDK." - echo "Configure: cmake --preset macos-default-relwithdebinfo" - echo "Build: cmake --build --preset macos-default-relwithdebinfo" - ''; - }; - - mkLinuxShell = pkgs: - pkgs.mkShell { - packages = (commonDevTools pkgs) ++ (linuxDevDeps pkgs); - shellHook = '' - echo "Dusklight dev shell (Linux)" - echo "Configure: cmake --preset linux-default-relwithdebinfo" - echo " cmake --preset linux-clang-relwithdebinfo" - echo "Build: cmake --build --preset " - ''; - }; - - mkDevShell = pkgs: - if pkgs.stdenv.isDarwin - then mkDarwinShell pkgs - else mkLinuxShell pkgs; - in { - packages.x86_64-linux.default = mkDusklight (pkgsFor "x86_64-linux"); - - devShells = forAllSystems (system: { - default = mkDevShell (pkgsFor system); - }); + systems = forAllSystems perSystem; + in + { + packages = lib.mapAttrs (_: s: s.packages) systems; + devShells = lib.mapAttrs (_: s: s.devShells) systems; }; }