at main 307 lines 10 kB view raw
1{ 2 description = "Build a cargo workspace"; 3 4 inputs = { 5 nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; 6 flake-utils.url = "github:numtide/flake-utils"; 7 8 advisory-db = { 9 url = "github:rustsec/advisory-db"; 10 flake = false; 11 }; 12 13 rust-overlay.url = "github:oxalica/rust-overlay"; 14 crane.url = "github:ipetkov/crane"; 15 dioxus.url = "github:DioxusLabs/dioxus"; 16 }; 17 18 outputs = { 19 self, 20 nixpkgs, 21 crane, 22 rust-overlay, 23 flake-utils, 24 advisory-db, 25 dioxus, 26 ... 27 }: let 28 name = "weaver"; 29 in 30 flake-utils.lib.eachDefaultSystem (system: let 31 pkgs = import nixpkgs { 32 inherit system; 33 overlays = [ 34 (import rust-overlay) 35 (_: prev: { 36 dioxus-cli = dioxus.packages.${prev.system}.dioxus-cli; 37 }) 38 ]; 39 }; 40 inherit (pkgs) lib; 41 42 rustToolchainFor = p: 43 p.rust-bin.selectLatestNightlyWith (toolchain: 44 toolchain.default.override { 45 # Set the build targets supported by the toolchain, 46 # wasm32-unknown-unknown is required for trunk. 47 targets = ["wasm32-unknown-unknown" "wasm32-wasip1" "wasm32-wasip2"]; 48 extensions = [ 49 "rust-src" 50 "rust-analyzer" 51 "clippy" 52 ]; 53 }); 54 craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchainFor; 55 src = craneLib.cleanCargoSource ./.; 56 57 # Common arguments can be set here to avoid repeating them later 58 commonArgs = { 59 inherit src; 60 strictDeps = true; 61 62 buildInputs = with pkgs; 63 [ 64 # Add additional build inputs here 65 sqlite 66 pkg-config 67 openssl 68 ] 69 ++ lib.optionals pkgs.stdenv.isDarwin [ 70 # Additional darwin specific inputs can be set here 71 pkgs.libiconv 72 ]; 73 nativeBuildInputs = with pkgs; [ 74 sqlite 75 pkg-config 76 openssl 77 ]; 78 # Additional environment variables can be set directly 79 # MY_CUSTOM_VAR = "some value"; 80 }; 81 82 # Build *just* the cargo dependencies (of the entire workspace), 83 # so we can reuse all of that work (e.g. via cachix) when running in CI 84 # It is *highly* recommended to use something like cargo-hakari to avoid 85 # cache misses when building individual top-level-crates 86 cargoArtifacts = craneLib.buildDepsOnly commonArgs; 87 88 individualCrateArgs = 89 commonArgs 90 // { 91 inherit cargoArtifacts; 92 inherit (craneLib.crateNameFromCargoToml {inherit src;}) version; 93 # NB: we disable tests since we'll run them all via cargo-nextest 94 doCheck = false; 95 }; 96 97 fileSetForCrate = crate: 98 lib.fileset.toSource { 99 root = ./.; 100 fileset = lib.fileset.unions [ 101 ./Cargo.toml 102 ./Cargo.lock 103 (lib.fileset.maybeMissing ./crates/weaver-app/Dioxus.lock) 104 (craneLib.fileset.commonCargoSources ./crates/weaver-common) 105 (craneLib.fileset.commonCargoSources crate) 106 ]; 107 }; 108 109 # Build the top-level crates of the workspace as individual derivations. 110 # This allows consumers to only depend on (and build) only what they need. 111 # Though it is possible to build the entire workspace as a single derivation, 112 # so this is left up to you on how to organize things 113 # 114 # Note that the cargo workspace must define `workspace.members` using wildcards, 115 # otherwise, omitting a crate (like we do below) will result in errors since 116 # cargo won't be able to find the sources for all members. 117 weaver-cli = craneLib.buildPackage (individualCrateArgs 118 // { 119 pname = "${name}"; 120 cargoExtraArgs = "-p ${name}-cli"; 121 src = fileSetForCrate ./crates/weaver-cli; 122 }); 123 weaver-app = craneLib.buildPackage (individualCrateArgs 124 // { 125 pname = "${name}-app"; 126 cargoExtraArgs = "-p ${name}-app"; 127 src = fileSetForCrate ./crates/weaver-app; 128 }); 129 weaver-renderer = craneLib.buildPackage (individualCrateArgs 130 // { 131 pname = "${name}-renderer"; 132 cargoExtraArgs = "-p ${name}-renderer"; 133 src = fileSetForCrate ./crates/weaver-renderer; 134 }); 135 in { 136 checks = { 137 # Build the crates as part of `nix flake check` for convenience 138 inherit weaver-cli weaver-app weaver-renderer; 139 140 # Run clippy (and deny all warnings) on the workspace source, 141 # again, reusing the dependency artifacts from above. 142 # 143 # Note that this is done as a separate derivation so that 144 # we can block the CI if there are issues here, but not 145 # prevent downstream consumers from building our crate by itself. 146 "${name}-workspace-clippy" = craneLib.cargoClippy (commonArgs 147 // { 148 inherit cargoArtifacts; 149 cargoClippyExtraArgs = "--all-targets -- --deny warnings"; 150 }); 151 152 "${name}-workspace-doc" = craneLib.cargoDoc (commonArgs 153 // { 154 inherit cargoArtifacts; 155 }); 156 157 # Check formatting 158 "${name}-workspace-fmt" = craneLib.cargoFmt { 159 inherit src; 160 }; 161 162 # "${name}-workspace-toml-fmt" = craneLib.taploFmt { 163 # src = pkgs.lib.sources.sourceFilesBySuffices src [".toml"]; 164 # # taplo arguments can be further customized below as needed 165 # taploExtraArgs = "--config ./taplo.toml"; 166 # }; 167 168 # Audit dependencies 169 "${name}-workspace-audit" = craneLib.cargoAudit { 170 inherit src advisory-db; 171 }; 172 173 # Audit licenses 174 "${name}-workspace-deny" = craneLib.cargoDeny { 175 inherit src; 176 }; 177 178 # Run tests with cargo-nextest 179 # Consider setting `doCheck = false` on other crate derivations 180 # if you do not want the tests to run twice 181 "${name}-workspace-nextest" = craneLib.cargoNextest (commonArgs 182 // { 183 inherit cargoArtifacts; 184 partitions = 1; 185 partitionType = "count"; 186 cargoNextestPartitionsExtraArgs = "--no-tests=pass"; 187 }); 188 }; 189 190 packages = 191 { 192 inherit weaver-cli weaver-app; 193 } 194 // lib.optionalAttrs (!pkgs.stdenv.isDarwin) { 195 # weaver-workspace-llvm-coverage = craneLibLLvmTools.cargoLlvmCov (commonArgs // { 196 # inherit cargoArtifacts; 197 # }); 198 }; 199 200 apps = { 201 weaver-cli = flake-utils.lib.mkApp { 202 drv = weaver-cli; 203 }; 204 weaver-app = flake-utils.lib.mkApp { 205 drv = weaver-app; 206 }; 207 }; 208 209 devShells.default = let 210 # dioxus-cli = pkgs.dioxus-cli.overrideAttrs (_: { 211 # postPatch = '' 212 # rm Cargo.lock 213 # cp ${./crates/weaver-app/Dioxus.lock} Cargo.lock 214 # ''; 215 # cargoDeps = pkgs.rustPlatform.importCargoLock { 216 # lockFile = ./crates/weaver-app/Dioxus.lock; 217 # }; 218 # }); 219 cargoLock = builtins.fromTOML (builtins.readFile ./Cargo.lock); 220 221 wasmBindgen = 222 pkgs.lib.findFirst 223 (pkg: pkg.name == "wasm-bindgen") 224 (throw "Could not find wasm-bindgen package") 225 cargoLock.package; 226 227 wasm-bindgen-cli = pkgs.buildWasmBindgenCli rec { 228 src = pkgs.fetchCrate { 229 pname = "wasm-bindgen-cli"; 230 version = wasmBindgen.version; 231 hash = "sha256-M6WuGl7EruNopHZbqBpucu4RWz44/MSdv6f0zkYw+44="; 232 }; 233 234 cargoDeps = pkgs.rustPlatform.fetchCargoVendor { 235 inherit src; 236 inherit (src) pname version; 237 hash = "sha256-ElDatyOwdKwHg3bNH/1pcxKI7LXkhsotlDPQjiLHBwA="; 238 }; 239 }; 240 in 241 craneLib.devShell { 242 inherit name; 243 # Inherit inputs from checks. 244 checks = self.checks.${system}; 245 NIX_LD_LIBRARY_PATH = with pkgs; 246 lib.makeLibraryPath [ 247 stdenv.cc.cc 248 openssl 249 # ... 250 ]; 251 NIX_LD = lib.fileContents "${pkgs.stdenv.cc}/nix-support/dynamic-linker"; 252 253 LD_LIBRARY_PATH = "$LD_LIBRARY_PATH:$NIX_LD_LIBRARY_PATH"; 254 255 # musl linker for static builds 256 #CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER = "${pkgs.pkgsMusl.stdenv.cc}/bin/cc"; 257 258 # Additional dev-shell environment variables can be set directly 259 # MY_CUSTOM_DEVELOPMENT_VAR = "something else"; 260 261 # Extra inputs can be added here; cargo and rustc are provided by default. 262 packages = with pkgs; [ 263 nixd 264 alejandra 265 diesel-cli 266 postgresql 267 cargo-insta 268 cargo-bloat 269 jq 270 dioxus-cli 271 wasm-bindgen-cli 272 wasm-pack 273 twiggy 274 binaryen.out 275 patchelf 276 llvmPackages_18.clang-unwrapped 277 llvmPackages_18.llvm 278 llvmPackages_18.libclang 279 wabt 280 ]; 281 282 nativeBuildInputs = [pkgs.llvmPackages_18.clang-unwrapped pkgs.llvmPackages_18.bintools-unwrapped]; 283 284 shellHook = '' 285 export CC_wasm32_unknown_unknown="${pkgs.llvmPackages_18.clang-unwrapped}/bin/clang" 286 export AR_wasm32_unknown_unknown="${pkgs.llvmPackages_18.bintools-unwrapped}/bin/llvm-ar" 287 CLANG_MAJOR_VERSION="18" 288 CLANG_RESOURCE_DIR="${pkgs.llvmPackages_18.clang-unwrapped}/lib/clang/$CLANG_MAJOR_VERSION" 289 290 # Use libclang's include directory which has the standard headers 291 LIBCLANG_INCLUDE="${pkgs.llvmPackages_18.libclang.lib}/lib/clang/$CLANG_MAJOR_VERSION/include" 292 293 export CFLAGS_wasm32_unknown_unknown="-isystem $LIBCLANG_INCLUDE -resource-dir $CLANG_RESOURCE_DIR" 294 export CPPFLAGS="-isystem $LIBCLANG_INCLUDE -resource-dir $CLANG_RESOURCE_DIR" 295 296 # Debug: Print the paths to verify they exist 297 echo "Clang resource dir: $CLANG_RESOURCE_DIR" 298 echo "Libclang include dir: $LIBCLANG_INCLUDE" 299 if [ -f "$LIBCLANG_INCLUDE/stddef.h" ]; then 300 echo "Found stddef.h at: $LIBCLANG_INCLUDE/stddef.h" 301 else 302 echo "stddef.h not found in $LIBCLANG_INCLUDE" 303 fi 304 ''; 305 }; 306 }); 307}