haskell / cabal

Official upstream development repository for Cabal and cabal-install
https://haskell.org/cabal
Other
1.61k stars 691 forks source link

Per-component settings in cabal.project and separation of concerns #7010

Open hseg opened 4 years ago

hseg commented 4 years ago

TL;DR There is currently no way, apart from editing the .cabal file, of setting per-component settings. However, some development settings need this granularity, eg warnings.

Some of the settings in cabal.project aren't necessarily one-size-fits-all for all the components in a project. For example, in a project with a much larger frontend than core, it would be a waste to turn on profiling globally when it's only the core that will be responsible. For another, some components might be unfixably broken wrt some warnings, but that doesn't mean those warnings aren't useful elsewhere in the project. Hence, the request for per-component settings in cabal.project.

(In general, it seems that .cabal serves to hold the packaging metadata (e.g. build-depends, version) whereas the cabal.project files serve to hold the development metadata (e.g. tests, jobs, profiling). (Note that if this interpretation is correct, it might be helpful to nudge users to separate their settings along these lines)

Unfortunately, ghc-options includes a bit of both. You have eg the ghc-typelits-* compiler plugins that are definitely packaging metadata, but by the same token ghctags is definitely development metadata. You have optimizations that might be important for the package to satisfy its performance promises, but you might also want to disable certain expensive optimizations at dev time. Moreover, note that some of these only make sense per-component, while others can and should be set as projectwide defaults.)

One actual usecase where this has bitten me is that I've disabled certain warnings in my .cabal because the relevant components are unfixably broken with them. However, those warnings are useful in the other components. I can't currently just enable the warnings in cabal.project.local, since that overrides the warnings I've set in .cabal. Moreover, these warnings not being part of the packaging metadata, they have no business being in .cabal. But if I could set per-component settings, I'd be able to extract them into project.cabal and then (assuming overrides follow some form of a specificity rule) just enable the relevant warnings globally in project.cabal.local.

coot commented 2 years ago

You can use the following snippet to set ghc options in a cabal.project.local file (per package):

package somepackage
  ghc-options:
    -- options only used by somepakcage
    -Werror
Mikolaj commented 2 years ago

@hseg: when you say "component" do you mean a package in a project or a component in a package in a project?

hseg commented 2 years ago

Sorry, only just saw the ping. Unfortunately, it's been a year since I posted this issue and I do not recall the details. Judging by the .cabal and cabal.project files I have lying around in the likely suspect, meant library/executable/test-suite stanzas in .cabal. It seems judging by them that I started this issue over wanting to make use of -Werror=unused-packages, but that being impossible because of https://gitlab.haskell.org/ghc/ghc/-/issues/18563 Since cabal.project only provides package-level granularity, that means it can only set those flags globally. Moreover, since its settings are appended to those from .cabal, warnings set there override settings in .cabal. So I can't even set a default there to be overriden for the exceptional cases. Instead, I'm forced to define this (development!) metadata per stanza inside the .cabal file. Hence, the issue. The design I alluded to would extend cabal.project's per-package settings to per-stanza settings, possibly as:

package pack
  ghc-options: -Wall -Wunused-packages
  library lib1
    ghc-options: -Wno-unused-packages
  executable exec
    profiling: False
  ....

This would solve my problem, and generally makes sense, as I alluded to in my partial profiling example in the OP.

Mikolaj commented 2 years ago

@hseg: thank you very much. That makes sense. I wonder if there was any discussion before about a similar proposal, in particular a possible alternate syntax, e.g.,

component pack:library:lib1
  ghc-options: -Wno-unused-packages

which could possible be easier to implement and maintain, though yours has the advantage of being hierarchical and so permitting defaults and overrides. If there are no counter-indications, this seems worth implementing and probably the implementer would have a major say about the syntax, in particular if the implementer has serious use cases to test this on.