-
-
Notifications
You must be signed in to change notification settings - Fork 269
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
Pkg3 ignores OS-specific requires #165
Comments
With BinDeps2 we won't need these platform specific packages anymore, so I'd really like to avoid adding this feature just so that we can support something we won't need in the future. Can we just unconditionally install platform-specific packages and have the build script do nothing and succeed when run on the wrong platform and then just not load the package except on the appropriate platform? cc @Keno and @staticfloat to double check my assumption that we won't need platform specific packages like this once BinDeps2 is widely adopted. |
That sounds fine to me. In this case, presumably the way forward would be to file an issues against WinRPM.jl to switch to BinDeps2 and only load on Windows? |
WinRPM doesn't need to switch to BinDeps2 – BinDeps2 makes it obsolete. The main action would be for it to do nothing when installed on any system besides Windows. |
I think there will still be a need for platform-specific packages. Imagine an Personally, I think the cleanest way to do this is to have conditional requires. I don't think we should go gangbusters with it, and with packages that are cross-platform we shouldn't need it, but I definitely don't think it's reasonable to require every package to work equally well on every platform; some packages (even Julia-only packages) are OS-specific by design, and shouldn't be forced to deal with properly disabling themselves on non-matching platforms; instead I think that complexity should be a part of the package manager, to be able to identify packages that should be installed given certain conditions. There's a second reason I don't think we should have this be decided by the dependent package; PortAudio may technically be installable on Windows, but it may be undesirable from a feature/performance standpoint. The The fact that platform is the only thing they can use as the predicate to conditional requirements is fine, IMO. I haven't been able to come up with any reasonable situations where it would be necessary to have these conditional requirements other than platform differences. |
So that argues for allowing packages to be installed on any platform but perhaps erroring if you try to actually use them on a platform where they don't work. That means that Pkg3 can work for now without supporting platform-specific dependencies at the cost of resolving all dependencies for all platforms at the same time, which is unnecessary, but once we figure out how to support platform-specific dependencies (along with build/test/doc/dev-only dependencies), that limitation can be relaxed and we teach the resolver that it can ignore platform-specific dependencies for platforms other than the one it is actually on. |
I actually think that's the opposite of what I said. ;) My example above is trying to communicate that it's better to let the depending package choose what gets installed than the depended package, so I'm arguing for this to be included within |
But where's the harm in allowing packages to be installed on all platforms even if they can't work? That at least decouples the problem of platform-specific dependencies from knowing that you don't care about resolving them on some platforms. |
The majority of our platform-dependent packages do not fail gracefully when |
I don't get it. It's a simple fix that allows us to solve the conditional resolution issue later. Just make the build script do nothing when run on unsupported platforms. How hard is that? |
It is better because I do not have a design for things like conditional requirements right now. You're talking about this as if I have a complete solution that I simply refuse to let you have, but I do not. If you want to think through all of the implication and alternatives of how to express and work with conditional dependencies, platform-specific dependencies, test-only dependencies, build-only dependencies, doc-only dependencies and all the rest of it, please be my guest but I do not have a solution. The options right now are:
Seems like a pretty clear decision to me. |
With regards to test-only and build-only dependencies, these are a bit easier because they are not used in the global resolve process and hence do not need to be in any central registry. They only need to be satisfied during test / build time and we already create a separate environment for packages upon testing / building them. We could have
in the Project file. These don't need to go to the registry. |
There is a point within a project's design/development stage at which it becomes counterproductive to argue over how things should work, and it should simply be decided how they will work. If we're at the stage where we just need to get this thing out the door and discussions like this aren't helping anything, fine. We can obviously live with that. Yes, in my mind this is as easy as adding an extra field into a TOML file, something like
I realize it's certainly not that easy. But the ease of something doesn't change the fact that we needed platform-only packages before, and we won't have them when we move to Pkg3, so we just need to make sure what we do have is reasonable. As an example, I don't think we have any Pkg2 packages that "disable" themselves on install when they're run on the wrong platform. Example: What would you suggest |
Are we just going to start slapping together longer and longer names for every feature this thing might need? That seems unsustainable. |
For some prior art, Cargo has:
which is kinda ugly but still. Also,
@StefanKarpinski Could you say what the main difficulty is? From an implementation point of view, it doesn't seem to bad so is it just figuring out how they should be listed in the TOML files? |
The main difficulty is coming up with a coherent approach that covers all of the different features we need without turning into a slapdash, ad hoc mess – which is a fairly common problem in package managers, as you may have observed. Here are features we need:
Note that all of this is deeply entangled in compatibility since it's about what combinations of packages and their versions are considered to be complete and satisfactory. So if anyone has a design that make all of this work in a clean, elegant way, I'm all ears. I'm not saying it's impossible – and maybe not even that hard, but it's non-trivial to satisfy all of this without creating a mess. |
This is my suggestion: Example Project.toml file
Code loading:Code loading needs to do the following:
Pkg3
|
Not directly relevant to this issue, but you mention the |
You need the compatibility in the package itself when you add a package that is not in the registry or you want to track a branch / commit. You also need it when you are developing a package since you might want to bump the compatibility and see that everything still works. |
I see. Thanks! |
Thanks, @KristofferC, it's helpful to have a mockup to discuss. More "typical" TOML format would be:
Problems I can see with this: the loading code, which only cares about UUIDs needs to know about and look for lots of different sections: I had mocked up a somewhat different format:
This moves the top-level section currently called The
This means that the The I considered including |
Note: I'm leaving compatibility constraints out of this because I don't believe it belongs in this file. |
I explicitly mentioned this: "Stuff under [build-deps] and [test-deps] will be run in a new temporary environment where these entries will exist in [deps]. This environment will be created by Pkg3. So nothing should change in the current code loading except how it finds the uuid (trivial modification of the regex in Base)." This is what we do already by the way. |
Having to create a completely new separate file just to add a teensy bit of extra information seems very wasteful to me. |
Your mockup is more a struct of arrays kind of thinking. When I look at a dependency I want to see all its information, not look through the whole file and collect all the bits and pieces spread out into the various sections. It seems easier to keep all the information about a dependency close together. |
Having to create a temporary project environment on the fly for testing and building seems like a hack that we were forced to do because test dependencies are not currently explicit, rather than something that we want to continue doing in an ideal state of affairs. |
Keep in mind that my design solves the dependency alternatives problem as well as the other problems. How would you add alternative dependencies to your scheme? I disagree that one actually wants to see all of the information about a package all at once in this file. Having a bunch of UUIDs scattered around all over the place seems like noise – I'd rather have them all in one place and then use meaningful names everywhere else. Case in point, in your arrangement, if some package is both a build dependency and a doc dependency, it needs two separate stanzas, each of which includes the UUID and all the other information about the package. Arguably worse than that is that those UUIDs could disagree – you could use different packages with the same name for building and docing the project. Pkg3 can support that but it seems like a pretty bad situation. The syntax would also allow for the same name to appear in It's better to structurally enforce that a project has a single global namespace of top-level dependencies across all actions – if |
We fundamentally have to do a new resolution when we are running tests or building because we are suddenly in a completely new situation with new dependencies. This is very naturally done by creating a new environment and resolving that one. Also, we cannot load build-only dependencies in the package when we are not building because these might be incompatible with the project itself. The code loading must with your suggestion, therefore, parse the whole file and figure out what is build dependencies and not allow those to load. And then we build we need to tell code loading that we are building and allow it to find packages at that point etc. It is much easier to take care of that business ourselves and have the code loading in base look for |
I think your proposal is good except that it needs to be easier for the code loading to figure out what is build-only and test-only dependencies and ignore those when it comes to loading packages until we make a new environment where those are "normal" dependencies (like a build-only dependency is during build time). Also, I am not sure how to fit "alternatives" into the current resolver code. |
This is currently true because the resolver can only resolve a dependency or not resolve it. The ideal behavior, however, is for the resolver to understand that default dependencies must be compatible with the entire environment while test/build/doc dependencies only need to compatible with what this package depends on. For testing a package our current approach is pretty broken – you really want to test a package with a set of dependency versions that are an extension of the versions that you actually use it with, which is currently not necessarily the case: additional dependencies for testing can cause totally different versions of the main dependencies to be resolved. For doc and build it's arguable that you don't care, but I suspect that treating all targets the same as test is best – teach the resolver to choose versions for targets that extend the versions chosen for the main project. The point that my design allows test/build/doc-only dependencies to be identified by the main project is a good one, although I'm not sure that's actually a bad thing. After all, the project file is only half of the loading equation – it identifies the package but in order to actually load the package, you need a manifest to tell you which version of that package to use. |
This why I'm looking into more general SAT solver stuff. We probably won't implement that soon, but we still need to plan for it. |
Ok, good point, we can just choose to not put things in the manifest that we do not want loadable. So let's do this then? :D |
Having thought about the separation of |
Bump. I'm sure people are busy, I'm just wondering about the plans/status here? |
I'm still really reluctant to add this unnecessary, complex feature. I also don't really understand how it somehow become my responsibility to implement a feature I don't think we should have. Perhaps someone who actually thinks this is a good idea should implement it. My concerns include:
If someone does really feel like implementing this, the design I had in mind was: [options.installer]
macos = "Homebrew"
windows = "WinRPM"
linux = "AptGet" Then again, I don't really think it's a good idea and we can already make this work through the relatively simple measure of having each platform-specific package implementing a no-op |
Even with
wouldn't break? |
They already have to. Such |
I think the right way forward here is to make this work on the package side without any package manager features—which no one feels is impossible, some people just think it's suboptimal—and then see how that plays out and what the best approaches are. Once we learn how to do this, we can build package manager features to make those approaches easier and smoother. |
There are occasions where things need to interact with OS-specific features (e.g. RCall and JavaCall both use WinReg to access the registry). I have intentionally made WinReg possible to install on non-Windows machines, but it is a little silly that it gets installed at all. |
Perhaps a bit of guidance would be useful, e.g. for OS specific packages themselves:
|
e.g. what I think should happen should look like JuliaPackaging/Homebrew.jl#239 (I'm not sure what to do about WinRPM, since it technically works on Windows and RPM-based linux distros) |
Should this issue be closed now since the approach is not to have Pkg handle these OS specific issues? |
There's still some support I can imagine. For example, declaring that a package only supports/is required on some systems. Then anything that depends on it can know that it shouldn't bother installing the package on other systems even though it will still resolve a version that could be resolved. |
Shockingly, the recommended approach is to just include Homebrew on all platforms: JuliaLang/Pkg.jl#165 (comment)
I think we can close this for now and open a new targeted issue if the need arise. |
Case in point is
LibCURL.jl
, whoseREQUIRE
file containsOn OSX,
Pkg3
attempts to installWinRPM
. Relevant section fromManifest.toml
:Discovered when using
Pkg3
to installIJulia
.(I looked through other issues, and didn't find this, but please close if I missed it.)
The text was updated successfully, but these errors were encountered: