Learn common build configurations
Create a folder for simple-package.
$ mkdir simple-package
Create the following directory structure.
simple-package
- src
- Simple
- Internal.hs
- Lib.hs
- simple-package.cabal
Populate the files with the contents below.
simple-package.cabal
name: simple-package
version: 0.1.0.0
build-type: Simple
library
hs-source-dirs: src
exposed-modules: Simple.Lib
other-modules: Simple.Internal
build-depends: base >=4.8 && <4.9
default-language: Haskell2010
hs-source-dirs is a space-separated list of directories in which to search for the specified modules.
Example
hs-source-dirs: src release developer
exposed-modules is a space-separated list of modules. These modules will be available for import by packages that depend on this library.
Example
exposed-modules: Simple.Lib
Simple.Lib2
Simple.Lib3
Each module will be searched relative to the directories.
If hs-source-dirs: src src2 is present, then Etlas will attempt to find one of the following
when attempting to search for the Simple.Lib module.
other-modules is identical to exposed-modules, except the modules listed are not available for import by packages that depend on this library.
build-depends is a comma-separated list of dependency constraints.
Example
build-depends: vector == 1.2.3
, containers == 1.2.*
, base >= 4.8 && < 4.11.0
, binary > 4.3
, bytestring < 1.2
, mtl
As you can see you can use the standard comparison operators >, <, <=, >=, ==, and the && operator to specify constraints.
src/Simple/Lib.hs
1 2 3 4 5 6 | module Simple.Lib (simpleString) where
import Simple.Internal
simpleString :: String
simpleString = simpleInternalString
|
src/Simple/Internal.hs
1 2 3 4 | module Simple.Internal (simpleInternalString) where
simpleInternalString :: String
simpleInternalString = "simpleString"
|
Build your project.
$ etlas build
Suppose you wanted to make the build faster for development by turning off optimizations and turn on optimizations for a release version of your library.
You can introduce a flag like so:
simple-package.cabal
name: simple-package
version: 0.1.0.0
build-type: Simple
flag developer
description: Build without optimizations
default: False
manual: True
library
hs-source-dirs: src
exposed-modules: Simple.Lib
other-modules: Simple.Internal
build-depends: base >=4.8 && <4.9
default-language: Haskell2010
if flag(developer)
eta-options: -O0
else
eta-options: -O2
And then build your project with the flag:
etlas build -fdeveloper
For more information on all the fields you can specify, like eta-options, you can go here.
For more information about how to conditionally configure your package, go here.
We will now proceed to add an executable component that uses the library component we defined above.
Update your directory structure.
simple-package
- app
- App.hs
- App
- Config.hs
- src
- Simple
- Internal.hs
- Lib.hs
- simple-package.cabal
Populate the files with the contents below.
simple-package.cabal
name: simple-package
version: 0.1.0.0
build-type: Simple
flag developer
description: Build without optimizations
default: False
manual: True
library
hs-source-dirs: src
exposed-modules: Simple.Lib
other-modules: Simple.Internal
build-depends: base >=4.8 && <4.9
default-language: Haskell2010
if flag(developer)
eta-options: -O0
else
eta-options: -O2
executable my-app
hs-source-dirs: app
main-is: App.hs
other-modules: App.Config
build-depends: base >=4.8 && <4.9
, simple-package
hs-source-dirs: src
app/App.hs
1 2 3 4 5 6 7 | import Simple.Lib
import App.Config
main :: IO ()
main = do
putStrLn $ "Simple String: " ++ simpleString
putStrLn $ "App Config: " ++ configString
|
app/App/Config.hs
1 2 3 4 | module App.Config (configString) where
configString :: String
configString = "fast: true"
|
Run the executable.
etlas run
Normally, the run command requires an executable target, but since there is only one executable, that executable will be selected.
We often want to send arguments to our apps. We demonstrate below
Update the file contents shown below.
app/App.hs
1 2 3 4 5 6 7 8 9 10 11 | import Simple.Lib
import App.Config
import System.Environment
main :: IO ()
main = do
args <- getArgs
putStrLn $ "Arguments: " ++ show args
putStrLn $ "Simple String: " ++ simpleString
putStrLn $ "App Config: " ++ configString
|
Run the program with arguments.
etlas run my-app -- 1 2 3 someOtherArg
Note that in this case, we specified the target name my-app because we are sending in arguments as well. Moreover, the -- is used a separator between Etlas arguments and your app's arguments.
We often want to test our code so Etlas provides a test component for that purpose.
Update your directory structure.
simple-package
- app
- App.hs
- App
- Config.hs
- src
- Simple
- Internal.hs
- Lib.hs
- test
- Test.hs
- simple-package.cabal
Update the file contents shown below.
simple-package.cabal
name: simple-package
version: 0.1.0.0
build-type: Simple
flag developer
description: Build without optimizations
default: False
manual: True
library
hs-source-dirs: src
exposed-modules: Simple.Lib
other-modules: Simple.Internal
build-depends: base >=4.8 && <4.9
default-language: Haskell2010
if flag(developer)
eta-options: -O0
else
eta-options: -O2
executable my-app
hs-source-dirs: app
main-is: App.hs
other-modules: App.Config
build-depends: base >=4.8 && <4.9
, simple-package
hs-source-dirs: src
test-suite simple-unit-tests
type: exitcode-stdio-1.0
hs-source-dirs: test
main-is: Test.hs
build-depends: base >=4.8 && <4.9
, HUnit
, simple-package
test/Test.hs
1 2 3 4 5 6 7 8 9 10 11 | import Simple.Lib
import Control.Monad
import Test.HUnit
import System.Exit
main :: IO ()
main = do
results <- runTestTT $ TestCase $
assertEqual "simpleString is valid" name ""
when (failures results > 0) $ exitFailure
print results
|
Run the tests.
etlas new-test
Note that new-test functions similar to run except that it doesn't take arguments. If you have multiple test suites, you must distinguish the test suite you want to run by passing it as a target argument.
etlas new-test simple-unit-tests
NOTE: The new-test command is experimental and will become the test command soon.