haskell / cabal

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

Have cabal_macros.h generate PKGCONFIG_VERSION and MIN_PKGCONFIG_VERSION #4237

Open RyanGlScott opened 7 years ago

RyanGlScott commented 7 years ago

I ran into an issue today where I needed to write some code like this:

#if /* <C library> version is greater than 2.1 */
wibble
#else
wobble
#endif

This is in a project where <C library> is detected with pkgconfig-depends. I would have hoped that the autogenerated cabal_macros.h would provide some way of detecting <C library>'s version (as specified in <C library>.pc, but sadly that doesn't seem to be the case, so I have to work around it manually by using Cabal flags and cpp-options: -DC_LIBRARY_VERSION=xyz.

Would it be unreasonable to have cabal_macros.h spit out PKGCONFIG_VERSION and MIN_PKGCONFIG_VERSION macros for every pkg-config dependency? There's the issue that pkg-config names can contain characters that aren't permissible in Cabal package names. For example, glib-2.0 contains a period. But maybe we could just turn periods into underscores like we currently do hyphens.

ezyang commented 7 years ago

This seems like it should be possible, but a more detailed spec of how pkg-config dependencies and versions get translated into the macro (note that MIN_VERSION macros hardcode the number of components) needs to be written.

RyanGlScott commented 7 years ago

Ack, that's a good point. According to https://people.freedesktop.org/~dbn/pkg-config-guide.html#writing, pkg-config version numbers are compared using the same algorithm as the RPM package manager, which is far more complicated than what we have in Haskell given that RPM versions can contain far more characters than what Haskell allows.

In fact, after reading the dissected algorithm in http://blog.jasonantman.com/2014/07/how-yum-and-rpm-compare-versions/#how-rpm-compares-version-parts, I'm doubtful that it'd be possible to easily port to a CPP macro...

RyanGlScott commented 7 years ago

Let me ask a slightly different question, then, since I'm doubting the possibility of accomplishing this with CPP macros more and more. Currently, we also autogenerate a file called Paths_<package>.hs which exports a Version value representing <package>. Could we also generate a file exporting, say, PkgConfigVersion values for its pkg-config dependencies?

This way, we can avoid conflating Haskell versions with pkg-config versions, and instead of having to put this in CPP, we could (in a separate library) develop a pkg-config version comparison algorithm à la rpmdev-vercmp, as ask folks to compare their pkg-config version numbers that way.

RyanGlScott commented 7 years ago

If we went with this approach, then the ambiguity surrounding periods in .pc filenames would go away. We could turn hyphens into underscores and periods into single quotes. That way, glib-2.0.pc would turn into, say, glib_2'0Version :: PkgConfigVersion.

RyanGlScott commented 7 years ago

Oh, I really should have done some searching beforehand, since there's some important background material.

First, there's https://github.com/haskell/cabal/issues/163, which laments the fact that pkg-config versions are much more complicated than Haskell Versions. https://github.com/haskell/cabal/pull/2730 was an attempt at incorporating odd pkg-config versions that include string suffixes (e.g., 5.1.0alpha) by simply dropping the suffix and interpreting pkg-config versions as Haskell Versions.

If we went with that approach (which hasn't been merged yet, FWIW), then we could go back to the earlier suggestion of using Cabal macros. I don't know how many folks would care if we dropped versions' string suffixes like that. I personally wouldn't, but maybe others would.

ezyang commented 7 years ago

I don't think anyone has ever been sad about being able to match against specific point releases. I know that with GHC's macros, we used to not tell people what the patch version was, and this meant people were sad sometimes. On the other hand, maybe that is good enough for you, and a fancier macro can be introduced when someone needs to scratch that itch.

I don't really know what the right thing to do here is (defer to your judgment!) just be aware that anything we do here we basically have to support forever! Cheers.

RyanGlScott commented 4 years ago

5911 introduced a versioning scheme for pkg-config version numbers, so I suppose that all that remains to resolve this issue is to figure out the corresponding CPP macros to enforce that versioning scheme.

phadej commented 4 years ago

@RyanGlScott PkgconfigVersion is unfortunately literally an arbitrary string. So we cannot do anything compatible MIN_PKGCONFIG_VERSION (with openssl being an example where we cannot even pretend).

Yet, exposing PKGCONFIG_VERSION as a string is straight-forward.

RyanGlScott commented 4 years ago

Ugh, right. I had completey forgotten about my comments above (written three years ago) about how infeasible this would be to implement as a CPP macro. Once again, I'm force to dismiss that as a possibility.

Having PKGCONFIG_VERSION might be worth it, but I'm somewhat worried about the potential for conflicts between the names of C packages and Haskell packages. I'm starting to wonder if perhaps the use case I had would be better suited by using Cabal flags, i.e.,

if flag(custom)
  cpp-options: -DNINE_POINT_THREE_H
  pkgconfig-depends: libpq >=9.3h
else
  pkgconfig-depends: libpq <9.3h
phadej commented 4 years ago

The prefix MIN_PKGCONFIG_ prevents clashes. I wouldn't worry about that.

Having that version can be useful to expose it from the compiled module. So you can say compiled against libpq "9.4" or something like that. Note: compiled against, what's actually (usually) dynamically loaded is another story.

I'll try to add it soon. I just recently refactored cabal_macros generation, so I'm not scare to edit that part of the code :)

roberth commented 2 years ago

I've released a Cabal setup hook library, cabal-pkg-config-version-hook that adds such macros, as an interim solution that is compatible with existing cabal versions.

It follows a different naming convention, so it doesn't interfere with the one suggested here.