I'm getting an error that says the module doesn't exist when I try to runhaskell. It's odd because I try to install it first and says its up to date. Any idea how to fix this?
You could try creating the package environment in the local directory that holds your project, like this:
c:\Users\...\ex1haskell> cabal install --lib --package-env . QuickCheck
This should create a file of the form .ghc.environment.xxx in ex1haskell, which hopefully should be picked up by runhaskell/ghci/ghc invocations.
In ghci sessions, a sign that the environment is being picked up is the following message while starting:
Loaded package environment from ...
When the --package-env location is not given explicitly, a default location is used. According to the docs:
By default, it is writing to the global environment in
~/.ghc/$ARCH-$OS-$GHCVER/environments/default. v2-install provides the
--package-env flag to control which of these environments is modified.
But it seems that runhaskell is having problems to find the environment file in that default location.
Note. When creating a package environment, it's possible to specify multiple packages simultaneously, like this:
cabal install --lib --package-env . QuickCheck random aeson transformers
Also, package environments are just text files, so local environments can be deleted and recreated at will. The actual package binaries reside elsewhere and can potentially be reused by cabal.
A Common Environment
It is hard to debug if/when the actual tooling differs so let's first get a unified setup. I'll use docker to get GHC 8 and Cabal 3.x:
docker run --rm -it haskell bash
Understand that this isn't arbitrary or even preemptive. What you have shown - cabal install --lib ... and runhaskell ... does work for sane tool installations. You might have a bad installation or an old version of a tool that has different behavior.
Running a single file with runhaskell
Now we need a project:
root#8a934c302dba:/# mkdir Ex1
root#8a934c302dba:/# cd Ex1
root#8a934c302dba:/Ex1# cat <<EOF >Main.hs
> import Test.QuickCheck
>
> main :: IO ()
> main = print =<< (generate arbitrary :: IO Int)
> EOF
And test failure:
root#8a934c302dba:/Ex1# runhaskell Main.hs
Main.hs:1:1: error:
Could not find module `Test.QuickCheck'
Use -v (or `:set -v` in ghci) to see a list of the files searched for.
|
1 | import Test.QuickCheck
And install the library:
root#8a934c302dba:/Ex1# cabal update && cabal install --lib QuickCheck
And successful run:
root#8a934c302dba:/Ex1# runhaskell Main.hs
15
So my comment above was wrong - we don't need to explicitly list the package as it is already exposed after installation.
Related
I installed the timezone-series Haskell module using cabal install timezone-series-0.1.5.1.
I then defined a module named Main.hs that starts with:
import Data.Time.LocalTime.TimeZone.Series -- from timezone-series-0.1.5.1
when I run ghc Main.hs, GHC throws the following error:
/home/ubuntu/Main.hs:2:1: error:
Failed to load interface for ‘Data.Time.LocalTime.TimeZone.Olson’
I tried explicitly including the cabal directory in GHC's search path using:
ghc -i/home/ubuntu/.cabal/lib/x86_64-linux-ghc-8.0.2/timezone-olson-0.2.0-KqRNJj3zomR7zz2Yx6P5Oq/ Main.hs
This resulted in the correct path being searched, but GHC is only looking for files ending in the suffix ".hs":
Locations searched:
...
/home/ubuntu/.cabal/lib/x86_64-linux-ghc-8.0.2/timezone-olson-0.2.0-KqRNJj3zomR7zz2Yx6P5Oq/Data/Time/LocalTime/TimeZone/Series.hs
/home/ubuntu/.cabal/lib/x86_64-linux-ghc-8.0.2/timezone-olson-0.2.0-KqRNJj3zomR7zz2Yx6P5Oq/Data/Time/LocalTime/TimeZone/Series.lhs
/home/ubuntu/.cabal/lib/x86_64-linux-ghc-8.0.2/timezone-olson-0.2.0-KqRNJj3zomR7zz2Yx6P5Oq/Data/Time/LocalTime/TimeZone/Series.hsig
/home/ubuntu/.cabal/lib/x86_64-linux-ghc-8.0.2/timezone-olson-0.2.0-KqRNJj3zomR7zz2Yx6P5Oq/Data/Time/LocalTime/TimeZone/Series.lhsig
Cabal installed interface files instead however:
/home/ubuntu/.cabal/lib/x86_64-linux-ghc-8.0.2/timezone-olson-0.2.0-KqRNJj3zomR7zz2Yx6P5Oq/Data/Time/LocalTime/TimeZone/Olson.hi
From line 318 of GHC's source code it looks like GHC ignores "*.hi" files unless it is called in single-shot mode (with the -c flag). Is this correct? (See: https://github.com/ghc/ghc/blob/67a5a91ef5e61f3b3c84481d8a396ed48cd5d96e/compiler/GHC/Unit/Finder.hs)
How can I get GHC to import this module?
An help will be greatly appreciated!
My suggested ways of installing packages in order of my preference:
Make a cabal package and add timezone-series you want to install to the build-depends field as described in the cabal manual.
Use the experimental cabal-env tool to basically automate the process of point 3 below, but then with the global environment. This makes a new build-plan every time you install a new package, so it is like removing the package environment and building it again with all the old packages and the new package added to it. You can add specific constraints like this: cabal-env "timezone-series == 0.1.5.1".
Install a package into local package environment with cabal --package-env . --lib timezone-series. You can add as many packages as you want after the --lib option to install more than one package. If you later want to use a different set of packages simply remove the .ghc.environment.* file that is generated and rerun the installation with a new set of packages. GHC will automatically use these package environment files that are in the current or parent directories. You can specify specific constraints with the --constraint option like this: --constraint "timezone-series == 0.1.5.1".
Use cabal install --lib timezone-series to install it directly into the global environment (~/.ghc/x86_64-linux-8.0.2/environments/default), this will fail if a conflicting package was installed earlier. When you run into errors you can remove that package environment and try again.
Finally, I want to note that GHC 8.0.2 is quite old, so I would advise you to upgrade if you don't have a specific reason for using that version.
I put this in a file (see bottom) and got the following error when loading it in ghci (i.e. start ghci then :l file):
7:13: error:
• Couldn't match expected type ‘network-uri-2.6.1.0#network-uri-2.6.1.0-7BN1tbB3iHQ2XgvmqLAYph:Network.URI.URI’
with actual type ‘Network.URI.URI’
NB: ‘Network.URI.URI’
is defined in ‘Network.URI’
in package ‘network-uri-2.6.1.0#network-uri-2.6.1.0-80FpvaNUTSDFCPv0sSze40’
‘network-uri-2.6.1.0#network-uri-2.6.1.0-7BN1tbB3iHQ2XgvmqLAYph:Network.URI.URI’
is defined in ‘Network.URI’
in package ‘network-uri-2.6.1.0#network-uri-2.6.1.0-7BN1tbB3iHQ2XgvmqLAYph’
Have I somehow installed two slightly different versions of network-uri, or what is this? How do I resolve it?
I've hardly used cabal but tried cabal install --reinstall network-uri, went fine but problem persists.
File contents:
import Network.HTTP
import Network.URI (parseURI)
import Data.Maybe (fromJust)
myRequestURL = "http://www.virginia.edu/cgi-local/ldapweb"
myRequest :: String -> Request_String
myRequest query = Request {
rqURI = fromJust $ parseURI myRequestURL
, rqMethod = POST
, rqHeaders = [ mkHeader HdrContentType "text/html"
, mkHeader HdrContentLength $ show $ length body ]
, rqBody = body
}
where body = "whitepages=" ++ query
main :: IO ()
main = do
response <- simpleHTTP $ myRequest "poon"
putStrLn ""
EDIT Re-installed haskell-platform. After this, ghc-pkg list reports all packages to be under (?) /usr/lib/ghc/package.conf.d, and the program I tried to copy loads just fine.
EDIT 2 After running cabal install some-pkg, ghc-pkg list reports that the newly installed stuff is in another directory. Indeed, ~/.cabal/config specifies install dirs for user, as well as install dirs for global. How is all this supposed to be managed properly?
GHC understands the concept of package databases. Cabal manages multiple package databases. There's a system package database, and a user package database. When you compile something with Cabal V1, it uses the union of these package databases. This is a bit of a time bomb, because, as you see, GHC does not like it when you have multiple of the same package. When you issued cabal install network-uri, cabal decided to install one copy of that package into your user database, though you already had one in the system database. When you tried to use ghc, it picked up on the two copies and got confused. Because cabal does not support removing packages, your Haskell installation was pretty much borked, and you reinstalled. I believe you could have done a more conservative rm ~/.ghc, or, had you been really adventurous, used the low-level ghc-pkg command to edit the package database.
Now that you've reinstalled the Platform, I would heavily recommend never using cabal install again. It's old, it's broken, cabal itself tells you not to use it. If you're using the Platform, I think it has stack in it, which is a different build manager, based on Cabal, which is not prone to this kind of breakage. Or, you can just stick to the V2 series of cabal commands, which is what I prefer.
Cabal V2 does not directly support your usecase, where you install a package globally and compile a program against it. This is because doing so is fundamentally broken: global package databases really just don't work for GHC. What Cabal V2 does is install packages into your home directory, ~/.cabal/store. You then have to explicitly tell it which packages you want, and it will construct a package database that contains each required package, without any wonkiness. You can get a REPL with a certain set of packages by issuing (this will take you to a temporary directory; you may need to :cd yourself back.)
cabal v2-repl -b network-uri -b package2 -b etc
If you want to actually compile files with ghc with a set packages, you have to actually define a package with a .cabal file. Here's a stub .cabal file:
name: temporary-pkg
version: 0.0.0.0
build-type: Simple
cabal-version: >=2.0
executable main -- if there is no Main, say "library" instead of "executable <name>"
default-language: Haskell2010
main-is: Main.hs -- only valid in executable stanzas
hs-source-dirs: src -- source files go here
build-depends: base, network-uri, package2, etc -- packages go here
Create and enter a directory, place that in temporary-pkg.cabal, place your sources in src/, and you can issue stuff like cabal v2-build and cabal v2-repl and cabal v2-exec main, etc. cabal will go off and install dependencies from Hackage into ~/.cabal/store as needed. cabal v2-install is therefore not that useful here. In general, v2-installing libraries is unnecessary, but v2-installing packages with executables is useful. Again, for hygiene reasons, you have to list all the packages you are importing from, but you don't need to list their dependencies or anything insane like that.
Cabal V2 still doesn't support uninstalling packages, though the point is that should not be necessary. However, if you find ~/.cabal/store getting too large for your liking, you can just nuke it, and should be built back up as packages are requested.
Pandoc comes with several default templates, which are distributed with the pandoc package. However, if I write an application that uses pandoc as a library, those default templates don't get included in the binary. I can still use them on my machine:
module Main where
import Text.Pandoc (getDefaultTemplate)
main = getDefaultTemplate Nothing "latex" >>= print
This will print the default.latex template. However, it's not portable, since it really refers to a file somewhere on my system:
$ cd path/to/example/project
$ stack build
$ scp path/to/binary remote:remote/path
$ ssh remote:remote/path/binary
example: Could not find data file /home/Zeta/.stack/snapshots/.../pandoc-1.16.0.2/data/templates/default.latex
Since pandoc's debian package does not include those files, it's somehow able to embed them. And indeed, there is a flag -f embed_data_files. I've tried to enable it in the local stack.yaml:
extra-deps: [pandoc-1.16]
flags:
pandoc:
embed_data_files: true
But that didn't change anything, the compiled binary still complains about missing data files.
So, is there any way to automatically include pandoc's template files?
It turns out that pandoc injects its data files during its build via hsb2hs. Somehow that step failed during stack build I missed the error message.
Neither hsb2hs nor its main dependency processing-tools are part of stack's LTS, they're only in the nightly stackage versions. The following additions to stack.yaml fixed the problem:
# part of stack.yaml:
extra-deps:
- preprocessor-tools-1.0.1
- hsb2hs-0.3.1
- pandoc-1.16
flags:
pandoc:
embed_data_files: true
For those using Cabal, this is somewhat equal to
cabal sandbox init
cabal update
cabal install hsb2hs-0.3.1 && cabal install pandoc-1.16 -f embed_data_files
cabal install --dependencies-only
cabal build
Here's how I verified that the templates are actually included:
$ stack build
$ grep "usepackage\{hyperref\}" .stack-work/install/*/bin/example -a
\usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry}
$endif$
\usepackage{hyperref}
$if(colorlinks)$
\PassOptionsToPackage{usenames,dvipsnames}{color} % color is loaded by hyperref
That snippet is part of default.latex, so it's really included in the binary.
I have a package named commands. I want to install it into its own sandbox e.g. .cabal-sandbox/x86_64-osx-ghc-7.8.3-packages.conf.d/commands-0.0.0-f3f84f48f42ac74a69ee5fd73512bfd0.conf. currently, there is just one .hi interface file for one module Commands, I don't know how it got there.
I tried cabal install commands, by the logic of "that's how the other packages got there I think", but it fails with unknown package.
I also tried stuff with ghc-pkg like ghc-pkg update commands -f .cabal-sandbox/x86_64-osx-ghc-7.8.3-packages.conf.d but I'm not using them right. ideally, I'd like to do this with cabal.
the last thing I tried was ghc -idist/build/, but it complained about the package names in the interface files being different, command versus main ("... differs from name found in the interface file ..."). and if I faked the executable's package with ghc -package-name commands-0.0.0, the linker complained that it couldn't find the symbol _ZCMain_main_closure, because every executable needs the function main in the module Main in the package main.
I'm sure there's a better way of doing this.
I followed online examples for my cabal file:
$ cat commands.cabal
name: commands
library
exposed-modules: Commands.Types, Commands.Bits
...
the minimal failing code example is just:
$ cat Main.hs
import Commands.Types
main = return ()
in the root project directory.
Context: I need to build my executable with make (not cabal) because it links to foreign code (Objective-C via language-c-inline). my makefile: https://github.com/sboosali/Haskell-DragonNaturallySpeaking/blob/master/Makefile). thus, I have to compile a script explicitly. I don't know how to compile the executable with cabal, but I want cabal to build and test and manage my library.
By putting my package into the sandbox, I will be able to import its modules from the script, by compiling with cabal exec -- ghc. I will also be able to include the script with extra-source-files at least, and know it will work.
Here's what I'd try:
First unregister any previous commands library. Try
ghc-pkg --global unregister commands
Install new commands to your sandbox.
From your sandbox directory, try this:
cabal --enable-shared --disable-documentation --prefix=./ install /path/to/your/library/source
Note the prefix specification.
I nuked it (rm -fr .cabal-sandbox/), reinstalled everything (cabal install --only-dependencies), added itself as a source (cabal sandbox add-source .), installed it (cabal install command). and then make worked. idk...
I’m trying to write a project with the Hakyll library. In order to avoid messing up with my system, I’d install it in a cabal sandbox in the same folder where my Hakyll project lives.
Being more or less a beginner, I’m still struggling with getting the pest practices right. A simple approach would be to just do
$ cabal sandbox init
$ cabal install hakyll
$ cabal exec ghc -- --make site.hs
where the last line compiles my Hakyll generator using the libraries in the sandbox. The obvious disadvantage is that this is not reproducible. The main version of Hakyll could have change when I try to run it again from a clean checkout.
Another approach would be to write a proper project.cabal file (For example like this: chromaticleaves.cabal) and then do cabal install or cabal run.
However, I feel that this may be a bit too much information. As I do not intend to publish this project any more than needed, I’m not really convinced I need to put a project name and version number in there. (For example, in a Ruby Gemfile, I would also only specify the libraries and nothing else unless I wanted to publish a gem myself.)
So, eventually I figured that with a file like
$ cat project.cabal
cabal-version: >= 1.2
library
build-depends: base >=4.6
, containers
, process
, hakyll >=4.5
, pandoc
, pandoc-types
I can type
$ cabal sandbox init
$ cabal install --only-dependencies
$ cabal exec ghc -- --make site.hs
and it seems to download all dependencies and is able to compile the file.
Is this a reasonable approach or is the best practice really to give a full specification with name, version and executable sections in the cabal file?
Edit: Apparently, my approach does not let me do cabal repl. So either there exists a completely different way of doing it or it seems I have to go with a fuller specification.
I use your first approach myself for my Hakyll-based webpage. You don't need to create a .cabal file to pin the Hakyll version, you only need to add the following line to cabal.config:
constraints: hakyll == 4.5
I think that cabal repl will work with this approach, but you will need to load site.hs manually (:l site.hs). Or you can use cabal exec ghci -- site.hs.