Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should GHC be linking different versions of the same libraries?

I'm trying to compile a program with GHC 7.6.3 and I get the error

/usr/lib/ghc/unix-2.6.0.1/libHSunix-2.6.0.1.a(execvpe.o): In function `pPrPr_disableITimers':
(.text+0x300): multiple definition of `pPrPr_disableITimers'
/home/tom/.cabal/lib/i386-linux-ghc-7.6.3/unix-2.7.1.0/libHSunix-2.7.1.0.a(ghcrts.o):ghcrts.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status

(The problem ultimately derives from a usage of readProcessWithExitCode but I don't think that's especially relevant)

If I run ghc with -v then I see amongst the command line parameters

  • '-L/home/tom/.cabal/lib/i386-linux-ghc-7.6.3/unix-2.7.1.0'
  • '-L/usr/lib/ghc/unix-2.6.0.1'
  • '-lHSunix-2.7.1.0'
  • '-lHSunix-2.6.0.1'

Is this a bug? Should GHC really be trying to link two different versions of unix?

like image 407
Tom Ellis Avatar asked Dec 15 '22 14:12

Tom Ellis


1 Answers

So, you haven't given me enough information in this bug per se, but I am going to attempt to use my psychic debugging powers to answer your question.

You attempting to compile a GHC program which relies on packages p and q. You probably specified them using -package p and -package q. Your package database probably looks something like this (or transitively looks like this):

id: p-0.1-8aa5d403c45ea59dcd2c39f123e27d57
depends: unix-2.6.0.1-9ce33138f4fcfb9c37f6e6c300bcc367

id: q-0.1-d5221a8c8a269b66ab9a07bdc23317dd
depends: unix-2.7.1.0-2f15426f5b53fe4c6490832f9b20d8d7

id: unix-2.6.0.1-9ce33138f4fcfb9c37f6e6c300bcc367
depends: (none)

id: unix-2.7.1.0-2f15426f5b53fe4c6490832f9b20d8d7
depends: (none)

When GHC looks for package p, it sees p-0.1-8aa5d403c45ea59dcd2c39f123e27d57 and decides to use it. Then, when it looks for package q, it sees q-0.1-d5221a8c8a269b66ab9a07bdc23317dd and decides to use it. It then does a consistency check, to make sure that for any package id foo-0.1, it didn't pick two installed package IDs. In my example, this is trivially true, since the two versions of unix which were picked had DIFFERENT package IDs (unix-2.6.0.1 and unix-2.7.1.0), and my psychic debugging powers say that in your extended package database, this is also true. (By the way, if you're running GHC 7.10, then the shadowing check ensures for any package key it didn't pick two different installed package IDs. So this is almost certainly guaranteed to be true.)

So GHC accepts the kaboodle, and we try to link in two different version of unix. Oops!

So, what should you do? Here are your options.

  1. Use Cabal. Cabal will enforce a stronger constraint, namely for every PACKAGE NAME there is only one PACKAGE VERSION. So when you try to cabal configure it will tell you it couldn't resolve the dependencies, or maybe pick an earlier version of q which was installed against unix-2.6.0.1 instead of unix-2.7.1.0

  2. Look and see if you have a version of q which is installed against the older unix, and explicitly request it. By default, if there are multiple possible choices for a package, GHC will pick the latest version. You can tell it to use an earlier version.

  3. Reinstall a NEWER version of p compiled against unix-2.7.1.0. Then GHC will pick it up and there's no incompatibility. Note that it has to be a newer version since today's Cabal won't let you have a copy of p-0.1 compiled against unix-2.6.0.1 AS WELL as a copy of p-0.1 compiled against unix-2.7.1.0. Silly right? We're trying to fix it.

  4. Blow away your .cabal and .ghc directories, and then cabal install the newest version of unix, and then everything else. Then everything will (probably) be compiled against the new version of unix and there won't be a problem.

Here are three more, not so useful solutions:

  1. Note that you are really only getting this link error because unix has C sources which get assigned the same name even under different versions of the package (this is not the case for Haskell identifiers, they are properly version prefixed). If unix were fixed so that all its C symbols were version prefixed, you would not have seen this problem and your program would have compiled fine. Well, unless you tried to use types from the two different versions of unix together (then you'd be told that unix-2.6.0.1:BlahBlah is not the same as unix-2.7.1.0:BlahBlah. If you're lucky.) There's no convention for how to do this right now but there is a GHC ticket about it: https://ghc.haskell.org/trac/ghc/ticket/9351

  2. Recently, some people have proposed that GHC should enforce a stronger consistency constraint when implementing shadowing, namely the same constraint that Cabal enforces. In that world, GHC would not have been able to find one of p or q, and would have reported that not all packages were satisfiable. Would that have been better? The plan for how to do this is to have Cabal manage a consistent "view" of the package database, so that when you use ghc by itself you'll never see packages that shouldn't actually be visible. That's this GSoC project: https://www.google-melange.com/gsoc/project/details/google/gsoc2015/vishal4556/5634387206995968

  3. Perhaps you might say, "Forget about all this fancy view business, really, GHC should just do a better consistency check on the packages you try to make it use to make sure that it's consistent with respect to a name to version mapping." (By the way, a simplified check would be the one that Setup executables currently do). Last summer I tried to convince Duncan that GHC should do this, but he was soundly of the opinion that this was Cabal's job, and we shouldn't duplicate this code in GHC. So to this day there is no ticket on the GHC bugtracker suggesting we should do this.

like image 93
Edward Z. Yang Avatar answered May 18 '23 14:05

Edward Z. Yang