Seems like that works, it just becomes ugly with many packages.
Using ghc ... -package somepackage
only works if somepackage
has already been installed. So for packages that are not distributed with GHC you would need to run some form of cabal ...
command every time you switch to a new GHC version.
I wonder how other ecosystems deal with this. I believe Rust doesn’t even allow using dependencies without making a crate (the Haskell equivalent would be a cabal package). But maybe other languages generally don’t use as many dependencies as Haskell.
every time you switch to a new GHC version
Once a year maybe, so that’s OK for the benchmarks game.
other ecosystems
For Rust someone showed me cargo
commands to download and build the latest versions of a programs dependencies. That expanded into a shell script and I jump through hoops making it work.
For Perl I’ve given up on a couple of benchmarks game programs because they pull in a build system with a seemingly bottomless pit of dependencies.
Of course, these things may work very well for their intended audience.
Meanwhile is:
Could not find module ‘Control.Concurrent.ParallelIO.Global’
an example where I need to run cabal
?
Yeah, if you see such an error without the suggestion to use -package ...
then you will need to run cabal
.
For your specific example you can search for the module on hoogle: Control.Concurrent.ParallelIO.Global - Hoogle. Then you’ll see all the results are from the parallel-io
package.
One complication now is that as far as I know there is no cabal command to install a package without exposing it in a package environment file. So you can run cabal install --lib --package-env ./env parallel-io
and then just discard the generated ./env
file and use ghc -package parallel-io ...
instead.
You could also save those env
files for every benchmark somewhere and just use ghc -package-env ./env ...
to compile. That avoids the ugliness with multiple packages, but it requires some extra management of those files.
Finally, one other alternative is to just run cabal install --lib parallel-io
, which installs it into an environment that is always read by default. This avoids the ugly command line arguments and does not require you to manage environment files. However, this can lead to very confusing error messages if you are trying to install packages that conflict with packages that were installed earlier. So, it is generally not recommended, but maybe that isn’t so much of a problem in this case.
$ cabal install --lib parallel-io
Resolving dependencies...
…
…
Building parallel-io-0.3.5 (lib)
Installing parallel-io-0.3.5 (lib)
Completed parallel-io-0.3.5 (lib)
$ cabal install --lib vector-algorithms
Resolving dependencies...
…
…
Building vector-algorithms-0.9.0.1 (lib)
Installing vector-algorithms-0.9.0.1 (lib)
Completed vector-algorithms-0.9.0.1 (lib)
$ cabal install --lib text
Resolving dependencies...
Up to date
But
knucleotide.ghc-3.hs:33:1: error:
Could not find module ‘Text.Builder’
Use -v (or `:set -v` in ghci) to see a list of the files searched for.
|
33 | import qualified Text.Builder as Builder
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Also I was trying to avoid being online when time measurements were being made, by downloading required libraries beforehand.
We should really (as a community) stop recommending cabal install --lib
. It’s horrendously flaky.
That seems to be an aside — in this actual example what do you recommend?
Well, do @jaror’s original instructions work? Hidden package — Could not load — how to :set - #3 by jaror
Now I’m confused. Those instructions seem to use cabal install --lib
which you say should not be recommended and is horrendously flaky?
That module seems to come from the text-builder
package. It is not from text
.
Now I’m confused. Those instructions seem to use
cabal install --lib
which you say should not be recommended and is horrendously flaky?
Correct. However, they are the instructions of the person that wrote the program in question, so I think they’re worth trying. Furthermore, use of --package-env
is likely to make --lib
less flaky. A “proper” solution is significantly more complicated[1] and involves writing a .cabal
file.
[1] i.e. it would take me 5 minutes rather than 5 seconds to write down
I think to be maximally helpful we’re going to need a lot more background information, for example, where is the original source for these programs, what is their purpose, what sort of system are you running them on?
I think ideally I would suggest writing .cabal
files for each of them. That way they will be maximally reproducible, but without seeing all the sources themselves I can’t see what exactly would be needed in the .cabal
file.
In those results the only result that matches literally is the one from text-builder
.
I now also found out that you can hoogle for +Text.Builder
to only show module results. Then it is much more obvious; there are only 7 results and text-builder
is the 3rd one.
and
text-builder
is the 3rd one
Yeah I’d probably have seen that, but I wouldn’t have thought to precede the search string by +
I suppose for other reasons those 7 partial match results are listed rather than the just the one result. Enough. I don’t need to know. Thanks.
Thanks. It seems these are individual source files. The normal way of creating a binary in Haskell would be to add a .cabal
file that contains detail of its dependencies and how it should be built. Would that be acceptable for your purpose, or are there constraints that the binaries should be built only from a single source file?
For the very limited purpose of the benchmarks game this seems unnecessary, just more stuff to maintain and copy into the build folder. Thanks.
OK, in that case I think that following @jaror’s suggestions and crossing your fingers is the best we can do.