How to configure build-dependencies in haskell+cabal? - haskell

I have to build some app that depends on OS. For example I'm searching over directory, and if I see some item is symbolic link (in linux), I just skip them and go over. To check this I use function System.Posix.Files.isSymbolicLink that ships by "unix" package. The problem is that this package would not build on Windows, and I have to bypass this limitation somehow when app builds on Windows. I've tried this trick:
1) Created additional file: ./System/Posix/Files.hs, where exposed function isSymbolicLink which always returns False.
2) Updated .cabal file with following:
if os(windows)
other-modules: System.Posix.Files
else
build-depends: unix
But, despite my configuration, cabal build always builds my /System/Posix/Files.hs since I have import System.Posix.Files in my main.hs:
Preprocessing executables for test-1.1.1...
Building test-1.1.1...
[1 of 2] Compiling System.Posix.Files ( System/Posix/Files.hs, dist/build/test/test-tmp/System/Posix/Files.o )
[2 of 2] Compiling Main ( main.hs, dist/build/test/test-tmp/Main.o )
Linking dist/build/test/test ...
So even I build on linux, application gets my blank isSymbolicLink function instead those provided by "unix" package. How can I tell to cabal do not include this file, and use module provided by "unix" package when I build on linux? Or maybe there is some another approach to solve such problems?

This can be solved using the CPP preprocessor.
In your .cabal file, add
if os(windows)
Cpp-options: -DWINDOWS
else
Build-depends: unix
Then add a module which will conditionally export isSymbolicLink from the unix package, or a dummy one for Windows.
{-# LANGUAGE CPP #-}
module Compatibility (isSymbolicLink) where
#ifndef WINDOWS
import System.Posix.Files
#else
isSymbolicLink _ = return False
#endif
Now just import this module whereever you need to use this function, and you should be good to go.
Another option is to stick with your initial approach, but move your System/Posix/Files.hs into a subdirectory which you conditionally add to Hs-Source-Dirs.
if os(windows)
Other-modules: System.Posix.Files
-- Assuming you moved it to windows/System/Posix/Files.hs
Hs-source-dirs: .,windows
else
Build-depends: unix
Hs-Source-Dirs: .

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 can I configure Cabal to build two executables?

I'm trying to build a Haskell project using Cabal. I have a file src/Main.hs which contains the module Main and a function main. That file runs the web interface of my app. And I have another file, src/CLI.hs which contains the module CLI and a function main. I can run it just fine with runhaskell CLI ..., but I can't seem to compile it using cabal.
The thing is, even if I specify CLI.hs as the main file (main-is: CLI.hs), it still compiles the project with the main from src/Main.hs, thereby giving me the web app instead of the CLI.
I want to be able to compile two executables, one which is the web app, and one which is the CLI, specifying the entry points of each as main in CLI.hs and main in Main.hs, respectively.
Here's the segment of the .cabal file I'm using at the moment:
executable color-word-analyzer-cli
main-is: CLI.hs
other-modules: AnnotateColors
, CategorizeColor
, ColorMaps
, FindColors
, PlotColors
, Types
, Main
build-depends: base
, lucid
...
, wai-middleware-static
hs-source-dirs: src/
default-language: Haskell2010
executable color-word-analyzer-web
main-is: Main.hs
other-modules: AnnotateColors
, CategorizeColor
, ColorMaps
, FindColors
, PlotColors
, Types
, CLI
build-depends: base
, lucid
...
, wai-middleware-static
hs-source-dirs: src/
default-language: Haskell2010
Which throws the error (among others):
Building executable 'color-word-analyzer-cli' for color-word-analyzer-0.1.0.0..
Warning: Enabling workaround for Main module 'Main' listed in 'other-modules'
illegally!
<no location info>: warning: [-Wmissing-home-modules]
These modules are needed for compilation but not listed in your .cabal file's other-modules:
Main
which is funny, since Main is clearly listed there in other-modules.
I'm using cabal version 3.0.0.0, and ghc version 8.8.2.
The fully explicit form of a compilation unit is <package>:<category>:<ident> where in the case the packages is color-word-analyzer, category is exe and ident is the executables. So for your case you can call:
cabal build color-word-analyzer:exe:color-word-analyzer-cli color-word-analyzer:exe:color-word-analyzer-web
Now you don't actually need to specify all of that. When the executable is unique the fact that it is an executable (and not, say, a test from some other package or another package name itself) and the fact that it is from color-word-analyzer is clear in this context. You can therefore call:
cabal build color-word-analyzer-cli color-word-analyzer-web
EDIT: because your link didn't have a stanza for -web I used one of my own creation which didn't include the CLI module. Notice your CLI file is module Main so that explains the error you see - you can't include a module Main as a library module.

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

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

cabal FFI dependency

I am making a small Haskell game in Windows, where I would like to respond each time the user presses a key. Because getChar behaves strangely on Windows, I use FFI to get access to getch in conio.h, as described here. The relevant code is:
foreign import ccall unsafe "conio.h getch" c_getch :: IO CInt
This works fine, when I run it in ghci, or compile it with ghc. I also want to try making a cabal package out of it, so extending from this question, I include the following in my cabal file:
...
executable noughts
Includes: conio.h
Extra-libraries conio
...
But when I run cabal configure, it tells me:
cabal: Missing dependency on a foreign library:
* Missing C library: conio
It makes sense, because in my haskell platform directory, under ...\Haskell Platform\2012.4.0.0\mingw there is a conio.h file under the include directory, but no other conio file to provide the object code.
Am I doing this the right way, and if so, how can I find out which library to include in my cabal file?
First off, there is not always a one-to-one mapping between C header files and libraries. In this case, the functions declared in conio.h can be found in various runtime libraries, such as crtdll (deprecated) or msvcrt (preferred, I guess).
With the Haskell Platform on Windows, Cabal will look for these libraries in .\mingw\lib (under your Haskell Platform directory): if you ask for msvcrt, it will look for .\mingw\lib\libmsvcrt.a. This specific library should already be shipped with your Haskell Platform. (If you want to point to other directories with lib*.a files, you can use Cabal's --extra-lib-dirs option.)
A tiny example of this would be as follows; this is Main.hs:
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.C.Types
foreign import ccall unsafe "conio.h _putch" c_putch :: CInt -> IO ()
main :: IO ()
main = do
c_putch . toEnum . fromEnum $ '!'
c_putch . toEnum . fromEnum $ '\n'
And this would be something-awesome.cabal:
name: something-awesome
version: 0.1.0.0
build-type: Simple
cabal-version: >=1.8
executable yay
main-is: Main.hs
build-depends: base ==4.5.*
includes: conio.h
extra-libraries: msvcrt
This should work fine:
c:\tmp\something-awesome> dir /B
Main.hs
something-awesome.cabal
c:\tmp\something-awesome> cabal configure
Resolving dependencies...
Configuring something-awesome-0.1.0.0...
c:\tmp\something-awesome> cabal build
Building something-awesome-0.1.0.0...
Preprocessing executable 'yay' for something-awesome-0.1.0.0...
[1 of 1] Compiling Main ( Main.hs, dist\build\yay\yay-tmp\Main.o )
Linking dist\build\yay\yay.exe ...
c:\tmp\something-awesome> dist\build\yay\yay.exe
!

Resources