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

Allowing pkg-config to fail #6771

Closed
hasufell opened this issue May 9, 2020 · 5 comments
Closed

Allowing pkg-config to fail #6771

hasufell opened this issue May 9, 2020 · 5 comments
Labels
re: pkg-config Concerning pkg-config and pkgconfig-depends constraints type: discussion

Comments

@hasufell
Copy link
Member

hasufell commented May 9, 2020

Currently, pkgconfig-depends imposes a hard requirement and will fail if the file is not found or pkg-config doesn't exist. This is not portable, there are a few reasons:

  1. some distros incorrectly add .pc files downstream, causing cross-distro breakage (especially debian)
  2. existence of a .pc file may depend on the version of the library
  3. it's not clear how well it works on non-linux platforms, although these are generally supported

In general, I believe users don't really care how cabal figures out the correct library destination etc. Of course pkg-config delivers better results than assuming e.g. FHS, but the latter still works for a majority of use cases, when pkg-config is absent.

As a result, I've come up with a template Setup.hs that sort of makes this optional. However, I feel this is rather fragile. @dcoutts reminded us that cabal-install feeds the pkg-config database into the solver and so should be able to use that information for resolution. A suggested way of triggering this was:

flag use-pkgconfig-foo
  description: get foo lib config from pkg-config
  manual: False
  default: True

library
  [...]

  if flag(use-pkgconfig-foo)
    pkgconfig-depends: libfoo
  else
    includes:          foo.h
    extra-libraries:   foo

This, however, doesn't work, because Cabal tries to find pkg-config deps during configure stage, before the solver:

requirePkg dep@(PkgconfigDependency pkgn range) = do
version <- pkgconfig ["--modversion", pkg]
`catchIO` (\_ -> die' verbosity notFound)
`catchExit` (\_ -> die' verbosity notFound)
let trim = dropWhile isSpace . dropWhileEnd isSpace
let v = PkgconfigVersion (toUTF8BS $ trim version)
if not (withinPkgconfigVersionRange v range)
then die' verbosity (badVersion v)
else info verbosity (depSatisfied v)
where
notFound = "The pkg-config package '" ++ pkg ++ "'"
++ versionRequirement
++ " is required but it could not be found."
badVersion v = "The pkg-config package '" ++ pkg ++ "'"
++ versionRequirement
++ " is required but the version installed on the"
++ " system is version " ++ prettyShow v
depSatisfied v = "Dependency " ++ prettyShow dep
++ ": using version " ++ prettyShow v
versionRequirement
| isAnyPkgconfigVersion range = ""
| otherwise = " version " ++ prettyShow range
pkg = unPkgconfigName pkgn

I tried commenting this out and indeed, cabal doesn't fail prematurely anymore. However, it doesn't seem to pick the alternative resolution (as in: it never disables use-pkgconfig-foo) and will fail at linking stage.

The pkg-config database is fed during the validation phase:

Any pointers would be appreciated.

@phadej
Copy link
Collaborator

phadej commented May 9, 2020

A solution is to introduce has(pkg-config) conditional construction, so your example could be rewritten as

-- no flag

library
  if has(pkgconfig)
    pkgconfig-depends: libfoo
  else
    includes:          foo.h
    extra-libraries:   foo
    -- or some other means to figure out library needs

or alternatively to allow flag defaults to be boolean expressions

flag use-pkgconfig-foo
  description: get foo lib config from pkg-config
  -- Note: this flag is manual!
  manual:  True
  default: has(pkgconfig) 

library
  [...]

  if flag(use-pkgconfig-foo)
    pkgconfig-depends: libfoo
  else
    includes:          foo.h
    extra-libraries:   foo

So there are two somewhat independent branches one can pursue:

  • Adding has(pkgconfig) support to ConfVar
  • Adding expression support to flag defaults

From this two the latter is expressions is IMHO more important as picking flag assignment based on OS, Architecture or even GHC version.
E.g. postgresql-simple would benefit from it by unconditionally asking pkgconfig-depends on non-windows platforms. haskellari/postgresql-libpq#3


I also vaguely remember that pgkconfig-depends behave badly (in solver)
when there are no pkg-config available (vs. library not available).
Or something related.

@hvr might remember the details.

@phadej
Copy link
Collaborator

phadej commented May 9, 2020

Note: pkgconfig does interact with solver, but no-one remembers how exactly.

EDIT: After reading some issues, it seems that there is no way to make solver commit to pkgconfig-depends branch when there is pkgconfig present. (I.e. to make users fix their .pcs, and not fallback to includes and extra-libraries). But OTOH some users might prefer that (current?) behavior.

Someone should make a table of behaviors, we ought to support all variants. I think has(pkgconfig) should help, but I'm not sure it's sufficient.

@mengwong
Copy link

I was trying to install regex-pcre and got some nonobvious errors.

This was on a freshly booted system. It turns out I had neither pkg-config nor libpcre installed. But, like the error messages I struggled with, that root cause was only obvious in hindsight:

cabal: The program 'pkg-config' version >=0.9.0 is required but it could not be found.

My first thought was, "if cabal is being so specific as to talk about version numbers, this has got to be a Haskell thing; why isn't it downloading pkg-config for me from Hackage?" Maybe it's because the package is mis-named? There's a hs-pkg-config out there, maybe the package got renamed? After barking up that wrong tree for a while, sudo apt install pkg-config fixed it.

Next,

ubuntu@ip-172-31-31-146:~$ cabal install regex-pcre
Resolving dependencies...  
cabal: Could not resolve dependencies:
[__0] trying: regex-pcre-0.95.0.0 (user goal)
[__1] rejecting: regex-pcre:+pkg-config (conflict: pkg-config package
libpcre-any, not found in the pkg-config database)
[__1] rejecting: regex-pcre:-pkg-config (manual flag can only be changed
explicitly)
[__1] fail (backjumping, conflict set: regex-pcre, regex-pcre:pkg-config)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: base, regex-pcre, regex-base,
regex-pcre:pkg-config, fps
Try running with --minimize-conflict-set to improve the error message.

Whoa.

If, somewhere in there, something had said "are you sure you have libpcre installed?" I would have known what to do next; as it stands, the errors tend to make me think that something is going wrong somewhere else.

Maybe I installed pkg-config wrong?

Or maybe my whole system is fubared? I mean, cabal says it's having trouble with base? Surely it can't be just a PCRE thing!

So, that was what I was thinking when I had this difficulty.

It's a pretty common pattern that a Hackage library relies on a system C library; I took it for granted that the system library was around, when I shouldn't have. But the error message could be more helpful.

@phadej
Copy link
Collaborator

phadej commented Jun 23, 2020

Unfortunately you have to learn to read the whole error message and log (it's printed, so you can figure out what's the cause):

[__1] rejecting: regex-pcre:+pkg-config (conflict: pkg-config package
libpcre -any, not found in the pkg-config database)

is the key line.

And note, we cannot just know which one is the thing user can try to resolve. For example in this case

[__1] rejecting: regex-pcre:-pkg-config (manual flag can only be changed
explicitly)

you might want to actually disable the manual flag, if you have libpcre available without pkg-config database entry!

Finally, the

[__1] fail (backjumping, conflict set: regex-pcre, regex-pcre:pkg-config)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: base, regex-pcre, regex-base,
regex-pcre:pkg-config, fps

summarizes that out of (maybe) hundreds of dependencies the problem is probably caused by something from
base, regex-pcre, regex-base, regex-pcre:pkg-config, fps list - and indeed problem is in installing regex-pcre.

To summarize: you have to learn to read error output in full. It's genuinely hard to say what is preventing finding install plan. And more specifically, guiding users how to install C-libraries (with/out configuring pkg-config) is out of scope of Cabal.

If that's unsatisfactory to you, don't use dependencies using C-libraries. There is regex-tdfa which is mostly as good. Or then there is https://hackage.haskell.org/package/regex-pcre-builtin.

If you still want the solver error messages to be improved, please open new issue with constructive improvement ideas. This issue is not about that.

@gbaz
Copy link
Collaborator

gbaz commented Dec 2, 2021

I think this was resolved by #7621

@gbaz gbaz closed this as completed Dec 2, 2021
hamishmack added a commit to input-output-hk/haskell.nix that referenced this issue Sep 13, 2022
A bug was fixed in cabal 3.8 (haskell/cabal#6771) that haskell.nix relied on for `pkg-config` in support.  To work around this we added a dummy `pkg-config` that `cabal configure` now uses when haskell.nix runs it `cabal configure` internally.  That returns version information for all the `pkg-config` packages in `lib/pkgconfig-nixpkgs-map.nix`.  This mapping has also been expanded based on the results of searching nixpkgs for `*.pc` files.

This update also includes workarounds for:

haskell/cabal#8352
haskell/cabal#8370
haskell/cabal#8455
@andreasabel andreasabel added the re: pkg-config Concerning pkg-config and pkgconfig-depends constraints label May 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
re: pkg-config Concerning pkg-config and pkgconfig-depends constraints type: discussion
Projects
None yet
Development

No branches or pull requests

5 participants