Including data files in cabal builds - haskell

I have a package with the following structure (okay, this is greatly simplified, but...)
app/
src/
Main.hs
data/
data.txt
app.cabal
Paths_app.hs
Setup.hs
In Paths_app.hs I have:
module Paths_app where
getDataFileName :: FilePath -> IO FilePath
getDataFileName = return
and in Main.hs I have:
module Main where
import Paths_app
main = do
file <- getDataFileName "data/data.txt"
data <- readFile file
putStrLn $ "Your data is: " ++ data
the relevant parts of my app.cabal file look like this:
name: app
version: 1.0
build-type: Simple
data-files: data/data.txt
executable foo
build-depends: base, haskell98
main-is: Main.hs
hs-source-dirs: src
This builds fine (using cabal configure followed by cabal install) but the executable complains that it can't find the data.txt file. I've tried replacing the line
file <- getDataFileName "data/data.txt"
with
file <- getDataFileName "data.txt"
but the same thing occurs. Is there something obvious I'm doing wrong?

I've tried to reproduce it, but it works fine for me.
In the setup you describe, I had to drop the dependency on haskell98 as both base and haskell98 were providing Prelude. Furthermore, the file Main wouldn't compile as it used the keyword data as a variable name, so I renamed the variable to dat. But then it worked just fine.
Some info on my setup:
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.4.1
$ cabal --version
cabal-install version 0.13.3
using version 1.14.0 of the Cabal library
$ ls ~/.cabal/bin/
... foo ...
$ ls ~/.cabal/share/app-1.0/data/
data.txt

The problem was that I was building on a Windows system, and when I used the filename returned by getDataFileName to load data into my program, I wasn't escaping the backslashes.

Related

Code that compiles with ghc but not with cabal new-run

I have this program Main.hs:
main :: IO ()
main = do
if False then undefined
else do
let x = 5
print x
When I compile it with ghc Main.hs it compils well generating a Main executable, but when (after initializing cabal with cabal init) I try to make a cabal new-run it gives an error:
$ cabal new-run
Build profile: -w ghc-8.6.5 -O1
In order, the following will be built (use -v for more details):
- ghc-vs-cabal-0.1.0.0 (exe:ghc-vs-cabal) (file Main.hs changed)
Preprocessing executable 'ghc-vs-cabal' for ghc-vs-cabal-0.1.0.0..
Building executable 'ghc-vs-cabal' for ghc-vs-cabal-0.1.0.0..
[1 of 1] Compiling Main ( Main.hs, /home/ivan/ghc_vs_cabal/dist-newstyle/build/x86_64-linux/ghc-8.6.5/ghc-vs-cabal-0.1.0.0/x/ghc-vs-cabal/build/ghc-vs-cabal/ghc-vs-cabal-tmp/Main.o )
Main.hs:4:10: error: Empty 'do' block
|
4 | else do
| ^^
With cabal run it also gives error.
I have cabal version 2.4.0.0:
$ cabal --version
cabal-install version 2.4.0.0
compiled using version 2.4.0.1 of the Cabal library
And ghc version 8.6.5:
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.6.5
Does somebody know what is happening?
I know that I can fix it if I add indentation:
main :: IO ()
main = do
if False then undefined
else do
let x = 5
print x
But I want to know why it compiles with ghc but not with cabal new-run
Your code requires a language extension to parse: NondecreasingIndentation. This extension exists to avoid the awkward runaway effect of nested dos
main :: IO ()
main = do
if False then undefined
else do -- next block should be indented in standard Haskell
let x = 5
print x -- ...but this can easily get out of hand if you do it multiple times
NondecreasingIndentation allows a nested do block to register as nested as long as it's indented as much as the containing block, instead of more than the container.
According to the GHC manual, NondecreasingIndentation is on by default but disabled in Haskell2010 mode (unless explicitly enabled again). I can't find the corresponding cabal documentation, but we can probably guess it defaults to specifying Haskell2010.
You can specify extensions in a source file to be enabled or disabled regardless of external options by adding a pragma like
{-# LANGUAGE NondecreasingIndentation #-}
to the very top of the file.

Hardcode datadir path upon installing executable

Problem: I've got a command-line tool written in Haskell that reads a data file. Upon installing the program, I'd like for the program to be able to read that data file regardless of the directory I find myself in. That is, upon installing, the path that the program knows should be aligned with the path that the installer chooses.
Initial attempt: I was directed to the section 7.6. Accessing data files from package code in Cabal (the library) and learned that I can import getDataDir :: IO FilePath from Paths_myprog, as long as I add Paths_myprog to other-modules (although Hpack auto-includes this by default) and that after installing my program, I can run it with:
myprog_datadir=~/tmp ~/.local/bin/myprog
Then all I need to do is have the installer move the data file to this directory, since myprog dynamically accesses that path rather than some hardcoded value. But I don't want to have to specify myprog_datadir=~/tmp in my environment every time I run the program, I want it hardcoded into the binary! And it seems that setting myprog_datadir=~/tmp when building and installing doesn't set a compile-time default.
So: Is there a way I can hardcode this path upon installation?
(Preferrably, an answer that relates to Stack, but a cabal-install answer is also greatly appreciated.)
Files listed in data-files are already automatically installed in the right location so that Paths_pkg will find them. Here's a minimal example:
% cat Main.hs
import Paths_so_test
main :: IO ()
main = getDataDir >>= putStrLn
% cat so-test.cabal
cabal-version: >=1.10
name: so-test
version: 0.1.0.0
build-type: Simple
data-files: test
executable so-test
main-is: Main.hs
other-modules: Paths_so_test
autogen-modules: Paths_so_test
build-depends: base >=4.14 && <4.15
default-language: Haskell2010
% cat test
Hello, world!
% cabal install
Wrote tarball sdist to
/home/dmwit/projects/oneoff/tmp.dir/dist-newstyle/sdist/so-test-0.1.0.0.tar.gz
Resolving dependencies...
Up to date
Symlinking 'so-test'
% cat `so-test`/test
Hello, world!

How do I add the "containers" package to my .cabal file (without getting overwritten by stack at compile time)?

I am working on the "roman-numerals" task from the exercism Haskell track and followed their instructions to installing stack. I am working on a Fedora 24 box.
As long as I was working with Haskell modules from base, I didn't have a problem. Now I am trying to import the Data.Map module. It works fine using the ghci command line:
$ ghci
GHCi, version 7.8.4: 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> import Data.Map
Prelude Data.Map>
However, when I try to import it from inside my src file with the command:
import qualified Data.Map as M (foldlWithKey, fromList)
I am running into problems when I try to run the test:
$ stack test
roman-numerals-0.0.0: build (lib + test)
Preprocessing library roman-numerals-0.0.0...
[2 of 2] Compiling Roman (...)
(...) /roman-numerals/src/Roman.hs:3:1: error:
Failed to load interface for ‘Data.Map’
It is a member of the hidden package ‘containers-0.5.7.1’.
Perhaps you need to add ‘containers’ to the build-depends in your .cabal file.
Use -v to see a list of the files searched for.
Progress: 1/2
(...)
I googled the problem and found a straightforward solution at the Cabal FAQ at haskell.org:
What you need to do is to add containers to the build-depends in your .cabal file.
I am assuming they mean the file roman-numerals.cabal that is in my working directory. The contents are:
-- This file has been generated from package.yaml by hpack version 0.14.0.
--
-- see: https://github.com/sol/hpack
name: roman-numerals
version: 0.0.0
build-type: Simple
cabal-version: >= 1.10
library
hs-source-dirs:
src
build-depends:
base
exposed-modules:
Roman
other-modules:
Paths_roman_numerals
default-language: Haskell2010
test-suite test
type: exitcode-stdio-1.0
main-is: Tests.hs
hs-source-dirs:
test
build-depends:
base
, roman-numerals
, hspec
default-language: Haskell2010
I tried to add "containers" to the build-depends in either and both the "library" and "test-suite" sections, but when I run
$ stack test
the error persists, and the .cabal file is reverted to the same contents shown above.
Any pointers? Much appreciated!
This is hinting at the problem:
-- This file has been generated from package.yaml by hpack version 0.14.0.
--
-- see: https://github.com/sol/hpack
hpack is an alternative, YAML-based specification format for Haskell packages which can be used instead of the traditional cabal format. The hpack program can then be used to convert a specification from the hpack format to the cabal format to be able to integrate with the rest of the Haskell toolchain.
Some basic support for hpack was added to stack some time ago. It checks for a file called package.yaml in the current directory, which is the standard name for hpack format package specifications, and if it exists, it runs hpack to convert it to a cabal file and then proceeds building as normal. This is what's trampling over your .cabal file.
To solve this, either:
Modify package.yaml instead of roman-numerals.cabal to achieve the same effect.
Delete package.yaml and continue working directly with roman-numerals.cabal.
The syntax for adding dependencies in the hpack format is:
dependencies:
- base
- containers

cabal-dev install Happstack-server how

here is what I did:
makdir happstack_01
cabal-dev install happstack-server
write the typical helloworld.hs with "import Happstack.Server (nullConf, simpleHTTP, toResponse, ok)"
ghc -threaded HelloWorld.hs -o helloworld
and I got:
Could not find module `Happstack.Server'
This is so obvious wrong. But what I am more surprised is that no tutorial on google for simple thing as this.
Any intuition would be awesome!
This is a set of instructions for a very bare-bones, Cabalized, and sandboxed build.
$ mkdir happstack01 && cd happstack01/
$ cabal init .
$ <CR><CR><CR><CR><CR><CR><CR><CR><CR> 1 <CR><CR><CR>
$ mkdir src
$ touch src/Main.hs
$ vi happstack-01.cabal
In happstack01.cabal
...
library
exposed-modules:
Main
build-depends: base >=4.6 && <4.7
, happstack-server
hs-source-dirs: src
default-language: Haskell2010
Then
$ cabal sandbox init
$ cabal install --only-dependencies
$ vi src/Main.hs
In src/Main.hs
import Happstack.Server
main :: IO ()
main = simpleHTTP nullConf $ return "Hello sandbox!"
Get some coffee while the sandbox builds.
$ cabal repl
> main
After this I usually add an executable entry to the Cabal file and begin to build the server from that.
Since you wanted a small tutorial, I am writing up how I just got it to work. I used cabal instead of cabal-dev though (if you care, let me know and I can play around a bit more)....
> cabal install happstack-server
> mkdir sample
> cd sample
Then I created the file sample.hs
import Happstack.Server
main = simpleHTTP nullConf $ return "hello, world!"
and I compiled it
> ghc sample.hs
(This is where you seem to be having problems finding the library.... You might want to check if ~/.ghc//package.conf.d/happstack-server-7.3.1-.conf and ~/.cabal/packages/hackage.haskell.org/happstack-server/ exist to verify the download)
Then run the server
./sample
and verify that it works using curl
> curl http://127.0.0.1:8000
This should respond with
hello, world!
ok I figured this out. GHC will not regonized local sanboxed libs. at least my GHC --version 7.6.3 does not. So I will have to cabalise my project in order to make sandboxed libs work.

plugins package unknown symbol when using cabal

I'm messing around with the plugins package however I bumped into a problem.
Here's the code:
Util/Header.hs
module Util.Header(PT(..)) where
data PT a = PT a deriving Show
Plug.hs
module Plug(helloPlugin) where
import Util.Header
helloPlugin :: PT Int
helloPlugin = PT 1
Main.hs
module Main where
import Util.Header
import System.Plugins
main :: IO ()
main = do
mv <- load "Plug.o" ["."] [] "helloPlugin"
case mv of
LoadFailure msg -> print msg
LoadSuccess _ v -> print $ show (v :: PT Int)
This all works fine then compiling with ghc. Building with Cabal works fine as well, but when I run the executable I get this error:
plugintest: /home/kevin/.cabal/lib/plugins-1.5.4.0/ghc-7.6.3/HSplugins-1.5.4.0.o: unknown symbol `ghczm7zi6zi3_ErrUtils_zdsinsertzuzdsgo5_info'
plugintest: user error (resolvedObjs failed.)
My very minimalistic cabal file:
name: plugintest
version: 0.1.0.0
license-file: LICENSE
build-type: Simple
cabal-version: >=1.8
library
hs-source-dirs: src
exposed-modules: Util.Header
build-depends: base ==4.6.*, plugins ==1.5.*
executable plugintest
main-is: Main.hs
build-depends: base ==4.6.*, plugins ==1.5.*, plugintest == 0.1.0.0
hs-source-dirs: src
Now I assume the problem is that it can't find the "ErrUtils" module which is part of the ghc package installed in /usr/lib/ghc-7.x.x.
Since it's using cabal it'll use the $HOME/.cabal/lib/ instead.
Now I obviously wouldn't want to use /usr/lib if I wanted to make it distributable. Sadly I'm not very familiar with how packages are managed nor am I familiar with the plugins package.
I have a feeling this is extremly nooby but I wasn't able to find a solution myself.
So a few questions:
How can I get my dependencies to work in a way to make this distributable?
It seems I'll need to know beforehand what my Plugin.o files will depend on before actually being able to use them (If I understand correctly).
Is there a way to package a .o files that I wouldn't have to worry about this problem? (Sorry if this question is too vague, feel free to ignore)
Thanks in advance!
Ok, so I had the exact same problem.
Here is a workaround I found
Change the load call to
load "Plug.o" [".","dist/build/plugintest/plugintest-tmp"] [] "testplugin"
Make sure you compile the thing with -c or by using the "make" library from plugins.
Quite annoyed by this... The error suggests it is having issues linking against the standard libs, so why does showing it these .o files fix it?
Anyways, this worked for me, and didn't require a ton of mucking around with .cabal files.
You must declare your exported- and other- modules in order for Cabal to package them all together. For instance (from https://github.com/tel/happstack-heroku-test)
name: hktest -- note the name here names
-- the *library* which is a package name
-- in scope when building the executable
...
library
exposed-modules:
HKTest
other-modules:
-- there aren't any, but there could be some
build-depends: base >= 4.6 && <4.7
...
, mtl >= 2.1.2
hs-source-dirs: src
executable server
main-is: Server.hs
other-modules:
-- there might be some use to having these here,
-- but they'll be harder to get into GHCi, so I wouldn't
-- recommend it---just put them in the library part
build-depends: base >=4.6 && <4.7
, hktest -- note that I grab all the hktest
-- modules here
hs-source-dirs: exe
If I leave out one of those modules I'll likely get a build error as Cabal compiles files which expect to be able to find symbols that haven't been packaged.
In your case, since you're building an executable, the common pattern exemplified above is to put all of your code into a library and then have the executable side depend upon that library. For instance, in this example the complete text of exe/Server.hs is
module Main where
import qualified HKTest as HK
main :: IO ()
main = HK.main

Resources