Specifying "Up The Tree" Haskell Modules - haskell

My understanding is that the dotted syntax of modules, in Haskell, represents logical structure on disk. So, if we have a structure like this:
Main.hs
Foo/
Bar.hs -- exports "Bar"
Quux.hs -- exports "Quux"
...then in our Main.hs, we can do:
import Foo.Bar
import Foo.Quux
(I assume we can only have modules at leaf nodes of the filesystem. For example, in the above, there's no way we could have a Foo module, as well.)
In this example, we're traversing down the tree. What happens if we want to go up?
lib/
SomeModule.hs
XYZ.hs
src/
Main.hs
That is, in Main.hs, how do we import SomeModule or XYZ?
Maybe this wouldn't be a common occurrence with Main, but what about inter-module dependencies? They could legitimately need to reference "cousin" nodes.

Just use the fully qualified name of the module and tell GHC where to find the root of the module hierarchy with the -i option. In your example, this means that you should use import XYZ in Main.hs to import the module and the command ghc -i../src --make Main.hs to compile your program. If you need to compile mutually recursive modules, take a look at this section of the GHC manual.
If you're using Cabal to build your package, you can group the modules under lib in a library and then make that library a dependency of your executable. You will have the following directory structure:
some-package.cabal
lib/
XYZ.hs
src/
Main.hs
The relevant parts of the some-package.cabal file will look like this:
Name: some-package
Version: 1.0
...
Library
...
Exposed-modules: XYZ
Hs-source-dirs: lib
...
Executable some-executable
...
build-depends: some-package == 1.0
...
...
This is especially useful if your package includes a test or benchmark suite, because the modules under lib will be compiled only once.
Here's a real-life example of this technique.

Related

Build dependency in library or executable section of cabal file?

First off, I'm new to using cabal and external packages with Haskell.
I'm trying to use the Graphics.Gloss package inside of MyLib. I can make it work if I include gloss in both the build-depends of library and executable.
Here is the relevant portion of the cabal file:
library
exposed-modules: MyLib
build-depends: base ^>=4.13.0.0,
gloss ^>=1.13.1.1
default-language: Haskell2010
executable ray-tracer
main-is: Main.hs
other-modules: MyLib
build-depends: base ^>=4.13.0.0, ray-tracer,
haskell-say ^>=1.0.0.0,
gloss ^>=1.13.1.1
MyLib.hs
module MyLib (someFunc) where
import Graphics.Gloss
someFunc :: IO ()
someFunc = display (InWindow "My Window" (200,200) (10,10)) white (Circle 80)
Main.hs
module Main where
import qualified MyLib (someFunc)
import HaskellSay (haskellSay)
main :: IO ()
main = do
MyLib.someFunc
Why doesn't this work when gloss is only included in the library dependencies?
You can make it work. There is a problem in your current set up, which is that the files for the library and the executable are in the same directory. See also this question How to avoid recompiling in this cabal file? which is a symptom of the same underlying problem: when you build the executable, it rebuilds MyLib from scratch (which requires the gloss dependency) instead of reusing your library that was already built.
MyLib/
ray-tracer.cabal
MyLib.hs
Main.hs # Bad
Move the .hs files in separate directories (technically you only need to move one of them, but I think it's better to keep the root directory as uniform as possible):
MyLib/
MyLib.cabal
src/
MyLib.hs
exe/
Main.hs
And in the cabal file, add hs-source-dirs: src and hs-source-dirs: exe to the corresponding sections:
library
hs-source-dirs: src
...
executable ray-tracer
hs-source-dirs: exe
...

Telling cabal where the main module is

I have a project with this structure:
foo.cabal
src/
Foo/
Main.hs
and part of foo.cabal looks like this:
executable foo
main-is: Foo/Main.hs
hs-source-dirs: src
Main.hs has the package name Foo.Main. When I build it cabal compiles everything but doesn't create an executable because it says there is no main module.
Warning: output was redirected with -o, but no output will be generated
because there is no Main module.
What am I doing wrong?
[EDIT] If I move Main up a level and change foo.cabal to read main-is: Main.hs it works. So can I not have a nested module name for Main?
The Main module must be called Main, not Foo.Main or anything else. If you want Foo.Main, then rename main in it to something like defaultMain, then make a top level Main module that imports Foo.Main (defaultMain) and defines main = defaultMain, such as:
src/
Foo/
Main.hs
Main.hs
foo.cabal
Where
-- src/Foo/Main.hs
module Foo.Main
( defaultMain
) where
defaultMain :: IO ()
defaultMain = putStrLn "Hello, world!"
And
-- src/Main.hs
module Main where
import Foo.Main (defaultMain)
main :: IO ()
main = defaultMain
Alternatively, you could keep it Foo.Main.main and just import it qualified.
Cabal's main-is: specifies only the filename from which to build the module containing the entrypoint (default Main.main); it does not allow changing that default.
Changing the default is compiler-specific, but if you are using GHC you can do this by passing a compiler command-line option: to your Cabal file executable definition add ghc-options: -main-is Foo. You may also use a different top-level function as the entry point: ghc-options: Foo.startup for example. See -main-is <thing> in the documentation for more details.
If you're using a package.yaml (as used by hpack/Stack/etc.) you may specify for main: either:
A .hs filename, in which case that will be directly used on the main-is: line in the generated Cabal file; or
A module name or module and exported definition name (e.g., Foo or Foo.startup) in which case the appropriate ghc-options: -main-is ... will be added to the generated Cabal file and main-is: will be a filename generated from the module name (e.g. main-is: Foo.hs).

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

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.

Install part of program with cabal like library

I have simple program written with haskell, i build it with cabal. For example i my program has next directory structure:
my-prog
* Main.hs
* my-prog.cabal
* SomeDirWithHsFiles
- File1.hs
- File2.hs
I want that when i'll make cabal build and cabal install (maybe something else), SomeDirWithHsFiles with *.hs files, installed like a normal haskell library, and then i'll use File1.hs and File2.hs modules in other programm.
How can i do this?
Thank you.
You need to declare your additional files in a library section, like so:
library
exposed-modules: File1
File2
executable foo
main-is: Main.hs
See for example, xmonad's .cabal file.

Resources