From ce0788389bdce5913800d060ed4b67a282124596 Mon Sep 17 00:00:00 2001 From: Matus Mastena Date: Sat, 12 Sep 2026 16:20:16 +0200 Subject: [PATCH] Add a Nix flake for the dev shell and package build The devShell carries the toolchain plus the X11, Wayland, Vulkan, fontconfig and freetype libraries winit and wgpu dlopen at run time, and the trunk/wasm-bindgen pair the web build needs. LD_LIBRARY_PATH is set there too, since a dev binary runs straight out of ./target and never gets the wrapper the package build applies. The four git dependencies each need an entry in cargoLock.outputHashes. They are lib.fakeHash for now; the first `nix build` prints the real values, and they have to be refreshed whenever a rev in Cargo.toml moves. --- .envrc | 1 + .gitignore | 3 ++ flake.nix | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 .envrc create mode 100644 flake.nix diff --git a/.envrc b/.envrc new file mode 100644 index 000000000..3550a30f2 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore index 80e292024..46903fb6d 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ __pycache__/ # Claude Code local preview/dev-server config .claude/launch.json + +# nix-direnv +.direnv/ diff --git a/flake.nix b/flake.nix new file mode 100644 index 000000000..fd09ceec8 --- /dev/null +++ b/flake.nix @@ -0,0 +1,151 @@ +{ + description = "Open CAD Studio - 2D drafting and 3D modeling in Rust"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + # rust-overlay ships upstream Rust binaries rather than building them, so + # following nixpkgs costs it no binary cache. + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { self, nixpkgs, rust-overlay }: + let + systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; + forAllSystems = f: + nixpkgs.lib.genAttrs systems (system: f (import nixpkgs { + inherit system; + overlays = [ rust-overlay.overlays.default ]; + })); + in + { + packages = forAllSystems (pkgs: + let + inherit (pkgs) lib stdenv; + + toolchain = pkgs.rust-bin.stable.latest.default.override { + targets = [ "wasm32-unknown-unknown" ]; + }; + + # Build with the overlay's toolchain rather than the nixpkgs default, + # so the package and the devShell compile with the same rustc. + rustPlatform = pkgs.makeRustPlatform { + cargo = toolchain; + rustc = toolchain; + }; + + # winit/wgpu dlopen these at run time, so they must also be on the + # wrapped binary's LD_LIBRARY_PATH, not just at link time. + runtimeLibs = with pkgs; [ + libGL + libxkbcommon + vulkan-loader + wayland + xorg.libX11 + xorg.libXcursor + xorg.libXi + xorg.libXrandr + ]; + in + rec { + default = opencadstudio; + + opencadstudio = rustPlatform.buildRustPackage { + pname = "opencadstudio"; + version = (lib.importTOML ./Cargo.toml).package.version; + src = self; + + cargoLock = { + lockFile = ./Cargo.lock; + # One entry per distinct git source in Cargo.lock. Replace each + # lib.fakeHash with the sha256 that `nix build` prints on the + # first attempt; they must be refreshed whenever the matching + # rev in Cargo.toml moves. + outputHashes = { + "acadrust-0.5.5" = lib.fakeHash; + "cadkernel-0.1.0" = lib.fakeHash; + "iced-0.15.0-dev" = lib.fakeHash; + "iced_aw-0.14.1" = lib.fakeHash; + }; + }; + + nativeBuildInputs = with pkgs; [ + pkg-config + makeWrapper + ]; + + buildInputs = with pkgs; [ + fontconfig + freetype + ] ++ runtimeLibs + ++ lib.optionals stdenv.hostPlatform.isDarwin [ darwin.apple_sdk.frameworks.AppKit ]; + + # build.rs asks git for a revision and falls back to "unknown" + # when the repo or the binary is absent, which it is in the + # sandbox. Nothing to do but let it take the fallback. + doCheck = false; + + postInstall = lib.optionalString stdenv.hostPlatform.isLinux '' + wrapProgram $out/bin/OpenCADStudio \ + --prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath runtimeLibs} + ''; + + meta = { + description = "Open-source 2D drafting and 3D modeling, built with Rust"; + homepage = "https://www.opencadstudio.com"; + license = lib.licenses.gpl3Only; + mainProgram = "OpenCADStudio"; + platforms = systems; + }; + }; + }); + + devShells = forAllSystems (pkgs: + let + toolchain = pkgs.rust-bin.stable.latest.default.override { + extensions = [ "rust-src" "rust-analyzer" "clippy" "rustfmt" ]; + targets = [ "wasm32-unknown-unknown" ]; + }; + runtimeLibs = with pkgs; [ + libGL + libxkbcommon + vulkan-loader + wayland + xorg.libX11 + xorg.libXcursor + xorg.libXi + xorg.libXrandr + ]; + in + { + default = pkgs.mkShell { + packages = with pkgs; [ + toolchain + pkg-config + fontconfig + freetype + git + # Web build: `trunk build` per Trunk.toml. wasm-bindgen-cli must + # match the wasm-bindgen version Cargo.lock resolves, the same + # constraint .github/workflows/pages.yml:83 reads out of the lock. + trunk + wasm-bindgen-cli + # Rasterises assets/logo.svg for packaging, as release.yml does. + librsvg + ] ++ runtimeLibs; + + # A dev binary is run straight out of ./target, so it never gets + # the wrapper the package build applies. + LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath runtimeLibs; + }; + }); + + checks = forAllSystems (pkgs: { + default = self.packages.${pkgs.stdenv.hostPlatform.system}.opencadstudio; + }); + + formatter = forAllSystems (pkgs: pkgs.nixpkgs-fmt); + }; +}