How can I use GHC with a cabal sandbox that's not in the current working directory? - haskell

If I create a cabal sandbox with cabal sandbox init, I can use cabal repl or cabal exec ghc(i) to work with those packages without creating a project:
$ mkdir /tmp/example && cd /tmp/example
$ cabal sandbox init
$ cabal install QuickCheck
$ cabal exec ghci
Prelude> :m Test.QuickCheck
Prelude Test.QuickCheck>
However, if I change the path to something else, even to a subdirectory, I cannot access the packages anymore:
$ mkdir -p /tmp/example/sub && cd /tmp/example/sub
$ cabal exec ghci
Prelude> :m Test.QuickCheck
<no location info>:
Could not find module ‘Test.QuickCheck’
It is not a module in the current program, or in any known package.
Is there any way to use the contents from the sandbox, without copying its content?

The problem is that cabal will only respect sandboxes in the current working directory. However, there are several options where you can specify a sandbox location for cabal or the package databse for GHC.
Using cabal features
You can use cabal's --sandbox-config-file option to specify a sandbox configuration, e.g.
$ cabal --sandbox-config-file=/tmp/example/cabal.sandbox.config exec ghci
Prelude> :m Test.QuickCheck
Prelude Test.QuickCheck>
This also enables you to change the sandbox from other places, which comes in handy if you just want to install random stuff into a temporary place:
$ cabal --sandbox-config-file=/tmp/example/cabal.sandbox.config install lens
$ cabal --sandbox-config-file=/tmp/example/cabal.sandbox.config repl
Prelude> :m Control.Lens
Prelude Control.Lens> :m Test.QuickCheck
Prelude Control.Lens Test.QuickCheck>
Since this gets cumbersome after a while, you should probably add an alias
$ alias sandboxed-cabal="cabal --sandbox-config-file=/tmp/example/cabal.sandbox.config"
$ sandboxed-cabal repl
Prelude>
Using ghc -package-db
Alternatively, you can directly specify the package database when you use GHC with -package-db:
$ ghci -package-db /tmp/example/.cabal-sandbox/<ARCH>-packages.conf.d
Prelude> :m Test.QuickCheck
Prelude Test.QuickCheck>
The <ARCH> depends on your system and the used GHC, e.g. on a 64bit Linux and GHC 7.10.3 it's x86_64-linux-ghc-7.10.3-packages.conf.d. You can then use all packages in that database:
$ ghci -package-db /tmp/example/.cabal-sandbox/<ARCH>-packages.conf.d
Prelude> :m Control.Lens
Prelude Control.Lens>
Again, an alias should come in handy.
Using GHC_PACKAGE_PATH
Last, but not least, you can adjust an environment variable. However, if the environment variable GHC_PACKAGE_PATH exists, it will overwrite GHC's usual package databases, so you either need to check ghc-pkg list and add them too
$ GHC_PACKAGE_PATH=/opt/ghc/7.10.3/lib/ghc-7.10.3/package.conf.d/:/tmp/example/.cabal-sandbox/x86_64-linux-ghc-7.10.3-packages.conf.d ghci
or use -global-package-db and -user-package-db to reenable them:
$ GHC_PACKAGE_PATH=/tmp/example/.cabal-sandbox/x86_64-linux-ghc-7.10.3-packages.conf.d ghci -global-package-db -user-package-db

Related

How to work together with cabal-3 and ghc (ghc-pkg, too)?

With the release of cabal-3, the packages from Hackage are installed in a new location that the compiler ghc and ghc-pkg know nothing about.
In other words, packages are installed but not registered for ghc. Ghci, ghc, ghc-pkg cannot work.
For example,
cabal install safe --lib
Create file t1.hs
import Safe
t1 = tailMay [1,2,3]
Let's try:
> ghci t1.hs
GHCi, version 8.10.2: https://www.haskell.org/ghc/:? for help
[1 of 1] Compiling Main (t1.hs, interpreted)
t1.hs: 1: 1: error:
Could not find module `Safe '
Use -v (or `: set -v` in ghci) to see a list of the files searched for.
|
1 | import Safe
| ^^^^^^^^^^^
Failed, no modules loaded.
This bug is described here
https://github.com/haskell/cabal/issues/6262
and here
https://gitlab.haskell.org/ghc/ghc/-/issues/17341
I use as a temporary solution setting a system variable
GHC_PACKAGE_PATH=C:\Users\me\AppData\Roaming\cabal\store\ghc-8.10.2\package.db;
(Windwos 10, haskell-dev by chocolatey)
via
On Windows, packages installed with cabal seem to be unavailable in ghc/ghci
but with updates I will have to manually change this system variable.
Are there any more elegant solutions to this problem?
P.S. Unfortunately, this solution (via GHC's environment variable GHC_PACKAGE_PATH) is incompatible with Cabal :(
https://github.com/haskell/cabal/issues/1944
One way to achieve this is to use the --env flag to make the libraries available to GHC whenever you are in the current directory:
~ $ mkdir /tmp/foo
~ $ cd /tmp/foo
/tmp/foo $ cabal install safe --lib --env .
Resolving dependencies...
Build profile: -w ghc-8.8.3 -O1
In order, the following will be built (use -v for more details):
- safe-0.3.19 (lib) (requires build)
Configuring library for safe-0.3.19..
Preprocessing library for safe-0.3.19..
Building library for safe-0.3.19..
…
> Installing library in /home/jojo/.cabal/store/ghc-8.8.3/incoming/new-4056/home/jojo/.cabal/store/ghc-8.8.3/safe-0.3.19-92fbaef88124b4508ce447f6245bc793f7a1748247ae68d10e449150df1069af/lib
t1.hs
/tmp/foo $ cat > t1.hs
import Safe
t1 = tailMay [1,2,3]
/tmp/foo $ ls -a
. .. .ghc.environment.x86_64-linux-8.8.3 t1.hs
/tmp/foo $ ghci t1.hs
GHCi, version 8.8.3: https://www.haskell.org/ghc/ :? for help
Loaded package environment from /tmp/foo/.ghc.environment.x86_64-linux-8.8.3
[1 of 1] Compiling Main ( t1.hs, interpreted )
Ok, one module loaded.
*Main>
Note that you probably shouldn’t do this in a directory where you actually have a foo.cabal file. See the documentation of cabal v2-install for details.
Working with GHC_ENVIRONMENT is better:
setx GHC_ENVIRONMENT C:\Users\me\.ghc\x86_64-mingw32-8.10.2\environments\default
it helps for ghc and ghci.
After, in C:\Users\me\AppData\Roaming\cabal\config we should add
package-db: C:\Users\me\AppData\Roaming\cabal\store\ghc-8.10.2\package.db
it helps for cabal.
Unfortunately, ghc-pkg still has problem and works with such flag:
ghc-pkg list --user-package-db="C:\Users\me\AppData\Roaming\cabal\store\ghc-8.10.2\package.db"
For Linux the steps are similar.

Cabal Vs runhaskell, when to use?

In haskell build system, Cabal as well as runhaskell has got almost same set of sub-commands, configure, build. For runhaskell, it is:
runhaskell Setup.hs configure
runhaskell Setup.hs build
...whereas for cabal it is:
cabal build
cabal configure
So, when should I use which command? Do both the commands have same functionality?
Can I run runhaskell without sudo access, because I see runhaskell makes entries inside /opt/ghc/7.8.4/lib whereas cabal works in sudo/non-sudo mode?
cabal and runhaskell serve entirely different purpose.
runhaskell is used for executing Haskell programs without
having the need to compile them. You can place this on the top of an Haskell file: #!/usr/bin/env runhaskell and give it the scripting ability. The cabal is a package manager and a build system
for Haskell.
Also cabal and runhaskell don't share their sub-commands like
configure, build, install etc.
i saw in this link bob.ippoli.to/archives/2013/01/11/getting-started-with-haskell, two commands being used... runhaskell Setup.hs configure && runhaskell Setup.hs build
Usually Setup.hs has the following code when generated from cabal init:
import Distribution.Simple
main = defaultMain
Now if you see the implementation of defaultMain:
defaultMain :: IO ()
defaultMain = getArgs >>= defaultMainHelper simpleUserHooks
So what you are passing is actually command line arguments which can be anything. In fact you can test that yourself:
$ runhaskell Setup.hs invalid_argument
unrecognised command: invalid_argument (try --help)
runhaskell doesn’t have any subcommands:
$ runhaskell --help
Usage: runghc [runghc flags] [GHC flags] module [program args]
It takes a path to a Haskell source file and executes it right away. So you should use it when all you want is to run some Haskell code you have. Of course, you can use runhaskell without superuser access; I doubt it creates anything in /opt.
Cabal is a build-system for Haskell projects, its purpose is transforming Haskell sources into binaries.

Haskell package installed but not found

I installed diagrams, and it seems to be there, but GHCi doesn’t find it. I tried adding the local sandbox to the command line (-package-db), but still no luck.
Any suggestions?
C:\Users\guthrie>
C:\Users\guthrie>cabal install diagrams
Resolving dependencies...
All the requested packages are already installed:
diagrams-1.2
Use --reinstall if you want to reinstall anyway.
I find it in:
C:\Users\guthrie\.cabal-sandbox\i386-windows-ghc-7.6.3-packages.conf.d
(diagrams-1.2, diagrams-contrib, -core, -lib, -svg)
But running: “cabal repl” or using the GHC(i) flag “-package-db=…”
fail to find it:
C:\Users\guthrie>cabal repl
GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> :m + Diagrams.Prelude
<no location info>:
Could not find module `Diagrams.Prelude'
It is not a module in the current program, or in any known package.
Prelude>
To clarify; ignoring the cabal invocations, using GHC/i directly, and the program diagramsDemo.hs:
-- http://projects.haskell.org/diagrams/doc/quickstart.html
--
import Diagrams.Prelude
import Diagrams.Backend.SVG.CmdLine
main = mainWith (circle 1 :: Diagram B R2)
Gives:
C:\Users\guthrie\Desktop\xFer\Graphics>ghc --make diagramsDemo.hs
diagramsDemo.hs:7:8:
Could not find module `Diagrams.Backend.SVG.CmdLine'
Use -v to see a list of the files searched for.
C:\Users\guthrie\Desktop\xFer\Graphics>ghc --make diagramsDemo.hs -package-db=C:\Users\guthrie\.cabal-sandbox\i386-windows-ghc-7.6.3-packages.conf.d
diagramsDemo.hs:7:8:
Could not find module `Diagrams.Backend.SVG.CmdLine'
Use -v to see a list of the files searched for.
As bheklilr said, if ghci is started with cabal repl, it will only find packages specified as a dependency in the .cabal file.
However you can start it with cabal exec ghci, then it will find all packages installed in the sandbox.
The same is true for invoking ghc (cabal build vs. cabal exec ghc), but note that if you want to pass flags you have to use --, like in cabal exec ghc -- -O2 Main.hs. Alternatively you can use cabal exec bash and launch ghci or ghc in the new shell.
cabal exec was added with Cabal 1.20.

ghc-mod does not use my cabal sandbox. why?

runghc -package-db=.cabal-sandbox/.cabal-sandbox/x86_64-osx-ghc-7.8.3-packages.conf.d hellowai.hs
Works perfect for me.
Similarly, with
ghci -package-db=.cabal-sandbox/.cabal-sandbox/x86_64-osx-ghc-7.8.3-packages.conf.d
I am also able to import my cabal-sandbox-installed Wai package in ghci with no issue at all.
But when I ask ghc-mod to validate my haskell source code, via
ghc-mod check --boundary="" -g -package-db=.cabal-sandbox/x86_64-osx-ghc-7.8.3-packages.conf.d hellowai.hs
hellowai.hs:4:8:Could not find module ‘Network.Wai.Handler.Warp’Use -v to see a list of the files searched for.
hellowai.hs:3:8:Could not find module ‘Network.HTTP.Types’Perhaps you meant Network.HTTP.Base (from HTTP-4000.2.19) Network.HTTP.Base (needs flag -package HTTP-4000.2.10) Network.HTTP.Headers (needs flag -package HTTP-4000.2.10)Use -v to see a list of the files searched for.
hellowai.hs:2:8:Could not find module ‘Network.Wai’Perhaps you meant Network.BSD (needs flag -package network-2.4.2.3) Network.URI (needs flag -package network-2.4.2.3) Network.TCP (needs flag -package HTTP-4000.2.10)Use -v to see a list of the files searched for.
It is unable to find my cabal sandbox installed module. Why is that so?
Do you have a cabal.sandbox.config file? And are you using a .cabal file for your project?
If you have both of these you should be able to use ghc-mod check ... and it will just work.
Another advantage of using a .cabal file is that you can use cabal repl to invoke ghci and cabal run to invoke runhaskell with the correct command line options.
Update
Here is a recipe you can try out to see when ghc-mod can find your cabal sandbox. Perhaps this can help you determine what's different with your set up.
Start in a clean directory:
$ mkdir foo
$ cd foo
$ cabal sandbox init
$ cabal get split
$ cd split-0.2.2
$ cabal sandbox init --sandbox=../.cabal-sandbox
Edit around line 55 of split.cabal to add heredoc as a dependency.
Edit src/Data/List/Split.hs to use the module Text.Heredoc:
{-# LANGUAGE QuasiQuotes #-}
...
import Text.Heredoc
...
foo :: String
foo = [here|this is a test|]
Make sure heredoc is installed:
$ cabal install --only-dependencies
Finally this should work:
$ ghc-mod check ./src/Data/List/Split.hs
And it will still work if you cd into a sub-directory:
$ cd src
$ ghc-mod check ./Data/List/Split.hs
However, ghc-mod won't work if you move away split.cabal:
(back at the top level directory)
$ mv split.cabal split.cabal-old
$ ghc-mod check ./src/Data/List/Split.hs
In this case I created the sandbox in a parent directory of our working directory, but things should also work if the initial sandbox was created like this:
$ mkdir foo
$ cd foo
$ mkdir sandbox-dir
$ cd sandbox-dir
$ cabal sandbox init
$ cd ..
$ cabal get split
$ cd split-0.2.2
$ cabal sandbox init --sandbox=../sandbox-dir/.cabal-sandbox

cabal sandbox + haskeline

cabal sandbox init
cabal install haskeline
... installs successfully ...
ghci
Prelude> :module +System.Console.Haskeline
<no location info>:
Could not find module `System.Console.Haskeline'
ghc-pkg list haskeline
.. not found ..
What do I have to do get haskeline to work with cabal sandbox? If I install haskeline normally (no sandbox) it is fine (ghc-pkg list haskeline -- found it).
Either use cabal repl like Joseph mentioned or you can explicitly pass the package db to the GHCi shell relative to your current working directory.
ghci -no-user-package-db -package-db .cabal-sandbox/*-packages.conf.d YourModule.hs
It's recommended that you just use cabal.
In order to get ghci to use a local sandbox you must (a) set up a my-project.cabal file and (b) use cabal repl.

Resources