diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5520e5c..2111a4b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,12 +31,15 @@ jobs: include: - target: x86_64-linux os: ubuntu-latest - - target: arm64-linux + - target: aarch64-linux os: ubuntu-latest - target: x86_64-windows os: ubuntu-latest - - target: x86_64-macos + - target: x86_64-darwin os: macos-latest + # FIXME: build broken + # - target: aarch64-darwin + # os: macos-latest steps: - name: Checkout code uses: actions/checkout@v2 @@ -53,7 +56,7 @@ jobs: - name: Build release archive run: | nix build -L .#${{ matrix.target }} - cp result/bin/himalaya* . + cp result/himalaya* . - name: Upload tgz release archive uses: actions/upload-release-asset@v1 env: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..c8dc6fe --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,41 @@ +name: test + +on: + push: + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-linux + os: ubuntu-latest + - target: aarch64-linux + os: ubuntu-latest + - target: x86_64-windows + os: ubuntu-latest + - target: x86_64-darwin + os: macos-latest + # FIXME: build broken + # - target: aarch64-darwin + # os: macos-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Install Nix + uses: cachix/install-nix-action@v24 + with: + nix_path: nixpkgs=channel:nixos-23.11 + extra_nix_config: | + experimental-features = nix-command flakes + - uses: cachix/cachix-action@v12 + with: + name: soywod + authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + - name: Run app + run: | + nix build -L .#${{ matrix.target }} + nix run -L .#${{ matrix.target }} -- --version + ls -R result diff --git a/flake.nix b/flake.nix index 0ac1797..86a00ae 100644 --- a/flake.nix +++ b/flake.nix @@ -23,127 +23,188 @@ outputs = { self, nixpkgs, gitignore, fenix, naersk, ... }: let + inherit (nixpkgs) lib; inherit (gitignore.lib) gitignoreSource; - staticRustFlags = [ "-Ctarget-feature=+crt-static" ]; - - # Map of map matching supported Nix build systems with Rust - # cross target systems. - crossBuildTargets = { + crossSystems = { x86_64-linux = { x86_64-linux = { rustTarget = "x86_64-unknown-linux-musl"; - override = { ... }: { }; }; - arm64-linux = rec { + aarch64-linux = rec { rustTarget = "aarch64-unknown-linux-musl"; - override = { system, pkgs }: + runner = { pkgs, himalaya }: "${pkgs.qemu}/bin/qemu-aarch64 ${himalaya}"; + mkPackage = { system, pkgs }: package: let inherit (mkPkgsCross system rustTarget) stdenv; - cc = "${stdenv.cc}/bin/${stdenv.cc.targetPrefix}cc"; in - rec { + cc = "${stdenv.cc}/bin/${stdenv.cc.targetPrefix}cc"; + in + package // { TARGET_CC = cc; - CARGO_BUILD_RUSTFLAGS = staticRustFlags ++ [ "-Clinker=${cc}" ]; - postInstall = mkPostInstall { - inherit pkgs; - bin = "${pkgs.qemu}/bin/qemu-aarch64 ./himalaya"; - }; + CARGO_BUILD_RUSTFLAGS = package.CARGO_BUILD_RUSTFLAGS ++ [ "-Clinker=${cc}" ]; }; }; x86_64-windows = { rustTarget = "x86_64-pc-windows-gnu"; - override = { system, pkgs }: + runner = { pkgs, himalaya }: + let wine = pkgs.wine.override { wineBuild = "wine64"; }; + in "${wine}/bin/wine64 ${himalaya}.exe"; + mkPackage = { system, pkgs }: package: let - inherit (pkgs) pkgsCross zip; - inherit (pkgsCross.mingwW64) stdenv windows; + inherit (pkgs.pkgsCross.mingwW64) stdenv windows; cc = "${stdenv.cc}/bin/${stdenv.cc.targetPrefix}cc"; - wine = pkgs.wine.override { wineBuild = "wine64"; }; - postInstall = mkPostInstall { - inherit pkgs; - bin = "${wine}/bin/wine64 ./himalaya.exe"; - }; in - { + package // { depsBuildBuild = [ stdenv.cc windows.pthreads ]; TARGET_CC = cc; - CARGO_BUILD_RUSTFLAGS = staticRustFlags ++ [ "-Clinker=${cc}" ]; - postInstall = '' - export WINEPREFIX="$(mktemp -d)" - ${postInstall} - ''; + CARGO_BUILD_RUSTFLAGS = package.CARGO_BUILD_RUSTFLAGS ++ [ "-Clinker=${cc}" ]; }; }; }; + aarch64-linux = { + aarch64-linux = { + rustTarget = "aarch64-unknown-linux-musl"; + }; + }; + x86_64-darwin = { - x86_64-macos = { + x86_64-darwin = { rustTarget = "x86_64-apple-darwin"; - override = { pkgs, ... }: - let inherit (pkgs.darwin.apple_sdk.frameworks) AppKit Cocoa; in - { + mkPackage = { pkgs, ... }: package: + let inherit (pkgs.darwin.apple_sdk.frameworks) AppKit Cocoa; + in package // { buildInputs = [ Cocoa ]; NIX_LDFLAGS = "-F${AppKit}/Library/Frameworks -framework AppKit"; }; }; - # FIXME: infinite recursion in stdenv?! - arm64-macos = { + # FIXME: https://github.com/NixOS/nixpkgs/issues/273442 + aarch64-darwin = { rustTarget = "aarch64-apple-darwin"; - override = { system, pkgs }: + runner = { pkgs, himalaya }: "${pkgs.qemu}/bin/qemu-aarch64 ${himalaya}"; + mkPackage = { system, pkgs }: package: let - # inherit (mkPkgsCross system "aarch64-darwin") stdenv; inherit ((mkPkgsCross system "aarch64-darwin").pkgsStatic) stdenv darwin; inherit (darwin.apple_sdk.frameworks) AppKit Cocoa; cc = "${stdenv.cc}/bin/${stdenv.cc.targetPrefix}cc"; in - rec { + package // { buildInputs = [ Cocoa ]; - NIX_LDFLAGS = "-F${AppKit}/Library/Frameworks -framework AppKit -F${Cocoa}/Library/Frameworks -framework Cocoa"; - NIX_CFLAGS_COMPILE = "-F${AppKit}/Library/Frameworks -framework AppKit -F${Cocoa}/Library/Frameworks -framework Cocoa"; + NIX_LDFLAGS = "-F${AppKit}/Library/Frameworks -framework AppKit"; TARGET_CC = cc; - CARGO_BUILD_RUSTFLAGS = staticRustFlags ++ [ "-Clinker=${cc}" "-lframework=${Cocoa}/Library/Frameworks" ]; - postInstall = mkPostInstall { - inherit pkgs; - bin = "${pkgs.qemu}/bin/qemu-aarch64 ./himalaya"; - }; + CARGO_BUILD_RUSTFLAGS = package.CARGO_BUILD_RUSTFLAGS ++ [ "-Clinker=${cc}" ]; + }; + }; + }; + + aarch64-darwin = { + aarch64-darwin = { + rustTarget = "aarch64-apple-darwin"; + mkPackage = { pkgs, ... }: package: + let inherit (pkgs.darwin.apple_sdk.frameworks) AppKit Cocoa; + in package // { + buildInputs = [ Cocoa ]; + NIX_LDFLAGS = "-F${AppKit}/Library/Frameworks -framework AppKit"; }; }; }; }; - mkToolchain = import ./rust-toolchain.nix fenix; + eachBuildSystem = lib.genAttrs (builtins.attrNames crossSystems); mkPkgsCross = buildSystem: crossSystem: import nixpkgs { system = buildSystem; crossSystem.config = crossSystem; }; - mkPostInstall = { pkgs, bin ? "./himalaya" }: with pkgs; '' - cd $out/bin - mkdir -p {man,completions} - ${bin} man ./man - ${bin} completion bash > ./completions/himalaya.bash - ${bin} completion elvish > ./completions/himalaya.elvish - ${bin} completion fish > ./completions/himalaya.fish - ${bin} completion powershell > ./completions/himalaya.powershell - ${bin} completion zsh > ./completions/himalaya.zsh - tar -czf himalaya.tgz himalaya* man completions - ${zip}/bin/zip -r himalaya.zip himalaya* man completions - ''; + mkToolchain = import ./rust-toolchain.nix fenix; - mkDevShells = buildPlatform: + mkApp = { pkgs, buildSystem, targetSystem ? buildSystem }: let - pkgs = import nixpkgs { system = buildPlatform; }; - rust-toolchain = mkToolchain.fromFile { system = buildPlatform; }; + himalaya = lib.getExe self.packages.${buildSystem}.${targetSystem}; + wrapper = crossSystems.${buildSystem}.${targetSystem}.runner or (_: himalaya) { inherit pkgs himalaya; }; + program = lib.getExe (pkgs.writeShellScriptBin "himalaya" "${wrapper} $@"); + app = { inherit program; type = "app"; }; in - { - default = pkgs.mkShell { + app; + + mkApps = buildSystem: + let + pkgs = import nixpkgs { system = buildSystem; }; + mkApp' = targetSystem: _: mkApp { inherit pkgs buildSystem targetSystem; }; + defaultApp = mkApp { inherit pkgs buildSystem; }; + apps = builtins.mapAttrs mkApp' crossSystems.${buildSystem}; + in + apps // { default = defaultApp; }; + + mkPackage = { pkgs, buildSystem, targetSystem ? buildSystem }: + let + targetConfig = crossSystems.${buildSystem}.${targetSystem}; + toolchain = mkToolchain.fromTarget { + inherit pkgs buildSystem; + targetSystem = targetConfig.rustTarget; + }; + rust = naersk.lib.${buildSystem}.override { + cargo = toolchain; + rustc = toolchain; + }; + mkPackage' = targetConfig.mkPackage or (_: p: p); + himalaya = "./himalaya"; + runner = targetConfig.runner or (_: himalaya) { inherit pkgs himalaya; }; + package = mkPackage' { inherit pkgs; system = buildSystem; } { + name = "himalaya"; + src = gitignoreSource ./.; + strictDeps = true; + doCheck = false; + auditable = false; + nativeBuildInputs = with pkgs; [ pkg-config ]; + CARGO_BUILD_TARGET = targetConfig.rustTarget; + CARGO_BUILD_RUSTFLAGS = [ "-Ctarget-feature=+crt-static" ]; + postInstall = '' + export WINEPREFIX="$(mktemp -d)" + + mkdir -p $out/bin/share/{applications,completions,man,services} + cp assets/himalaya.desktop $out/bin/share/applications/ + cp assets/himalaya-watch@.service $out/bin/share/services/ + + cd $out/bin + ${runner} man ./share/man + ${runner} completion bash > ./share/completions/himalaya.bash + ${runner} completion elvish > ./share/completions/himalaya.elvish + ${runner} completion fish > ./share/completions/himalaya.fish + ${runner} completion powershell > ./share/completions/himalaya.powershell + ${runner} completion zsh > ./share/completions/himalaya.zsh + tar -czf himalaya.tgz himalaya* share + ${pkgs.zip}/bin/zip -r himalaya.zip himalaya* share + + mv share ../ + mv himalaya.tgz himalaya.zip ../ + ''; + }; + in + rust.buildPackage package; + + mkPackages = buildSystem: + let + pkgs = import nixpkgs { system = buildSystem; }; + mkPackage' = targetSystem: _: mkPackage { inherit pkgs buildSystem targetSystem; }; + defaultPackage = mkPackage { inherit pkgs buildSystem; }; + packages = builtins.mapAttrs mkPackage' crossSystems.${buildSystem}; + in + packages // { default = defaultPackage; }; + + mkDevShells = buildSystem: + let + pkgs = import nixpkgs { system = buildSystem; }; + rust-toolchain = mkToolchain.fromFile { inherit buildSystem; }; + defaultShell = pkgs.mkShell { nativeBuildInputs = with pkgs; [ pkg-config ]; buildInputs = with pkgs; [ # Nix - # rnix-lsp + nixd nixpkgs-fmt # Rust @@ -157,63 +218,13 @@ notmuch ]; }; - }; - - mkPackage = pkgs: buildPlatform: targetPlatform: package: - let - toolchain = mkToolchain.fromTarget { - inherit pkgs buildPlatform targetPlatform; - }; - naersk' = naersk.lib.${buildPlatform}.override { - cargo = toolchain; - rustc = toolchain; - }; - package' = { - name = "himalaya"; - src = gitignoreSource ./.; - # overrideMain = _: { - # postInstall = '' - # mkdir -p $out/share/applications/ - # cp assets/himalaya.desktop $out/share/applications/ - # ''; - # }; - doCheck = false; - auditable = false; - strictDeps = true; - CARGO_BUILD_TARGET = targetPlatform; - CARGO_BUILD_RUSTFLAGS = staticRustFlags; - postInstall = mkPostInstall { inherit pkgs; }; - } // package; in - naersk'.buildPackage package'; + { default = defaultShell; }; - mkPackages = system: - let - pkgs = import nixpkgs { inherit system; }; - mkPackage' = target: package: mkPackage pkgs system package.rustTarget (package.override { inherit system pkgs; }); - in - builtins.mapAttrs mkPackage' crossBuildTargets.${system}; - - mkApp = drv: - let exePath = drv.passthru.exePath or "/bin/himalaya"; in - { - type = "app"; - program = "${drv}${exePath}"; - }; - - mkApps = buildPlatform: - let - pkgs = import nixpkgs { system = buildPlatform; }; - mkApp' = target: package: mkApp self.packages.${buildPlatform}.${target}; - in - builtins.mapAttrs mkApp' crossBuildTargets.${buildPlatform}; - - supportedSystems = builtins.attrNames crossBuildTargets; - mapSupportedSystem = nixpkgs.lib.genAttrs supportedSystems; in { - apps = mapSupportedSystem mkApps; - packages = mapSupportedSystem mkPackages; - devShells = mapSupportedSystem mkDevShells; + apps = eachBuildSystem mkApps; + packages = eachBuildSystem mkPackages; + devShells = eachBuildSystem mkDevShells; }; } diff --git a/rust-toolchain.nix b/rust-toolchain.nix index 5c3d36a..57140c2 100644 --- a/rust-toolchain.nix +++ b/rust-toolchain.nix @@ -5,16 +5,16 @@ let sha256 = "+syqAd2kX8KVa8/U2gz3blIQTTsYYt3U63xBWaGOSc8="; in { - fromFile = { system }: fenix.packages.${system}.fromToolchainFile { + fromFile = { buildSystem }: fenix.packages.${buildSystem}.fromToolchainFile { inherit file sha256; }; - fromTarget = { pkgs, buildPlatform, targetPlatform }: + fromTarget = { pkgs, buildSystem, targetSystem }: let name = (pkgs.lib.importTOML file).toolchain.channel; - fenixPackage = fenix.packages.${buildPlatform}; + fenixPackage = fenix.packages.${buildSystem}; toolchain = fenixPackage.fromToolchainName { inherit name sha256; }; - targetToolchain = fenixPackage.targets.${targetPlatform}.fromToolchainName { inherit name sha256; }; + targetToolchain = fenixPackage.targets.${targetSystem}.fromToolchainName { inherit name sha256; }; in fenixPackage.combine [ toolchain.rustc