Cabal: build dir with source - haskell

I have a src directory. In this directory I have Main.hs file and Test directory. In the Test directory I have Test.hs module. I need to compile it with cabal.
In my cabal file I have:
Executable main
-- .hs or .lhs file containing the Main module.
Main-is: src/Main.hs
and
-- Modules not exported by this package.
Other-modules: Test.Test
When I do cabal configure it's OK, but when I try to cabal build I get the following error:
cabal build
Preprocessing executables for main-0.0.1...
cabal: can't find source for Test/Test in ., dist/build/autogen
How can I correctly build Main.hs and some other directories with .hs files?
Thank you.

If Test.Test is defined in src/Test/Test.hs, you need
hs-source-dirs: src
in the Executable section of your Cabal file. Note that your main-is file path should be relative to the source directory, so in this case, you should change it to Main.hs.

Related

How to import Control.Lens in Haskell?

I am new to Haskell. I want to use Control.Lens package. I've read this and applied what it says but I get an error that says:
Resolving dependencies...
cabal-3.6.2.0.exe: Cannot build the executables in the package lens because it
does not contain any executables. Check the .cabal file for the package and
make sure that it properly declares the components that you expect.
when I try to run cabal install lens in the project folder.(I opened terminal in the project folder.)
Any help would be appreciated.
Solution: I've learned that I need to add 'lens' into build-depends part of .cabal file.Then I need to import Control.Lens inside Main.hs . I give my .cabal file as an example:
executable Prelude3
main-is: Main.hs
-- Modules included in this executable, other than Main.
--other-modules: Basic
-- LANGUAGE extensions used by modules in this package.
-- other-extensions:
build-depends: containers,lens,microlens,microlens-platform,base ^>=4.14.3.0
hs-source-dirs: app
default-language: Haskell2010
On the top of the Main.hs I write import Control.Lens. Finally after I run 'cabal build' and cabal run in the terminal necessary packages successfully downlaoaded.

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 doesn't find Source.hs

My project structure is as follows:
~/.../project_name
project_name.cabal
Setup.hs
src/
Main.hs
Data/
...
test/
MainTestSuite
...
I have (amongst others) the following lines in my project.cabal:
build-type: Simple
...
executable project_name
main-is: Main.hs
...
hs-source-dirs: src
When I cabal configure (works fine) and then cabal build I get the error message:
cabal: can't find source for Setup in src, dist/build/autogen
It works when I put Source.hs in src but this seems messy to me and I haven't seen this in other projects, where Source.hs is always in the project root. How do I get cabal to find Source.hs?
As an aside: What's the purpose of Source.hs anyways?
The problem was caused by accidently adding the Source file as a dependency in other-modules in the cabal-file of the project ... that caused all the trouble.
hs-source-dirs: ., src comes to mind as a fast fix.
That's what my projects use, and I generate my cabal files automatically (so I suppose that's the default).

How to make a Haskell cabal project with library+executables that still run with runhaskell/ghci?

If you declare a library + executable sections in a cabal file while avoiding double compilation of the library by putting the library into a hs-source-dirs directory, you cannot usually run your project with ghci and runhaskell anymore, especially if the executables have helper modules themselves.
What is a recommended project layout that
only builds what is needed once
allows using runhaskell
has a clean structure without hacks?
Let's assume you have a mylib library, and mylib-commandline and mylib-server executables.
You use hs-source-dirs for the library and each executable so that each has their own project root, avoiding double compilation:
mylib/ # Project root
mylib.cabal
src/ # Root for the library
tests/
mylib-commandline/ # Root for the command line utility + helper modules
mylib-server/ # Root for the web service + helper modules
Full directory layout:
mylib/ # Project root
mylib.cabal
src/ # Root for the library
Web/
Mylib.hs # Main library module
Mylib/
ModuleA # Mylib.ModuleA
ModuleB # Mylib.ModuleB
tests/
...
mylib-commandline/ # Root for the command line utility
Main.hs # "module Main where" stub with "main = Web.Mylib.Commandline.Main.main"
Web/
Mylib/
Commandline/
Main.hs # CLI entry point
Arguments.hs # Programm command line arguments parser
mylib-server/ # Root for the web service
Server.hs # "module Main where" stub with "main = Web.Mylib.Server.Main.main"
Web/
Mylib/
Server/
Main.hs # Server entry point
Arguments.hs # Server command line arguments parser
The stub-like entry point file mylib-commandline/Main.hs looks like this:
module Main where
import qualified Web.Mylib.Server.Main as MylibServer
main :: IO ()
main = MylibServer.main
You need them because an executable must start on a module simply called Main.
Your mylib.cabal looks like this:
library
hs-source-dirs: src
exposed-modules:
Web.Mylib
Web.Mylib.ModuleA
Web.Mylib.ModuleB
build-depends:
base >= 4 && <= 5
, [other dependencies of the library]
executable mylib-commandline
hs-source-dirs: mylib-commandline
main-is: Main.hs
other-modules:
Web.Mylib.Commandline.Main
Web.Mylib.Commandline.Arguments
build-depends:
base >= 4 && <= 5
, mylib
, [other depencencies for the CLI]
executable mylib-server
hs-source-dirs: mylib-server
main-is: Server.hs
other-modules:
Web.Mylib.Server.Main
build-depends:
base >= 4 && <= 5
, mylib
, warp >= X.X
, [other dependencies for the server]
cabal build will build the library and the two executables without double compilation of the library, because each is in their own hs-source-dirs and the executables depend on the library.
You can still run the executables with runghc from your project root, using the -i switch to tell where it shall look for modules (using : as separator):
runhaskell -isrc:mylib-commandline mylib-commandline/Main.hs
runhaskell -isrc:mylib-server mylib-server/Server.hs
This way, you can have a clean layout, executables with helper modules, and everything still works with runhaskell/runghc and ghci. To avoid typing this flag repeatedly, you can add something similar to
:set -isrc:mylib-commandline:mylib-server
to your .ghci file.
Note that sometimes should split your code into separate packages, e.g. mylib, mylib-commandline and mylib-server.
You can use cabal repl to start ghci with the configuration from the cabal file and cabal run to compile and run the executables. Unlike runhaskell and ghci, using cabal repl and cabal run also picks up dependencies from cabal sandboxes correctly.

Why does "cabal sdist" not include all "files needed to build"?

According to the wiki entry,
It packages up the files needed to build the project
I have a simple executables-only .cabal project, which basically contains
Executable myprog
hs-source-dirs: src
main-is: MyMain.hs
and is made up of some additional .hs files below src/ beyond src/MyMain.hs. E.g., src/Utils.hs and a few others.
cabal build has no problems building myprog, and compiles the required additional .hs files below src/, but cabal sdist does not, thus creating a dysfunctional source-tarball. What am I doing wrong? How do I tell cabal to include all source files below hs-source-dirs?
As a side-note, with GNU Autotools, there was a make distcheck target, which would first build a source-tarball, and then try to build the project via the newly generated source-tarball, thus ensuring everything's ok. Is there something similar for cabal, in order to make sure my source-tarball is sound?
You should list the other Haskell files in the .cabal file, inside the Executable stanza.
other-modules: Utils AFewOthers
The distribution only includes source files that are listed in your .cabal file. Cabal has no other way to detect which source files are in your package. You could still build because cabal build calls ghc --make, and ghc will find and compile all the source files it needs.

Resources