From 76bae0630ebcfd2b03bccb4c91a4d949f7d1c347 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Tue, 27 Oct 2026 06:13:57 -0700 Subject: [PATCH] build(nix): build and check for macOS and Windows A flake that builds the recorder for macOS and cross-compiles it for Windows from a Mac (xwin for the SDK, LLVM for the toolchain), with a dev shell for each, and `nix flake check` running clippy for both targets, rustfmt, taplo, cargo-deny and the tests. The sources of komorebi for Mac and komorebi for Windows are flake inputs, pinned in `flake.lock`: the recorder indexes them so that a line of komorebi's log can be traced to the statement that wrote it, and the dev shells and every derivation export where they are. --- .envrc | 1 + CONTRIBUTING.md | 20 ++- README.md | 10 +- flake.lock | 191 ++++++++++++++++++++++++++ flake.nix | 359 ++++++++++++++++++++++++++++++++++++++++++++++++ justfile | 11 +- nix/windows.nix | 80 +++++++++++ 7 files changed, 665 insertions(+), 7 deletions(-) create mode 100644 .envrc create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 nix/windows.nix diff --git a/.envrc b/.envrc new file mode 100644 index 00000000..3550a30f --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3e9bea5f..14e76069 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -46,12 +46,26 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ## Development environment -The project builds with the stable Rust toolchain, and is formatted with nightly `rustfmt` (`cargo +nightly fmt`). +The project is built with Nix. `nix develop` (or direnv, whose `.envrc` is `use flake`) provides the +Rust toolchain with nightly `rustfmt`, `cargo-deny`, `cargo-nextest`, `ffmpeg`, `jq`, `just` and +`ripgrep`, and sets `KOMOREBI_MAC_SRC` and `KOMOREBI_WINDOWS_SRC` (with `_COMMIT`) to the komorebi +sources pinned in `flake.lock`. The tests that read komorebi's source need them, so run `cargo` inside +the shell. + +The Windows code is type-checked from a Mac with `nix develop .#windows`, whose target is +`x86_64-pc-windows-msvc`. Nothing there runs it: a change to a `cfg(windows)` line is first run by the +`windows` job in CI. ## Checks -Before pushing, run `just check`, which runs formatting, clippy, the tests, rustdoc with its warnings as errors and -`cargo deny`. `just --list` shows the other recipes. +Before pushing, run + +```sh +just check +``` + +which runs formatting, clippy and the tests for macOS, clippy for Windows, rustdoc with its warnings as +errors for both hosts, and `cargo deny`. `just --list` shows the other recipes. ## Commits diff --git a/README.md b/README.md index 9d7fdafb..3fb80ff6 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,17 @@ There are no releases yet: build it from source, below. ### From source -With a stable Rust toolchain, in a checkout: +The repository is a Nix flake. In a checkout: ```sh +nix develop # the toolchain and the pinned komorebi sources cargo install --path komorebi-recorder --locked ``` +`nix build` makes the macOS binary in `./result/bin`, and `nix build .#komorebi-recorder-windows` cross-compiles +`komorebi-recorder.exe` and, with it, `komorebi-recorder-gui.exe` from a Mac. `nix run github:LGUG2Z/komorebi-recorder` +runs the latest commit without a checkout. + ## How it fits together Two things vary independently: the _host_ the recorder runs on (macOS or Windows) and the _flavor_ of komorebi it @@ -33,7 +38,8 @@ rewritten after they are written. ## Checks -`just check` runs formatting, clippy, the tests, rustdoc with its warnings as errors, and `cargo deny`. +`just check` runs formatting, clippy and the tests for macOS, clippy for Windows (the Windows code is type-checked +from a Mac, not run), rustdoc with its warnings as errors for both hosts, and `cargo deny`. It needs `nix develop`. CI runs the same checks, builds both platforms and, for Windows, the installer. ## Documentation diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..ed3454d7 --- /dev/null +++ b/flake.lock @@ -0,0 +1,191 @@ +{ + "nodes": { + "crane": { + "locked": { + "lastModified": 1792350552, + "narHash": "sha256-292lvpvxTGKryKxh3/3tcIVi85CwYGdl4oOi113Sob8=", + "owner": "ipetkov", + "repo": "crane", + "rev": "e675a36b7377bebe41d548388a2501cbb16d380d", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "owner": "NixOS", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1790898470, + "narHash": "sha256-zTwuwezD0w3hpga6a6P8emidzAZFyWqlNeRBlpWOOl8=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "024633cd702b10285db5cb19b40ad48d2399ba60", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "git-hooks-nix": { + "inputs": { + "flake-compat": "flake-compat", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1791909798, + "narHash": "sha256-VAhpCOmrun/KXimYfR8NM88bciKCui7CqHHhThSzgag=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "1ba1dbfe28738c9a71c266be6efa5b89e75491a9", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "komorebi-mac": { + "flake": false, + "locked": { + "lastModified": 1777946799, + "narHash": "sha256-uDprEfYaPugY2eJpKRIHJQoyxYKwXmnu/r8VQ7j9Fts=", + "owner": "LGUG2Z", + "repo": "komorebi-for-mac", + "rev": "bdf10452f10ebf15ec1978cb05d0aac79ef5611f", + "type": "github" + }, + "original": { + "owner": "LGUG2Z", + "repo": "komorebi-for-mac", + "type": "github" + } + }, + "komorebi-windows": { + "flake": false, + "locked": { + "lastModified": 1787433983, + "narHash": "sha256-L17PiaT8KH+2lEmsWJYnPV4HVifRi44tXJTCpCf4kwc=", + "owner": "LGUG2Z", + "repo": "komorebi", + "rev": "e0709f02bfae4e503bf4640f58ee75ecbbfdbb97", + "type": "github" + }, + "original": { + "owner": "LGUG2Z", + "repo": "komorebi", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1792842277, + "narHash": "sha256-pGPnZGi8y9d76xNeracniXO3dsYVROEmMkMc8jD0Ihc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d3b13ad75cc492690728f9307e443dec9ef9a20e", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1790477367, + "narHash": "sha256-oujbxmVKDhci2E4EM3KyAbRUgp5/IsCoiA/LfEF7OOk=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "f7cd230690d9fc982d06129f9189b101fddcfa3b", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "root": { + "inputs": { + "crane": "crane", + "flake-parts": "flake-parts", + "git-hooks-nix": "git-hooks-nix", + "komorebi-mac": "komorebi-mac", + "komorebi-windows": "komorebi-windows", + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay", + "treefmt-nix": "treefmt-nix" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1793086596, + "narHash": "sha256-ObKS44vw4IIVpQ69YJzUGjZ0IwnpWoUlwjJSY7gefdo=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "c7e9d512653a35ef4d5879c3df4d44d7b78d0e6d", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1791885023, + "narHash": "sha256-C3alQ2MEt0zVrUSho5NUDo3jmhbff72++bfwoqT9Omo=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "0d6d739a833ba9a9c93034862e4a7b061a062a1c", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..b677d619 --- /dev/null +++ b/flake.nix @@ -0,0 +1,359 @@ +{ + description = "komorebi-recorder: synchronized screen, log and trace capture for komorebi bug reproduction"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + flake-parts.url = "github:hercules-ci/flake-parts"; + crane.url = "github:ipetkov/crane"; + rust-overlay.url = "github:oxalica/rust-overlay"; + rust-overlay.inputs.nixpkgs.follows = "nixpkgs"; + treefmt-nix.url = "github:numtide/treefmt-nix"; + treefmt-nix.inputs.nixpkgs.follows = "nixpkgs"; + git-hooks-nix.url = "github:cachix/git-hooks.nix"; + git-hooks-nix.inputs.nixpkgs.follows = "nixpkgs"; + + # komorebi for Mac and komorebi for Windows: only their sources, which the recorder indexes so + # that `code` can map a line of a session's log to the statement that wrote it + komorebi-mac = { + url = "github:LGUG2Z/komorebi-for-mac"; + flake = false; + }; + komorebi-windows = { + url = "github:LGUG2Z/komorebi"; + flake = false; + }; + }; + + outputs = + inputs@{ + nixpkgs, + flake-parts, + crane, + rust-overlay, + ... + }: + let + windows = import ./nix/windows.nix; + + # the sources the recorder indexes for each flavor of komorebi (see komorebi-recorder/build.rs), + # which are also the trees the tests that read komorebi's source read + sourceEnv = { + KOMOREBI_MAC_SRC = "${inputs.komorebi-mac}"; + KOMOREBI_MAC_COMMIT = inputs.komorebi-mac.rev; + KOMOREBI_WINDOWS_SRC = "${inputs.komorebi-windows}"; + KOMOREBI_WINDOWS_COMMIT = inputs.komorebi-windows.rev; + }; + + version = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).workspace.package.version; + + # what the build needs of the repository: Cargo sources, and the files the crate embeds or + # its tests read + mkSource = + { pkgs, craneLib }: + pkgs.lib.cleanSourceWith { + src = ./.; + filter = + path: type: + (craneLib.filterCargoSources path type) + || (pkgs.lib.hasSuffix "/komorebi-recorder/src/guide.md" path) + || (pkgs.lib.hasInfix "/komorebi-recorder/tests/fixtures/" path); + }; + + mkPackages = + { pkgs }: + let + toolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; + craneLib = (crane.mkLib pkgs).overrideToolchain toolchain; + src = mkSource { inherit pkgs craneLib; }; + + commonArgs = { + inherit src version; + pname = "komorebi-recorder"; + strictDeps = true; + inherit (sourceEnv) + KOMOREBI_MAC_SRC + KOMOREBI_MAC_COMMIT + KOMOREBI_WINDOWS_SRC + KOMOREBI_WINDOWS_COMMIT + ; + nativeBuildInputs = [ + pkgs.darwin.cctools + ]; + postFixup = '' + for bin in $out/bin/*; do + if [ -f "$bin" ] && [ -x "$bin" ]; then + # Get all linked libraries and fix libiconv references + otool -L "$bin" | grep -o '/nix/store/[^/]*/lib/libiconv[^ ]*' | while read -r lib; do + install_name_tool -change "$lib" /usr/lib/libiconv.dylib "$bin" + done + fi + done + ''; + }; + + cargoArtifacts = craneLib.buildDepsOnly commonArgs; + + individualCrateArgs = commonArgs // { + inherit cargoArtifacts; + doCheck = false; + doDoc = false; + }; + + fullBuild = craneLib.buildPackage individualCrateArgs; + + # `komorebi-recorder-gui` is the same program as `komorebi-recorder` on a Mac + komorebi-recorder = pkgs.runCommand "komorebi-recorder" { meta = fullBuild.meta // { }; } '' + mkdir -p $out/bin + cp ${fullBuild}/bin/komorebi-recorder $out/bin/ + ''; + in + { + inherit + craneLib + src + individualCrateArgs + fullBuild + komorebi-recorder + ; + }; + + # komorebi-recorder for Windows, cross-compiled from this host + mkWindowsPackages = + { pkgs, windowsSdk }: + let + toolchain = (pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml).override { + targets = [ "x86_64-pc-windows-msvc" ]; + }; + craneLib = (crane.mkLib pkgs).overrideToolchain toolchain; + msvcEnv = windows.mkMsvcEnv { inherit pkgs windowsSdk; }; + src = mkSource { inherit pkgs craneLib; }; + + commonArgs = { + inherit src version; + pname = "komorebi-recorder-windows"; + strictDeps = true; + cargoExtraArgs = "--locked -p komorebi-recorder"; + inherit (sourceEnv) + KOMOREBI_MAC_SRC + KOMOREBI_MAC_COMMIT + KOMOREBI_WINDOWS_SRC + KOMOREBI_WINDOWS_COMMIT + ; + + nativeBuildInputs = [ + pkgs.llvmPackages.clang-unwrapped + pkgs.llvmPackages.lld + pkgs.llvmPackages.llvm + ]; + } + // msvcEnv; + + cargoArtifacts = craneLib.buildDepsOnly commonArgs; + individualCrateArgs = commonArgs // { + inherit cargoArtifacts; + doCheck = false; + doDoc = false; + }; + + komorebi-recorder = craneLib.buildPackage individualCrateArgs; + in + { + inherit + craneLib + individualCrateArgs + msvcEnv + komorebi-recorder + ; + }; + + mkPkgs = + system: + import nixpkgs { + inherit system; + overlays = [ (import rust-overlay) ]; + }; + in + flake-parts.lib.mkFlake { inherit inputs; } { + systems = [ + "aarch64-darwin" + "x86_64-darwin" + ]; + + imports = [ + inputs.treefmt-nix.flakeModule + inputs.git-hooks-nix.flakeModule + ]; + + perSystem = + { config, system, ... }: + let + pkgs = mkPkgs system; + build = mkPackages { inherit pkgs; }; + windowsSdk = windows.mkWindowsSdk { + inherit pkgs; + inherit (windows) windowsSdkVersion windowsCrtVersion; + }; + windowsBuild = mkWindowsPackages { inherit pkgs windowsSdk; }; + rustToolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; + nightlyRustfmt = pkgs.rust-bin.nightly.latest.rustfmt; + rustToolchainWithNightlyRustfmt = pkgs.symlinkJoin { + name = "rust-toolchain-with-nightly-rustfmt"; + paths = [ + nightlyRustfmt + rustToolchain + ]; + }; + in + { + treefmt = { + projectRootFile = "flake.nix"; + programs = { + deadnix.enable = true; + just.enable = true; + nixfmt.enable = true; + taplo.enable = true; + rustfmt = { + enable = true; + package = pkgs.rust-bin.nightly.latest.rustfmt; + }; + }; + }; + + checks = { + komorebi-recorder-clippy = build.craneLib.cargoClippy ( + build.individualCrateArgs + // { + cargoClippyExtraArgs = "--all-targets -- -D warnings"; + } + ); + + komorebi-recorder-fmt = build.craneLib.cargoFmt { + inherit (build) src; + pname = "komorebi-recorder"; + }; + + komorebi-recorder-toml-fmt = build.craneLib.taploFmt { + src = pkgs.lib.sources.sourceFilesBySuffices build.src [ ".toml" ]; + pname = "komorebi-recorder"; + }; + + komorebi-recorder-deny = build.craneLib.cargoDeny { + inherit (build) src; + pname = "komorebi-recorder"; + }; + + komorebi-recorder-nextest = build.craneLib.cargoNextest build.individualCrateArgs; + + # `--all-targets` so that every line of `cfg(windows)` code, tests included, is type-checked + # without a Windows machine + komorebi-recorder-windows-clippy = windowsBuild.craneLib.cargoClippy ( + windowsBuild.individualCrateArgs + // { + cargoClippyExtraArgs = "--all-targets -- -D warnings"; + } + ); + }; + + packages = { + inherit (build) komorebi-recorder; + inherit windowsSdk; + komorebi-recorder-windows = windowsBuild.komorebi-recorder; + default = build.komorebi-recorder; + }; + + apps = { + komorebi-recorder = { + type = "app"; + program = "${build.komorebi-recorder}/bin/komorebi-recorder"; + }; + default = { + type = "app"; + program = "${build.komorebi-recorder}/bin/komorebi-recorder"; + }; + }; + + devShells.default = pkgs.mkShell { + name = "komorebi-recorder"; + + RUST_BACKTRACE = "full"; + + inherit (sourceEnv) + KOMOREBI_MAC_SRC + KOMOREBI_MAC_COMMIT + KOMOREBI_WINDOWS_SRC + KOMOREBI_WINDOWS_COMMIT + ; + + inputsFrom = [ build.fullBuild ]; + + packages = [ + rustToolchainWithNightlyRustfmt + + pkgs.cargo-deny + pkgs.cargo-nextest + # `komorebi-recorder frames` and `selftest` extract frames with ffmpeg; it is never + # used for capture and is not bundled into the packaged binary + pkgs.ffmpeg-headless + pkgs.jq + pkgs.just + pkgs.ripgrep + ]; + }; + + # For working on the Windows side from a Mac: `nix develop .#windows`, then plain + # `cargo clippy --all-targets` (the target is already `x86_64-pc-windows-msvc`). + devShells.windows = pkgs.mkShell { + name = "komorebi-recorder-windows"; + + RUST_BACKTRACE = "full"; + + inherit (windowsBuild.msvcEnv) + CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER + CC_x86_64_pc_windows_msvc + CXX_x86_64_pc_windows_msvc + AR_x86_64_pc_windows_msvc + CFLAGS_x86_64_pc_windows_msvc + CXXFLAGS_x86_64_pc_windows_msvc + CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUSTFLAGS + CARGO_BUILD_TARGET + ; + inherit (sourceEnv) + KOMOREBI_MAC_SRC + KOMOREBI_MAC_COMMIT + KOMOREBI_WINDOWS_SRC + KOMOREBI_WINDOWS_COMMIT + ; + + packages = [ + (rustToolchain.override { targets = [ "x86_64-pc-windows-msvc" ]; }) + pkgs.llvmPackages.clang-unwrapped # provides clang-cl + pkgs.llvmPackages.lld # provides lld-link + pkgs.llvmPackages.llvm # provides llvm-lib + pkgs.cargo-deny + pkgs.just + ]; + }; + + pre-commit = { + check.enable = true; + settings.hooks.treefmt = { + enable = true; + package = config.treefmt.build.wrapper; + pass_filenames = false; + }; + }; + }; + + flake = { + overlays.default = + final: _: + let + pkgs = mkPkgs final.system; + build = mkPackages { inherit pkgs; }; + in + { + inherit (build) komorebi-recorder; + }; + }; + }; +} diff --git a/justfile b/justfile index 7477692c..d1e7dbb4 100644 --- a/justfile +++ b/justfile @@ -1,7 +1,7 @@ export RUST_BACKTRACE := "full" -# everything CI checks, in order -check: fmt-check clippy test doc deny +# everything CI checks, in order; run it inside `nix develop` (direnv does) +check: fmt-check clippy check-windows test doc deny # nightly rustfmt, which the devShell provides, and the macros this project does not allow fmt-check: @@ -20,6 +20,9 @@ fix: clippy: cargo clippy --workspace --all-targets --locked -- -D warnings +# type-check every `cfg(windows)` line, tests included, from a Mac (the Windows devShell targets x86_64-pc-windows-msvc) +check-windows: + nix develop .#windows --command cargo clippy --workspace --all-targets --locked -- -D warnings # lib, integration and doc tests; the ones that read komorebi's source need KOMOREBI_MAC_SRC, which `nix develop` sets test: @@ -28,6 +31,7 @@ test: # rustdoc with its warnings as errors, for both hosts: links in `cfg(windows)` docs are only checked on Windows doc: RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps --locked + nix develop .#windows --command env RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps --locked deny: cargo deny check @@ -48,6 +52,9 @@ run target: record *args: cargo run --bin komorebi-recorder --locked -- {{ args }} +# cross-compile komorebi-recorder.exe and komorebi-recorder-gui.exe into ./result-windows +build-windows: + nix build .#komorebi-recorder-windows --out-link result-windows deps: cargo update diff --git a/nix/windows.nix b/nix/windows.nix new file mode 100644 index 00000000..245ac568 --- /dev/null +++ b/nix/windows.nix @@ -0,0 +1,80 @@ +# Building for Windows (x86_64-pc-windows-msvc) from any host. +# +# The MSVC CRT and the Windows SDK come from xwin, the compiler and linker from LLVM, so nothing +# here needs a Windows machine. Copied from komorebi for Windows' own flake, with the same pinned +# versions. +{ + windowsSdkVersion = "10.0.26100"; + windowsCrtVersion = "14.44.17.14"; + + mkWindowsSdk = + { + pkgs, + windowsSdkVersion, + windowsCrtVersion, + }: + pkgs.stdenvNoCC.mkDerivation { + name = "windows-sdk-${windowsSdkVersion}-crt-${windowsCrtVersion}"; + + nativeBuildInputs = [ pkgs.xwin ]; + + outputHashAlgo = "sha256"; + outputHashMode = "recursive"; + # NOT the hash komorebi for Windows' own flake pins (sha256-6cLS5q1BDRpLPScfmmKpTTEHUzsgKTKD1+mKvGX9Deo=): + # that did not reproduce on aarch64-darwin on 2026-10-27 with xwin 0.7.0, which produced this one. + # Whether Microsoft re-published that SDK or the splat differs by host is not known. + outputHash = "sha256-YjmEfoxtcmQXvUc+WtaElnyP/4osNvtSI7X6MDaNTjg="; + + buildCommand = '' + export HOME=$(mktemp -d) + xwin --accept-license \ + --sdk-version ${windowsSdkVersion} \ + --crt-version ${windowsCrtVersion} \ + splat --output $out + ''; + }; + + mkMsvcEnv = + { pkgs, windowsSdk }: + let + clangVersion = pkgs.lib.versions.major pkgs.llvmPackages.clang.version; + includes = [ + # IMPORTANT: libclang include path MUST come first to avoid header conflicts + "/imsvc${pkgs.llvmPackages.libclang.lib}/lib/clang/${clangVersion}/include" + "/imsvc${windowsSdk}/crt/include" + "/imsvc${windowsSdk}/sdk/include/ucrt" + "/imsvc${windowsSdk}/sdk/include/um" + "/imsvc${windowsSdk}/sdk/include/shared" + ]; + cflags = builtins.concatStringsSep " " ( + [ + "--target=x86_64-pc-windows-msvc" + "-Wno-unused-command-line-argument" + "-fuse-ld=lld-link" + ] + ++ includes + ); + in + { + # linker for the windows target + CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER = "lld-link"; + + # c/c++ compiler + CC_x86_64_pc_windows_msvc = "clang-cl"; + CXX_x86_64_pc_windows_msvc = "clang-cl"; + AR_x86_64_pc_windows_msvc = "llvm-lib"; + CFLAGS_x86_64_pc_windows_msvc = cflags; + CXXFLAGS_x86_64_pc_windows_msvc = cflags; + + # target-specific rust flags with linker flavor and library search paths + CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUSTFLAGS = builtins.concatStringsSep " " [ + "-Clinker-flavor=lld-link" + "-Lnative=${windowsSdk}/crt/lib/x86_64" + "-Lnative=${windowsSdk}/sdk/lib/um/x86_64" + "-Lnative=${windowsSdk}/sdk/lib/ucrt/x86_64" + ]; + + # cargo target + CARGO_BUILD_TARGET = "x86_64-pc-windows-msvc"; + }; +}