{ description = "cargoxx"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; flake-utils.url = "github:numtide/flake-utils"; bundlers.url = "github:NixOS/bundlers"; bundlers.inputs.nixpkgs.follows = "nixpkgs"; }; outputs = { self, nixpkgs, flake-utils, bundlers }: flake-utils.lib.eachDefaultSystem (system: let pkgs = import nixpkgs { inherit system; }; # exec::run shells out to these at runtime; wrap the binary so # they're reachable even outside a nix develop shell. cargoxxRuntimePath = pkgs.lib.makeBinPath [ pkgs.nix pkgs.cmake pkgs.ninja pkgs.curl pkgs.git ]; # Defaults applied to the bundled `nix` so it works on hosts # that don't already have nix set up (Arch/Debian/Fedora users # who install our .pkg.tar.zst / .deb / .rpm). Multi-user mode # would expect a `nixbld` group and a running daemon cargoxxNixConfig = '' experimental-features = nix-command flakes build-users-group = ''; cargoxx-bin = pkgs.gcc15Stdenv.mkDerivation { pname = "cargoxx"; version = "0.1.0"; src = ./.; nativeBuildInputs = [ pkgs.cmake pkgs.ninja pkgs.makeWrapper ]; buildInputs = [ pkgs.sqlite pkgs.reproc pkgs.catch2_3 ]; configurePhase = '' cmake -S build -B build/release -G Ninja \ -DCMAKE_BUILD_TYPE=Release ''; buildPhase = '' cmake --build build/release ''; installPhase = '' mkdir -p $out/bin cp build/release/cargoxx $out/bin/ wrapProgram $out/bin/cargoxx \ --prefix PATH : ${cargoxxRuntimePath} \ --set-default NIX_CONFIG ${pkgs.lib.escapeShellArg cargoxxNixConfig} ''; hardeningDisable = [ "all" ]; }; buildCppPackage = { src, name ? null, ... }@args: let lock = builtins.fromTOML (builtins.readFile (src + "/Cargoxx.lock")); isDep = p: p ? linkdb_source; isRoot = p: !(isDep p); isCargoxxSource = p: (p.source_kind or "") != ""; root = builtins.head (builtins.filter isRoot lock.package); depPkgs = builtins.filter isDep lock.package; pname = if name != null then name else root.name; pkgsAt = rev: (builtins.getFlake "github:NixOS/nixpkgs/${rev}") .legacyPackages.${system}; # cargoxx-source deps recurse into buildCppPackage; the result # joins buildInputs so the consumer's find_package( CONFIG # REQUIRED) resolves via CMAKE_PREFIX_PATH. evalDep = p: if (p.source_kind or "") == "cargoxx-path" then buildCppPackage { src = src + ("/" + p.source_path); } else if (p.source_kind or "") == "cargoxx-git" then let depSrc = pkgs.fetchgit { url = p.source_git_url; rev = p.source_git_commit; hash = p.source_git_sha256; }; in buildCppPackage { src = depSrc; } else let rev = if (p ? nixpkgs_rev) && (p.nixpkgs_rev != "") then p.nixpkgs_rev else lock.nixpkgs_rev; in (pkgsAt rev).${p.nixpkgs_attr}; depInputs = map evalDep depPkgs; usesPkgConfig = builtins.any (p: (p.linkdb_source or "") == "pkg-config") depPkgs; nixpkgsSource = (builtins.getFlake "github:NixOS/nixpkgs/${lock.nixpkgs_rev}").outPath; flakeUtilsSource = (builtins.getFlake "github:numtide/flake-utils/${lock.flake_utils_rev}").outPath; mkDepTomlEntry = p: let derivation = evalDep p; # For cargoxx-source deps we don't have a nixpkgs rev/attr — the # vendor.toml entry just needs a name + store_path so cargoxx's # offline pathway can find the dep's installed prefix. isCargoxx = (p.source_kind or "") != ""; attr = if isCargoxx then "" else p.nixpkgs_attr; rev = if isCargoxx then "" else if (p ? nixpkgs_rev) && (p.nixpkgs_rev != "") then p.nixpkgs_rev else lock.nixpkgs_rev; in '' [[dep]] name = "${p.name}" nixpkgs_attr = "${attr}" nixpkgs_rev = "${rev}" store_path = "${derivation}" ''; vendorToml = pkgs.writeText "vendor.toml" ('' schema = 1 [nixpkgs] rev = "${lock.nixpkgs_rev}" store_path = "${nixpkgsSource}" [flake_utils] rev = "${lock.flake_utils_rev}" store_path = "${flakeUtilsSource}" '' + builtins.concatStringsSep "\n" (map mkDepTomlEntry depPkgs)); in pkgs.gcc15Stdenv.mkDerivation { inherit pname src; version = root.version; nativeBuildInputs = [ cargoxx-bin pkgs.cmake pkgs.ninja ] ++ pkgs.lib.optional usesPkgConfig pkgs.pkg-config; buildInputs = depInputs; dontConfigure = true; buildPhase = '' export HOME=$(mktemp -d) cargoxx build --release --offline --vendor ${vendorToml} ''; installPhase = '' cmake --install build/release --prefix $out ''; hardeningDisable = [ "all" ]; }; bundlers-sys = bundlers.bundlers.${system}; # Arch's pacman expects a tar.zst archive containing a # `.PKGINFO` metadata file plus the file tree rooted at /. # We ship the entire closure under /nix/store; /usr/bin/cargoxx # is a symlink to the in-store wrapper. toArchPkg = drv: let pname = drv.pname or drv.name; version = drv.version or "0"; mainProgram = drv.meta.mainProgram or pname; in pkgs.runCommand "${pname}-${version}-1-x86_64.pkg.tar.zst" { nativeBuildInputs = [ pkgs.libarchive pkgs.coreutils ]; closureInfo = pkgs.closureInfo { rootPaths = [ drv ]; }; } '' stage=$(mktemp -d) mkdir -p $stage/nix/store $stage/usr/bin for p in $(cat $closureInfo/store-paths); do cp -a "$p" $stage/nix/store/ done ln -s ${drv}/bin/${mainProgram} $stage/usr/bin/${mainProgram} installed_size=$(du -sk $stage | cut -f1) cat > $stage/.PKGINFO < drv`. # Mirror the `to*` naming used by github:NixOS/bundlers. lib.toAppImage = bundlers-sys.toAppImage; lib.toDockerImage = bundlers-sys.toDockerImage; lib.toDEB = bundlers-sys.toDEB; lib.toRPM = bundlers-sys.toRPM; lib.toArchPkg = toArchPkg; lib.buildCppPackage = buildCppPackage; devShells.default = pkgs.gcc15Stdenv.mkDerivation { name = "cargoxx-dev"; version = "0.1.0"; nativeBuildInputs = [ pkgs.ninja pkgs.cmake ]; buildInputs = [ pkgs.reproc pkgs.sqlite pkgs.catch2_3 ]; hardeningDisable = [ "all" ]; }; }); }