-
Notifications
You must be signed in to change notification settings - Fork 91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot detect local path dependencies #133
Comments
I also ran into a failing path dependency:
I see that there are multi-crate workspace tests for naersk but the crates are not depending on each other. Adding such a dependency would be a good way to observe this issue. |
FWIW, within a workspace local path dependencies work without problems for me. What doesn't work is local path dependencies outside of workspaces. In my case, I hit the issue while trying to build While I see the general problem (especially |
Hmm… Does just adding The way it works is just, that it copies the non-workspaced sources to naersk's first (dependency-only) build. However, if all your source code is in Does that make sense? TL;DR:
|
@Ekleog I've updated the question to clear some misunderstanding. So in your explanation, we should only use naersk's To avoid workspace, I thought I should make that |
This is currently correct, to the best of my understanding naersk not being able to find path dependencies outside of its ( You can have a single If all your packages are in subfolders and there is no Cargo.toml at the lowest common directory of all your path-dependency crates, I'm not sure naersk can currently handle this situation, unfortunately :/ |
Thank you, that clarifies my current situation. |
There is a way to do this. In our project we've been using a home-rolled 2-phase build solution until a couple of weeks ago when we switched to naersk, and we had this exact issue. Long story short: naersk as-is currently only supports local crates in a common workspace. This has various disadvantages (the big one for us being that cargo merges conditional features into a single featureset for the whole workspace, so sometimes you simply can't put a crate in a workspace), so there's an alternate way to have non-workspace local dependencies in the form of
(Btw we also have "overlapping" crate dependencies for different projects, so we're actually creating workspaces dynamically on the fly which is quite tricky... I really hope both cargo and its nix support will mature over time) |
Because I also need to build crates that have dependencies specified at paths, I've come to the solution of actually modifying Cargo.toml before passing it as a source to naerks like so: { lib, formats, runCommand, naersk }:
let
replaceDepsSrc = { src, deps, cargoToml ? "Cargo.toml" }:
let
inherit (builtins) mapAttrs hasAttr isAttrs removeAttrs;
inherit (lib) importTOML mapAttrsToList filterAttrs;
toml = importTOML (src + "/${cargoToml}");
tdeps = toml.dependencies;
tdeps' = mapAttrs
(n: v:
if hasAttr n deps then
(if isAttrs v then
removeAttrs v [ "registry" "git" "branch" "rev" ]
else
{ version = v; }
) // { path = deps."${n}"; }
else v
)
tdeps;
toml' = toml // { dependencies = tdeps'; };
newCargoToml = (formats.toml { }).generate "Cargo.toml" toml';
in
runCommand "replace-deps-src"
{
propagatedBuildInputs = mapAttrsToList (n: p: p) (filterAttrs (n: _: hasAttr n tdeps) deps);
} ''
cp -r ${src} $out
chmod +w "$out/${cargoToml}"
cat < ${newCargoToml} > "$out/${cargoToml}"
'';
in
naerks.lib.buildPackage rec {
pname = "my-project";
src = replaceDepsSrc {
src = ./.;
deps = {
foo = ./../foo;
bar = ./../bar;
};
};
buildInputs = src.propagatedBuildInputs;
} I don't really like the use of propagatedBuildInputs here. But I find this a decent solution, maybe it could be implemented in naerks itself? |
I ended up switching to https://github.com/ipetkov/crane to work around this issue. |
I'm not completely sure how crane solves the issue of building adjacent crates that are not part of the same workspace. |
Use |
I can't really find any documentation for copySources nor can I really figure out how to call it :( |
So if you have:
then you can do
Because of the way this is used in the naersk code, it destroys the two-step caching. This is mentioned here: Line 352 in 94beb7a
Line 187 in 94beb7a
$copySourcesFrom/$p which means if any source file in the base src path changes then that whole bash script invalidates, even though the relative path $p may not have changed.
I fixed this in this PR: #147 but this didn't get merged because I also included an IFD indirection for handling other corner cases (when the source itself comes from a /nix/store path). |
Does replacing dependencies (modifying Cargo.toml) also invalidate two-step caching? Edit:
which resulted in a build error, because Cargo.toml still has a relative path to
The example structure of the crates is as follows:
baz is the project I want to build. foo and bar are common dependencies that other crates use. |
Generally speaking it's best if you point We've been through this with our stack, and we ended up rolling a "synthetic workspace" design where we create a /nix/store path with all the sources, including generating a top-level workspace Cargo.toml on the fly. This is because we also had cases where two projects A and B both referred to local crate C, but C cannot be present in two cargo workspaces. It's all a bit messy. |
Yeah, using workspaces introduces the limitations that come with namespaces, which is what I'm trying to avoid. From what I can tell (did an I personally don't mind having a nix store path for each dependency I want to replace (or even for every dependency), so replacing paths, in this case, allows me to have relative paths in Cargo.toml, to make development easier, because I can build using cargo just fine, without having to go through nix. It also has the added benefit that I can more easily patch dependencies and replace them in case I want to test something fast. I know cargo also has this feature, but having it using nix feels a bit better. I still don't completely understand how
Are there additional details I'm missing? From what I can tell, these don't really solve the problem of crates having dependencies specified as relative paths outside their The solution would be, as you suggested, to create a structure that conforms to how dependencies are specified in Cargo.toml so that building just works. This results in a single nix store path that contains all the crates, so every time the main program changes, those crates also get recompiled. Does changing Cargo.toml not avoid this complexity? One downside being that each dependency that has a relative path outside of |
The logic is described here: Line 187 in 94beb7a
So for each
or something like it. |
Another version of the function, that recursively translates all Cargo.toml relative dependency paths that contain
used as such:
It is similar in functionality with the previous function, however, it automatically detects path dependencies and does not allow for manual replacements which can be powerful. It would be cool for naerks to support both scenarios. I don't have a good understanding of how naerks works yet, so I can't implement it myself right now. Maybe somebody more knowledgeable includes it until I understand it better. |
For anyone else who stumbled here by wild googling, https://github.com/ipetkov/crane managed to build my problem project without issues. |
I tried crane, substituting I'm going to try to summarize my understanding of things (also for my self) and approaches I've tried. My scenario is dead simple, Naersk basically makes 2 derivations:
@noonien 's solution seems to be working great for me, once I copied and pasted it correctly. |
I have this dependency in my
Cargo.toml
:Since my
common
package is a local library, when I build myrust-backend
I got the following error:I tried with
rustPlatform.buildRustPackage
and the behavior is the same. is there something wrong with my setup?You can find the project here: https://github.com/numtide/todomvc-nix/tree/flake
The text was updated successfully, but these errors were encountered: