-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
add tooling to deal with build.zig dependency trees #14288
Comments
I work with elixir and I really like the tooling A few commands: mix hex.outdated
Dependency Current Latest Status
base24 0.1.3 0.1.3 Up-to-date
ecto_sql 3.9.1 3.9.2 Update possible
esbuild 0.5.0 0.6.0 Update possible
floki 0.34.0 0.34.0 Up-to-date
gettext 0.20.0 0.21.0 Update possible
jason 1.4.0 1.4.0 Up-to-date
...
Run `mix hex.outdated APP` to see requirements for a specific dependency.
To view the diffs in each available update, visit:
https://hex.pm/l/GPaDq
It also features nice conflict resolution and explanation when there is one. |
I can vouch for the Elixir approach too, I find it straightforward and it always worked well in my experience. To expand a bit on what @kuon said, the key is that when you declare a dependency you specify a version requirement, which can be a specific version or (more often) an accepted range of versions. Much of the convenience of the configuration comes (imho) from the Note that the success of this approach comes mainly from the fact that the Elixir community takes Semantic Versioning to heart, which means that I can be sure that if I stick to a certain major version of a dependency, my stuff will continue to work and the API will not change randomly between minor versions (for major versions > 0, see SemVer for the whole explanation). If dependencies don't follow semantic versioning, then this approach breaks easily. Maybe there could be ways to enforce this (e.g. the Elm programming language automatically bumps versions following SemVer by analyzing the code and checking if there was any API breaking change) but I assume that for now we'd have to rely on the good faith of authors. Here's a snippet of the dependency configuration part of the [
{:plug, ">= 0.4.0"},
{:gettext, github: "elixir-lang/gettext", ref: "ad014681ee119954e3bad6dd2e22687330e45068"},
{:zigler, git: "https://github.com/ityonemo/zigler.git", tag: "0.9.1"},
{:local_dependency, path: "path/to/local_dependency"}
] See here for an overview of the full list of options |
While reading this I realize that it might be a justification for the
For example, keys order would be untouched. This is important because if I have the following dependencies: .{
.name = "libffmpeg",
.version = "5.1.2",
.dependencies = .{
.libz = ">= 1.0.2",
.libmp3lame = ">= 1.0.2",
},
} And I do .{
.name = "libffmpeg",
.version = "5.1.2",
.dependencies = .{
.libz = ">= 1.0.0",
.libmp3lame = ">= 1.0.0",
.png = ">= 1.0.0",
},
} (Key added last). Now let's say I comment my file and reorder dependencies for documentation: .{
.name = "libffmpeg",
.version = "5.1.2",
.dependencies = .{
// Image libraries
.png = ">= 1.0.0",
.jpeg = ">= 1.0.0",
// Compression
.libz = ">= 1.0.0",
// Audio
.libmp3lame = ">= 1.0.0",
},
} If I add a package with .{
.name = "libffmpeg",
.version = "5.1.2",
.dependencies = .{
// Image libraries
.png = ">= 1.0.0",
.jpeg = ">= 1.0.0",
// Compression
.libz = ">= 1.0.0",
// Audio
.libmp3lame = ">= 1.0.0",
.imagemagick = ">= 1.0.0",
},
} As for tooling, I realize we do not want a central package repository, but I think an index would help a lot, to provide:
|
Thinking about this in context of #14314, there are two kinds of dependencies - those that are mentioned in the For eg. (from #14314 (comment)) different dependencies for audio backends but only one of them being enabled at build time for the target platform - different platforms might enable different set of backends. The distinction is important to this issue as there can be two different approaches to adding the required tooling mentioned in this issue. For adding and updating dependencies of the current main package can be done by just analyzing and modifying the But for operations like conflict detection/resolution and dependency tree generation things get a bit more complicated. For eg. for dependency tree generation we could -
The second point above can be achieved in different ways. I was thinking if we could create a dummy builder that has empty stubs for the different functions not required for analyzing dependencies and pass that in to the build scripts might be a simple and fast way of achieving 2. |
In Rust, Go, and NPM (excluding peer dependencies), diamond dependency problems are avoided by allowing multiple versions of the same dependency to co-exist and any potential API conflicts is handled by the type system. This is a big improvement over the traditional gems/pip/maven workflow that only allows a single global dependency singleton to be loaded unless package shading is enabled. https://stephencoakley.com/2019/04/24/how-rust-solved-dependency-hell https://research.swtch.com/vgo-mvs https://lexi-lambda.github.io/blog/2016/08/24/understanding-the-npm-dependency-model/ https://pnpm.io/symlinked-node-modules-structure We should implement a similar system for Zig. Once C libraries come into play, it will be very thorny if Zig modules struggle to link against conflicting upstream dependencies. |
On the topic of dealing with version conflicts and reproducibility, imo the nix package manager handles this the best. I'm assuming most people understandably want something more zig focused but it might be worth considering borrowing some ideas from nix (mainly the package store). https://github.com/NixOS/nix P.S. I'm fairly new to zig bug have been playing around with 0.10 on some hobby projects using nix as my package manager for all of them (since it can also manage the required C deps). Just wanting to bring this up for fear that it makes using zig with nix harder! |
Glad to see this. I think this simple feature is critical for making dependency management enjoyable. To elaborate on @rbino's comment on Elixir's override option.
With regards to bringing in multiple versions of the same dependency, I was under the impression that Go avoided this solution due to the possibility of In any case, NPMs multiple versions approach seems at odds with Zig's ReleaseSmall and WASM targets. I'd personally prefer to choose a single version for any conflicting dependency. With the option to override and a willingness to contribute upstream as needed, I think this works out better in the end (at least for my use cases). |
It would be useful to allow directed dependency graph. E.g. package A package B Dependencies like this currently fail with an error (tested on 0.14.0-dev.1158+90989be0e):
|
That use case is solved; the error you're getting indicates that you're passing different options through to |
That is good to know. In my test I just did zig init for projects called appa, libb, libc. Then in appa/build.zig.zon I added
and in libb/build.zig.zon I added
So when I was building I had not added anything to build.zig. |
That might be a bug in |
When I went back to create a minimal repro I decided to do in Linux and the error did not show up there. Then I went back to windows and no error. It turns out the double backslash was causing it \. The forward slash works in Windows. Not sure if this warrants a bug report then. |
Extracted from #14265.
Terminology clarification: #14307
Recognize these fields in build.zig.zon:
Add subcommands for dealing with the following situations:
A conflict occurs when:
Add conflict resolution logic. This could go one of two ways:
The text was updated successfully, but these errors were encountered: