# Cargo.nix and crate-hashes.json were created with: # - `nix run '.#crate2nix' -- generate -f ~/ref/repos/gnome/fractal/Cargo.toml` # or, for devel crate2nix: # - `nix shell -f https://github.com/kolloch/crate2nix/tarball/master` # - `crate2nix generate -f ~/ref/repos/gnome/fractal/Cargo.toml` # # to update: # - `git fetch` in `~/ref/repos/gnome/fractal/` # - re-run that crate2nix step # - update `src` rev to match the local checkout! { pkgs , lib , stdenv , appstream-glib , buildPackages , cargo , defaultCrateOverrides , desktop-file-utils , fetchFromGitHub , gdk-pixbuf , glib , gst_all_1 , gtk4 , gtksourceview5 , libadwaita , libshumate , meson , ninja , openssl , pipewire , pkg-config , rust , rustPlatform , sqlite , wrapGAppsHook4 , writeText , xdg-desktop-portal , optimize ? true , crateOverrideFn ? x: x }: let mkConfigured = { optimize }: let # `optimize` option applies only to the top-level build; not fractal's dependencies. # as of 2023/10/29: # - opt-level=0: builds in 1min, 105M binary # - opt-level=1: builds in 2.25hr, 75M binary # - opt-level=2: builds in 2.25hr # - opt-level=3: builds in 2.25hr, 68-70M binary # as of 2023/10/30: # - opt-level=3: builds in 5min, 71M binary optFlags = if optimize then "-C opt-level=3" else "-C opt-level=0"; extraCrateOverrides = { fractal = attrs: attrs // { src = pkgs.fetchFromGitLab { domain = "gitlab.gnome.org"; owner = "GNOME"; repo = "fractal"; rev = "6"; hash = "sha256-J4Jb7G5Rfou3N7mytetIdLl0dGY5dSvTjnu8aj4kWXQ="; # rev = "5"; # hash = "sha256-XHb8HjQ5PDL2sen6qUivDllvYEhKnp1vQynD2Lksi30="; }; codegenUnits = 256; #< this does get plumbed, but doesn't seem to affect build speed outputs = [ "out" ]; # default is "out" and "lib", but that somehow causes cycles outputDev = [ "out" ]; nativeBuildInputs = [ appstream-glib # optional, for validation desktop-file-utils # for update-desktop-database glib # for glib-compile-resources, gettext gtk4 # for gtk4-update-icon-cache meson ninja pkg-config wrapGAppsHook4 ]; buildInputs = [ glib gst_all_1.gst-plugins-bad gst_all_1.gst-plugins-base gst_all_1.gst-plugins-good gst_all_1.gstreamer gtk4 gtksourceview5 libadwaita libshumate openssl pipewire sqlite xdg-desktop-portal ]; mesonFlags = let # this gets meson to shutup about rustc not producing executables. # kinda silly though, since we patch out the actual cargo (rustc) invocations. crossFile = writeText "cross-file.conf" '' [binaries] rust = [ 'rustc', '--target', '${rust.toRustTargetSpec stdenv.hostPlatform}' ] ''; in lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [ "--cross-file=${crossFile}" ]; # patch so meson will invoke our `crate2nix_cmd.sh` instead of cargo postPatch = '' substituteInPlace src/meson.build \ --replace 'cargo_options,' "" \ --replace "cargo, 'build'," "'bash', 'crate2nix_cmd.sh'," \ --replace "'src' / rust_target" "'target/bin'" ''; postConfigure = '' # copied from mesonFlags="--prefix=$prefix $mesonFlags" mesonFlags="\ --libdir=''${!outputLib}/lib --libexecdir=''${!outputLib}/libexec \ --bindir=''${!outputBin}/bin --sbindir=''${!outputBin}/sbin \ --includedir=''${!outputInclude}/include \ --mandir=''${!outputMan}/share/man --infodir=''${!outputInfo}/share/info \ --localedir=''${!outputLib}/share/locale \ -Dauto_features=''${mesonAutoFeatures:-enabled} \ -Dwrap_mode=''${mesonWrapMode:-nodownload} \ $mesonFlags" mesonFlags="''${crossMesonFlags+$crossMesonFlags }--buildtype=''${mesonBuildType:-plain} $mesonFlags" echo "meson flags: $mesonFlags ''${mesonFlagsArray[@]}" meson setup build $mesonFlags "''${mesonFlagsArray[@]}" cd build ''; preBuild = '' build_bin() { # build_bin is what buildRustCrate would use to invoke rustc, but we want to drive the build # with meson instead. however, meson doesn't know how to plumb our rust dependencies into cargo, # so we still need to use build_bin for just one portion of the build. # # so, this mocks out the original build_bin: # - we patch upstream fractal to call our `crate2nix_cmd.sh` when it wants to compile the rust. # - we don't actually invoke meson (ninja) at all here, but rather in the `installPhase`. # if we invoked it here, the whole build would just get re-done in installPhase anyway. # # rustc invocation copied from crate_name_=fractal main_file=../src/main.rs fix_link="-C linker=${stdenv.cc}/bin/${stdenv.cc.targetPrefix}cc" EXTRA_RUSTC_FLAGS="$EXTRA_RUSTC_FLAGS ${optFlags}" cat >> crate2nix_cmd.sh < assertion `left == right` failed # > left: "ring_core_0_17_5" # > right: "ring_core_0_17_7" # ``` # just update this patch to reflect the right-hand side # CARGO_MANIFEST_LINKS = "ring_core_0_17_7"; postPatch = (attrs.postPatch or "") + '' substituteInPlace build.rs --replace \ 'links = std::env::var("CARGO_MANIFEST_LINKS").unwrap();' 'links = "ring_core_0_17_7".to_string();' ''; }; sourceview5-sys = attrs: attrs // { nativeBuildInputs = [ pkg-config ]; buildInputs = [ gtksourceview5 ]; }; }; defaultCrateOverrides' = defaultCrateOverrides // (lib.mapAttrs (crate: fn: # map each `extraCrateOverrides` to first pass their attrs through `defaultCrateOverrides` attrs: fn ((defaultCrateOverrides."${crate}" or (a: a)) attrs) ) extraCrateOverrides); crate2NixOverrides = crates: crates // { # crate2nix sometimes "misses" dependencies, or gets them wrong in a way that crateOverrides can't patch. # this function lets me patch over Cargo.nix without actually modifying it by hand. matrix-sdk = crates.matrix-sdk // { dependencies = crates.matrix-sdk.dependencies ++ [ { name = "ruma-events"; packageId = "ruma-events"; } ]; }; matrix-sdk-base = crates.matrix-sdk-base // { dependencies = crates.matrix-sdk-base.dependencies ++ [ { name = "ruma-events"; packageId = "ruma-events"; } ]; }; matrix-sdk-crypto = crates.matrix-sdk-crypto // { dependencies = crates.matrix-sdk-crypto.dependencies ++ [ { name = "ruma-common"; packageId = "ruma-common"; } ]; }; }; cargoNix = import ./Cargo.nix { inherit pkgs; release = false; #< XXX(2023/12/06): `release=true` is incompatible with cross compilation rootFeatures = [ ]; #< avoids --cfg feature="default", simplifying the rustc CLI so that i can pass it around easier defaultCrateOverrides = defaultCrateOverrides'; }; builtCrates = cargoNix.internal.builtRustCratesWithFeatures { packageId = "fractal"; features = []; buildRustCrateForPkgsFunc = pkgs: crateArgs: let crateDeriv = (pkgs.buildRustCrate.override { defaultCrateOverrides = defaultCrateOverrides'; }) crateArgs; in crateOverrideFn crateDeriv; crateConfigs = crate2NixOverrides cargoNix.internal.crates; runTests = false; }; fractalDefault = builtCrates.crates.fractal; in fractalDefault.overrideAttrs (super: { passthru = (super.passthru or {}) // { optimized = mkConfigured { optimize = true; }; unoptimized = mkConfigured { optimize = false; }; inherit (builtCrates) crates; }; }); in mkConfigured { inherit optimize; }