Skip to content
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

Introduce "setup dependencies" #2515

Merged
merged 28 commits into from
May 21, 2015
Merged

Introduce "setup dependencies" #2515

merged 28 commits into from
May 21, 2015

Conversation

edsko
Copy link
Contributor

@edsko edsko commented Apr 1, 2015

.. And finally, the pièce de résistance, introducing suppport for setup dependencies! This PR relies on #2500, #2504 and #2514.

In this PR we add a new section to the .cabal file in which packages can specify explicit setup dependencies. When this section is absent (i.e., currently for all packages) we don't do anything different to what we do now, but when the section is present then that section is used to the dependencies of a setup script.

For example, suppose we have two versions of package A available in our global (or user local, if not using sandboxes) DB. If we have a package whose setup script relies on version 0.1 of A, rather than version 0.2, it will fail to build because by default cabal-install just makes all packages visible when compiling a setup script, which means that it will be linked against the newer version.

However, we can now use an explicit setup dependencies stanza to address this:

custom-setup
  setup-depends:       base, Cabal, a ==0.1.0.0

Setup dependencies are treated as independent in the solver: we can pick different versions of packages for the setup script that we pick for the package proper, although we make an attempt not to do so (as explained in the blog post about independent goals).

As a sanity check, I ran the solver after all these PRs against all (the latest versions of) all packages on Hackage (all 7889), and wherever we produce an install plan we produce the same install plan, so that's reassuring.

In addition, I also did some performance measurements, but there's hardly any difference in performance. The modified solver is slightly slower, but barely so: here's a density plot of execution time in seconds; red is stock cabal-install 1.22, blue is the solver with all my PRs:

absolute

And here's a density plot of the relative performance of the two solvers; 1.0 meaning exactly equal, below 1.0 meaning the modified solver is faster, above 1.0 meaning the modified solver is slower:

relative

Basically, the conclusion -- performance-wise anyway -- is: no significant difference.

dcoutts and others added 19 commits March 27, 2015 15:38
It turns out not to be the right solution for general private
dependencies and is just complicated. However we keep qualified
goals, just much simpler. Now dependencies simply inherit the
qualification of their parent goal. This gets us closer to the
intended behaviour for the --independent-goals feature, and for
the simpler case of private dependencies for setup scripts.

When not using --independent-goals, the solver behaves exactly as
before (tested by comparing solver logs for a hard hackage goal).
When using --independent-goals, now every dep of each independent
goal is qualified, so the dependencies are solved completely
independently (which is actually too much still).
POption annotates a package choice with a "linked to" field. This commit
just introduces the datatype and deals with the immediate fallout, it doesn't
actually use the field for anything.
This is implemented as a separate pass so that it can be understood
independently of the rest of the solver.
In particular, in the definition of dependencyInconsistencies.

One slightly annoying thing is that in order to validate an install plan, we
need to know if the goals are to be considered independent. This means we need
to pass an additional Bool to a few functions; to limit the number of functions
where this is necessary, also recorded whether or not goals are independent as
part of the InstallPlan itself.
Since we didn't really have a unit test setup for the solver yet, this
introduces some basic tests for solver, as well as tests for independent goals
specifically.
I don't know why we we constructed this graph manually here rather than calling
`graphFromEdges`; it doesn't really matter except that we will want to change
the structure of this graph somewhat once we have more fine-grained
dependencies, and then the manual construction becomes a bit more painful;
easier to use the standard construction.
This commit does nothing but rearrange the Modular.Dependency module into a
number of separate sections, so that's a bit clearer to see what's what. No
actual code changes here whatsoever.
The ComponentDeps datatype will give us fine-grained information about the
dependencies of a package's components.  This commit just introduces the
datatype, we don't use it anywhere yet.
The modular solver has its own representation for a package (PInfo). In this
commit we modify PInfo to keep track of the different kinds of dependencies.

This is a bit intricate because the solver also regards top-level goals as
dependencies, but of course those dependencies are not part of any 'component'
as such, unlike "real" dependencies. We model this by adding a type parameter
to FlaggedDeps and go which indicates whether or not we have component
information; crucially, underneath flag choices we _always_ have component
information available.

Consequently, the modular solver itself will not make use of the ComponentDeps
datatype (but only using the Component type, classifying components); we will
use ComponentDeps when we translate out of the results from the modular solver
into cabal-install's main datatypes.

We don't yet _return_ fine-grained dependencies from the solver; this will be
the subject of the next commit.
In this commit we modify the _output_ of the modular solver (CP, the modular's
solver internal version of ConfiguredPackage) to have fine-grained dependency.
This doesn't yet modify the rest of cabal-install, so once we translate from CP
to ConfiguredPackage we still lose the distinctions between different kinds of
dependencies; this will be the topic of the next commit.

In the modular solver (and elsewhere) we use Data.Graph to represent the
dependency graph (and the reverse dependency graph). However, now that we have
more fine-grained dependencies, we really want an _edge-labeled_ graph, which
unfortunately it not available in the `containers` package. Therefore I've
written a very simple wrapper around Data.Graph that supports edge labels; we
don't need many fancy graph algorithms, and can still use Data.Graph on these
edged graphs when we want (by calling them on the underlying unlabeled graph),
so adding a dependency on `fgl` does not seem worth it.
The crucial change in this commit is the change to PackageFixedDeps to return a
ComponentDeps structure, rather than a flat list of dependencies, as long with
corresponding changes in ConfiguredPackage and ReadyPackage to accomodate this.

We don't actually take _advantage_ of these more fine-grained dependencies yet;
any use of

    depends

is now a use of

   CD.flatDeps . depends

but we will :)

Note that I have not updated the top-down solver, so in the output of the
top-down solver we cheat and pretend that all dependencies are library
dependencies.
@edsko
Copy link
Contributor Author

edsko commented Apr 1, 2015

/cc @kosmikus .

@edsko edsko mentioned this pull request Apr 6, 2015
edsko and others added 9 commits April 6, 2015 12:52
Although we don't use the new setup dependency component anywhere yet, I've
replaced all uses of CD.flatDeps with CD.nonSetupDeps. This means that when we
do introduce the setup dependencies, all code in Cabal will still use all
dependencies except the setup dependencies, just like now. In other words,
using the setup dependencies in some places would be a conscious decision; the
default is that we leave the behaviour unchanged.
This patch adds it to the package description types and to the parser.
There is a new custom setup section which contains the setup script's
dependencies. Also add some sanity checks.
(and, therefore, also to the modular solver's output)
By chosing setup dependencies after regular dependencies we get more
opportunities for linking setup dependencies against regular dependencies.
The only problematic thing is that when we call `cabal clean` or `cabal
haddock` (and possibly others), _without_ first having called `configure`, we
attempt to build the setup script without calling the solver at all. This means
that if you do, say,

    cabal configure
    cabal clean
    cabal clean

for a package with a custom setup script that really needs setup dependencies
(for instance, because there are two versions of Cabal in the global package DB
and the setup script needs the _older_ one), then first call to `clean` will
succeed, but the second call will fail because we will try to build the setup
script without the solver and that will fail.
@dcoutts
Copy link
Contributor

dcoutts commented May 20, 2015

I think the status here is that @kosmikus is happy for this to be committed, and for his comments to be addressed after merging. Right @kosmikus?

The only other thing is a follow-up patch to address @23Skidoo's comment about cabal version checks.

Anything else? From my point of view this is ready to go in (and we'll follow up on the comments).

@dcoutts
Copy link
Contributor

dcoutts commented May 20, 2015

Ok @kosmikus confirmed to me that he's happy to merge now and that we can address his comments after.

@23Skidoo so feel free to merge, or give me an ack and I'll merge.

@23Skidoo
Copy link
Member

@dcoutts
Sure, if you want to address comments in a later PR, then go ahead, just don't forget about them.

@dcoutts
Copy link
Contributor

dcoutts commented May 20, 2015

@23Skidoo promise :-) Thanks. (We want it to work well and be maintainable obviously)

dcoutts added a commit that referenced this pull request May 21, 2015
Introduce "setup dependencies"
@dcoutts dcoutts merged commit d938b91 into haskell:master May 21, 2015
@23Skidoo
Copy link
Member

Yay!

@edsko edsko deleted the pr/setup-deps branch June 1, 2015 13:10
@ezyang
Copy link
Contributor

ezyang commented Jun 1, 2015

One thing that hasn't been discussed here, is what recommended backwards-compatible usage for people who don't have the newest version of Cabal? Example: ekmett/lens#496 (comment) where people want to support older versions of GHC with the stock Cabal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants