Add support for prebuilt dependencies

This commit is contained in:
Nicolas Mattia 2019-07-04 16:34:33 +02:00
parent 9787ccbeee
commit 4022afd8b9
6 changed files with 150 additions and 118 deletions

View file

@ -1,10 +1,10 @@
src:
{ #| What command to run during the build phase
cargoBuild ? "cargo build --frozen --$CARGO_BUILD_PROFILE -j $NIX_BUILD_CORES"
cargoBuild ? "cargo build --$CARGO_BUILD_PROFILE -j $NIX_BUILD_CORES"
, #| What command to run during the test phase
cargoTest ? "cargo test --$CARGO_BUILD_PROFILE"
, doCheck ? true
, name ? null
, name
, rustc
, cargo
, override ? null
@ -24,12 +24,10 @@ src:
, symlinkJoin
, runCommand
, remarshal
, crateDependencies
, cratePaths
}:
with
{ libb = import ./lib.nix { inherit lib writeText runCommand remarshal; };
};
with
{ builtinz =
builtins //
@ -37,49 +35,23 @@ with
{ inherit writeText remarshal runCommand ; };
};
with
{ cargolock =
if isNull cargolockPath then
builtinz.readTOML "${src}/Cargo.lock"
else
builtinz.readTOML cargolockPath;
cargotoml =
if isNull cargotomlPath then
builtinz.readTOML "${src}/Cargo.toml"
else
builtinz.readTOML cargotomlPath;
};
with rec
{
drv = stdenv.mkDerivation
{ inherit src doCheck nativeBuildInputs cargolockPath cargotomlPath;
{ inherit
src
doCheck
nativeBuildInputs
cargolockPath
cargotomlPath
cratePaths
name;
CARGO_BUILD_PROFILE = if release then "release" else "debug";
# The list of paths to Cargo.tomls. If this is a workspace, the paths
# are the members. Otherwise, there is a single path, ".".
cratePaths =
with rec
{ workspaceMembers = cargotoml.workspace.members or null;
};
if isNull workspaceMembers then "."
else lib.concatStringsSep "\n" workspaceMembers;
# Otherwise specifying CMake as a dep breaks the build
dontUseCmakeConfigure = true;
name =
if ! isNull name then
name
else if lib.length crateNames == 0 then
abort "No crate names"
else if lib.length crateNames == 1 then
lib.head crateNames
else
lib.head crateNames + "-et-al";
buildInputs =
[ cargo
@ -89,9 +61,8 @@ with rec
# needed for "cc"
llvmPackages.stdenv.cc
# needed for "cc"
# needed at various steps in the build
jq
rsync
] ++ (stdenv.lib.optionals stdenv.isDarwin
[ darwin.Security
@ -129,7 +100,7 @@ with rec
mkdir -p target
cat ${writeText "deps" (builtins.toJSON builtDependencies)} |\
cat ${builtinz.writeJSON "deps" builtDependencies} |\
jq -r '.[]' |\
while IFS= read -r dep
do
@ -180,7 +151,7 @@ with rec
# "--$CARGO_BUILD_PROFILE" like we do with "cargo build" and "cargo
# test"
install_arg=""
if "$CARGO_BUILD_PROFILE" == "debug"
if [ "$CARGO_BUILD_PROFILE" == "debug" ]
then
install_arg="--debug"
fi
@ -189,7 +160,11 @@ with rec
for p in "$cratePaths"; do
# XXX: we don't quote install_arg to avoid passing an empty arg
# to cargo
cargo install --path $p $install_arg --bins --root $out ||\
cargo install \
--path $p \
$install_arg \
--bins \
--root $out ||\
echo "WARNING: Member wasn't installed: $p"
done
@ -222,36 +197,16 @@ with rec
echo '{"package":"${sha256}","files":{}}' > $out/${name}-${version}/.cargo-checksum.json
'';
# creates a forest of symlinks of all the dependencies XXX: this is very
# basic and means that we have very little incrementality; e.g. when
# anything changes all the deps will be rebuilt. The rustc compiler is
# pretty fast so this is not too bad. In the future we'll want to pre-build
# the crates and give cargo a pre-populated ./target directory.
mkSnapshotForest =
symlinkJoin
{ name = "crates-io";
paths = map (v: unpackCrate v.name v.version v.sha256)
(libb.mkVersions cargolock);
};
# All the Cargo.tomls, including the top-level one
cargotomls =
with rec
{ workspaceMembers = cargotoml.workspace.members or [];
};
[cargotoml] ++ (
map (member: (builtinz.readTOML "${src}/${member}/Cargo.toml"))
workspaceMembers);
crateNames = builtins.filter (pname: ! isNull pname) (
map (ctoml: ctoml.package.name or null) cargotomls);
cargoconfig = builtinz.writeTOML
{ source =
{ crates-io = { replace-with = "nix-sources"; } ;
nix-sources =
{ directory = mkSnapshotForest; };
{ directory = symlinkJoin
{ name = "crates-io";
paths = map (v: unpackCrate v.name v.version v.sha256)
crateDependencies;
};
};
};
};
};

View file

@ -15,6 +15,7 @@
-of json \
-o $out
''));
writeTOML = attrs: runCommand "write-toml"
{ buildInputs = [ remarshal ]; }
''
@ -24,4 +25,7 @@
-of toml \
-o $out
'';
writeJSON = name: attrs: writeText name
(builtins.toJSON attrs);
}

View file

@ -15,50 +15,117 @@
with
{ libb = import ./lib.nix { inherit lib writeText runCommand remarshal; }; };
with
{ defaultBuildAttrs =
{ inherit
llvmPackages
jq
runCommand
lib
darwin
writeText
stdenv
rsync
remarshal
symlinkJoin
cargo
rustc;
};
};
with
{ builtinz =
builtins //
import ./builtins.nix
{ inherit writeText remarshal runCommand ; };
};
# Crate building
with rec
{
commonAttrs = src: attrs: rec
{ cargolockPath = attrs.cargolockPath or null;
cargotomlPath = attrs.cargotomlPath or null;
cargolock =
if isNull cargolockPath then
builtinz.readTOML "${src}/Cargo.lock"
else
builtinz.readTOML cargolockPath;
cargotoml =
if isNull cargotomlPath then
builtinz.readTOML "${src}/Cargo.toml"
else
builtinz.readTOML cargotomlPath;
# The list of paths to Cargo.tomls. If this is a workspace, the paths
# are the members. Otherwise, there is a single path, ".".
cratePaths =
with rec
{ workspaceMembers = cargotoml.workspace.members or null;
};
if isNull workspaceMembers then "."
else lib.concatStringsSep "\n" workspaceMembers;
crateDependencies = libb.mkVersions cargolock;
directDependencies = lib.filter
(v:
lib.elem v.name (builtins.attrNames cargotoml.dependencies) ||
(builtins.hasAttr "dev-dependencies" cargotoml &&
lib.elem v.name (builtins.attrNames cargotoml.dev-dependencies)
)
)
(libb.mkVersions cargolock);
};
buildPackage = src: attrs:
with (commonAttrs src attrs);
import ./build.nix src
( { inherit
llvmPackages
jq
runCommand
lib
darwin
writeText
stdenv
rsync
remarshal
symlinkJoin
cargo
rustc;
} // attrs
( defaultBuildAttrs //
{ name = "foo"; # TODO: infer from toml
inherit cratePaths crateDependencies;
} //
attrs
);
# XXX: not quite working yet
# buildPackageIncremental = cargolock: name: version: src: attrs:
# with rec
# { buildDependency = depName: depVersion:
# # Really this should be 'buildPackageIncremental' but that makes
# # Nix segfault
# buildPackage (libb.dummySrc depName depVersion)
# { cargoBuild = "cargo build --$CARGO_BUILD_PROFILE -p ${depName}:${depVersion} -j $NIX_BUILD_CORES";
# inherit (attrs) cargo;
# cargotomlPath = libb.writeTOML (libb.cargotomlFor depName depVersion);
# cargolockPath = libb.writeTOML (
# libb.cargolockFor cargolock depName depVersion
# );
# doCheck = false;
# };
# };
# buildPackage src (attrs //
# {
# builtDependencies = map (x: buildDependency x.name x.version)
# (libb.directDependencies cargolock name version) ;
# }
# );
buildPackageIncremental = src: attrs:
with (commonAttrs src attrs);
with
{ buildDepsScript = writeText "prebuild-script"
''
cat ${builtinz.writeJSON "crates" directDependencies} |\
jq -r \
--arg cbp $CARGO_BUILD_PROFILE \
--arg nbc $NIX_BUILD_CORES \
'.[] | "cargo build --\($cbp) -j \($nbc) -p \(.name):\(.version)"' |\
while IFS= read -r c
do
echo "Running build command $c"
$c
done
'';
};
buildPackage src
(attrs //
{ builtDependencies = [
(
buildPackage libb.dummySrc
(attrs //
{ cargoBuild = "source ${buildDepsScript}";
doCheck = false;
cargolockPath = builtinz.writeTOML cargolock;
cargotomlPath = builtinz.writeTOML
(
{ package = { name = "dummy"; version = "0.0.0"; };
dependencies = cargotoml.dependencies;
} //
(lib.optionalAttrs
(builtins.hasAttr "dev-dependencies" cargotoml)
{ inherit (cargotoml) dev-dependencies; }
)
)
;
})
)
];
});
};
{ inherit buildPackage buildPackageIncremental crates;

View file

@ -79,7 +79,7 @@ rec
};
# A very minimal 'src' which makes cargo happy nonetheless
dummySrc = name: version: runCommand "dummy-${name}-${version}" {}
dummySrc = runCommand "dummy-src" {}
''
mkdir -p $out/src
touch $out/src/main.rs
@ -118,4 +118,7 @@ rec
parseDependency' = str:
with { components = lib.splitString " " str; };
{ name = lib.elemAt components 0; version = lib.elemAt components 1; };
allRemoteDependencies = cargolock:
[];
}

View file

@ -5,10 +5,10 @@
"homepage": "https://doc.rust-lang.org/cargo",
"owner": "nmattia",
"repo": "cargo",
"rev": "87d48b01ed21b0c90ce081273cd7a0eb70673342",
"sha256": "1v68v40px7p7w6wmbvls6x3my3jyvl5m22ll9bz3vfwwdv5r4fcq",
"rev": "979904e092b39bb6aafe62a3ff3d994d3d8b6247",
"sha256": "078hhwii2qhdsm179xl249p0c2445yiyl5dv48kvx2372mc0g2gd",
"type": "tarball",
"url": "https://github.com/nmattia/cargo/archive/87d48b01ed21b0c90ce081273cd7a0eb70673342.tar.gz",
"url": "https://github.com/nmattia/cargo/archive/979904e092b39bb6aafe62a3ff3d994d3d8b6247.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"lorri": {

View file

@ -77,14 +77,21 @@ rec
# Error: Cannot parse as TOML (<string>(92, 14): msg)
#rust = naersk.buildPackage sources.rust {};
rustlings = naersk.buildPackage sources.rustlings {};
rustlings = naersk.buildPackageIncremental sources.rustlings {};
simple-dep = naersk.buildPackage ./test/simple-dep {};
simple-dep = naersk.buildPackageIncremental
(pkgs.lib.cleanSource ./test/simple-dep)
{ inherit cargo; };
# TODO: figure out why 'cargo install' rebuilds some deps
cargo =
with rec
{ cargoSrc = sources.cargo ;
cargoCargoToml = builtinz.readTOML "${cargoSrc}/Cargo.toml";
# XXX: this works around some hack that breaks the build. For more info
# on the hack, see
# https://github.com/rust-lang/rust/blob/b43eb4235ac43c822d903ad26ed806f34cc1a14a/Cargo.toml#L63-L65
cargoCargoToml' = cargoCargoToml //
{ dependencies = pkgs.lib.filterAttrs (k: _:
k != "rustc-workspace-hack")
@ -100,10 +107,6 @@ rec
# Tests fail, although cargo seems to operate normally
doCheck = false;
# cannot pass in --frozen because cargo fails (unsure why).
# Nonetheless, cargo doesn't try to hit the network, so we're fine.
cargoBuild = "cargo build --release -j $NIX_BUILD_CORES";
override = oldAttrs:
{ buildInputs = oldAttrs.buildInputs ++
[ pkgs.pkgconfig