How to get a graph of dependencies of Haskell project - haskell

I have a several executable targets in the project, like:
...
app/
other_app/
src/
package.yaml
stack.yaml
...
so, I have obviously different .hs files in app/, other_app/, src/. If I build it with stack tool then it build apps and other_apps executables from their dependencies, ie, if some .hs file changed in src/ - the result executable will be rebuild. Otherwise - no. stack knows a graph of dependencies like GNU make does it. How to list/print this graph? For example, for C I have makedepend tool which is able to extract dependencies recursively from .c files. Is it possible to be done for Haskell files? With stack tool itself? Maybe with a cabal tool? I tried, for example, v2-freeze of the cabal tool, but it is not related to the problem.
UPDATE:
package.yaml looks like:
.............
executables:
app1-exe:
main: Main.hs
source-dirs: app1
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- app1
app2-exe:
main: Main.hs
source-dirs: app2
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- app1
............
and now I want to list recursively dependencies (in Makefile-style, not dependencies on packages, like stack dot does it!), for instance for app2's Main.hs, something like:
src/Component1/Types.hs
src/Component1/Utils.hs
src/CoolLibrary/CoolUtility.hs
...

Related

Adding dependencies to stack project

I am very new to Haskell and I am trying to add the graphics package gloss to my stack project but I am encountering problems when doing stack build.
I have created my stack project as follows:
LICENSE package.yaml stack.yaml
README.md package.yaml~ stack.yaml.lock
Setup.hs project39.cabal stack.yaml~
TAGS project39.cabal~ test
and edited the stack.yamland the cabal file as follows:
# extra-deps:
# - acme-missiles-0.3
# - git: https://github.com/commercialhaskell/stack.git
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
# - gloss-1.13.2.1
executable project39-exe
main-is: Main.hs
other-modules:
Paths_project39
hs-source-dirs:
app
ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends:
base >=4.7 && <5
, project39
, gloss
default-language: Haskell2010
In the src file Lib.hs I have added a Import Graphics.Gloss to test if it works:
module Lib
( someFunc
) where
import Graphics.Gloss
but when I then do stack build I get the following error:
Could not load module ‘Graphics.Gloss’
It is a member of the hidden package ‘gloss-1.13.2.1’.
Perhaps you need to add ‘gloss’ to the build-depends in your .cabal file.
Use -v (or `:set -v` in ghci) to see a list of the files searched for.
|
4 | import Graphics.Gloss
| ^^^^^^^^^^^^^^^^^^^^^
I am unsure what the problem here is and how to solve it.
You have a separate library stanza in your package.yaml. You need to add the gloss dependency there.

Building multiple executables in the default Haskell Stack project

I used the default stack new to setup a project that has a server and a client as separate executables. I altered the package.yaml file in what seems like the right way (As of April 21, 2020 "There is no user guide") and added a new file to my app directory called Client.hs.
I got an error saying "Enabling workaround for Main module 'Main' listed in 'other-modules' illegally!"
How do I have stack build both the client and the server?
When I ran stack build I got:
[... clip ...]
Building executable 'ObjectServer' for ObjectServer-0.1.0.1..
[4 of 4] Compiling Client
Linking .stack-work\dist\29cc6475\build\ObjectServer\ObjectServer.exe ...
Warning: Enabling workaround for Main module 'Main' listed in 'other-modules'
illegally!
Preprocessing executable 'Client' for ObjectServer-0.1.0.1..
Building executable 'Client' for ObjectServer-0.1.0.1..
[3 of 3] Compiling Client
<no location info>: error:
output was redirected with -o, but no output will be generated
because there is no Main module.
-- While building package ObjectServer-0.1.0.1 using:
D:\HaskellStack\setup-exe-cache\x86_64-windows\Cabal-simple_Z6RU0evB_3.0.1.0_ghc-8.8.3.exe --builddir=.stack-work\dist\29cc6475 build lib:ObjectServer exe:Client exe:ObjectServer --ghc-options " -fdiagnostics-color=always"
Process exited with code: ExitFailure 1
The relevant portion of package.yaml looks like this:
executables:
ObjectServer:
main: Main.hs
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- ObjectServer
Client:
main: Client.hs
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- ObjectServer
There are two problems here. First, the default value for other-modules in hpack is "all modules in source-dirs except main and modules mentioned in a when clause". If you look at the generated .cabal file, you'll see that as a result of this default, each executable has incorrectly included the other executable's module in its other-modules list. Second, the main setting gives the source file that contains the main module, but doesn't change the name of the module expected by GHC from Main to anything else. Therefore, that module still needs to be named module Main where ..., not module Client where..., unless you also, separately add a -main-is Client GHC option.
So, I would advise modifying Client.hs to make it the Main module:
-- in Client.hs
module Main where
...
and then specifying other-modules: [] explicitly for both executables:
executables:
ObjectServer:
main: Main.hs
other-modules: []
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- ObjectServer
Client:
main: Client.hs
other-modules: []
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- ObjectServer
That seems to work in my testing.

Re-use tests between packages in Stack

I'm curious if it's possible to expose test folder of one package, so another package in multi-package Stack setup could re-use test functions & instances:
second-package-test -> dependsOn -> first-package-test
The first package has the following lines in package.yaml:
tests:
first-package-test:
main: Spec.hs
source-dirs: test
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- first-package
- hspec
- QuickCheck
- quickcheck-instances
- quickcheck-classes
And the second package that should rely on the first one has the following setup:
stack.yaml contains:
extra-deps:
- ../first-package <-- it seems that it imports only library, not the tests
package.yaml contains:
tests:
second-package-test:
main: Spec.hs
source-dirs: test
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- second-package
- hspec
- QuickCheck
- quickcheck-instances
- quickcheck-classes
The root aggregation of them looks simple. stack.yaml:
packages:
- first-package
- second-package
I think, in theory, it's possible to create a third package with tests only that are exposed as a library, but wonder if there is a bit more elegant way to achieve the same thing.

How to use stack with nix to build wxHaskell project?

I'm trying to set up a build environment for wxHaskell using Nix and Stack.
I've installed wxWidgets-3.0.2 through nix. This is the relevant portion from by .cabal file
executable hellowx-exe
hs-source-dirs: app
main-is: Main.hs
ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends: base
, hellowx
, wx
, wxc
, wxcore
, wxdirect
and the stack.yaml file
resolver: lts-5.0
extra-deps:
- wx-0.92.2.0
- wxc-0.92.2.0
- wxcore-0.92.2.0
- wxdirect-0.92.2.0
I tried adding
nix:
enable: true
packages: [wxwidgets]
but that wasn't the right way apparently.
So I got rid of the nix part in the .yaml file and tried the command $ stack --nix build which resulted in failure. The log file said
[1 of 1] Compiling Main ( /run/user/1000/stack8847/wxc-0.92.2.0/Setup.hs, /run/user/1000/stack8847/wxc-0.92.2.0/.stack-work/dist/x86_64-linux-nix/Cabal-1.22.5.0/setup/Main.o )
Linking /run/user/1000/stack8847/wxc-0.92.2.0/.stack-work/dist/x86_64-linux-nix/Cabal-1.22.5.0/setup/setup ...
Error: wx-config not found, please install wx-config before installing wxc
However I do have wx-config and wxwidgets installed through nix. The build process can't find it for some reason. What can I do to set up this build environment? Is there a way to direct the build process to look in the directory containing wx-config? I can't figure out why it can't find it. Its in the PATH.
Ok, I figured it out. I was adding the wrong "attribute name". Here is the correct stack.yaml file
# at this point in time nix supports lts-5.0
resolver: lts-5.0
packages:
-'.'
extra-deps:
- wx-0.92.2.0
- wxc-0.92.2.0
- wxcore-0.92.2.0
- wxdirect-0.92.2.0
# wxwidgets-3.0.2 has the attribute name wxGTK30
# you also need zlib, mesa_noglu and x11
nix:
enable: true
packages: [zlib, wxGTK30, mesa_noglu, x11]
That seems to build everything properly, and I was able to build a minimal window from here (minimal.hs)

Shared cabal "build-depends" (Haskell) [duplicate]

Here's a .cabal file:
Name: myprogram
Version: 0.1
-- blah blah blah
Cabal-version: >=1.9.2
Executable myprogram
HS-source-dirs: src
Main-is: Main.hs
Build-depends: attoparsec == 0.10.*,
base == 4.3.*,
-- long long list of packages
Test-Suite test
HS-source-dirs: test, src
Type: exitcode-stdio-1.0
Main-is: Main.hs
Build-depends: attoparsec == 0.10.*,
base == 4.3.*,
-- long long list of packages
QuickCheck == 2.4.*
Is there any way I can replace the long list of build-depends packages for the test suite with "same as for the executable, plus QuickCheck"?
Edit: version information.
cabal-dev 0.9
cabal-install 0.10.2
Cabal library 1.10.2.0
GHC 7.0.4
Haskell Platform 2011.4.0.0
NOTE: superseded by phadej's answer suggesting common stanzas.
Is there any way I can replace the long list of build-depends packages for the test suite with "same as for the executable, plus QuickCheck"?
Not that I know of. However, there is a way to only mention the list of build-depends packages once, by structuring your project into three targets:
a library that contains all your code, and needs the long build-depends list.
an executable that consists of only one file, and depends on base and the library from above.
a test-suite that depends on the library from above, and the testing packages you are using.
Maybe this approach is what indygemma's answer proposes, but the Cabal file proposed there will not quite achieve it, as Norman Ramsey points out in a comment. Here's the main points of what you need in a Cabal file. For a full example that works for me, you can look at this Cabal file.
name: my-program
version: ...
library
hs-source-dirs: src-lib
build-depends: base, containers, ...
exposed-modules: My.Program.Main, ...
executable my-program
hs-source-dirs: src-exec
main-is: my-program.hs
Build-depends: base, my-program
test-suite tests
type: exitcode-stdio-1.0
hs-source-dirs: src-test
main-is: tests.hs
other-modules: ...
build-depends: base, my-program, test-framework, ...
Important points:
There are three separate source directories for the three targets. This is necessary to stop GHC from recompiling library files when building the other targets.
All of the application code is in the library. The executable is just a wrapper, like this:
import My.Program.Main (realMain)
main = realMain
The library exposes all modules that are necessary for testing.
The last point highlights the drawback of this approach: You end up having to expose internal modules. The main benefit of this approach is that you have less duplication in the Cabal file, and maybe more importantly, less duplication in the build process: The library code will be built only once, and then linked into both the executable and the test-suite.
Since version 2.2 Cabal supports common stanzas, to dedup build info fields:
https://cabal.readthedocs.io/en/latest/developing-packages.html#common-stanzas
cabal-version: 2.2
name: myprogram
version: 0.1
-- blah blah blah
common deps
build-depends: base ^>= 4.11,
-- long long list of packages
ghc-options: -Wall
library
import: deps
exposed-modules: Foo
test-suite tests
import: deps
type: exitcode-stdio-1.0
main-is: Tests.hs
build-depends: foo
You could also consider using hpack instead of writing the .cabal file by hand:
In hpack's package.yaml format, you can specify a common dependencies field whose entries are added to every components' build-depends field when generating the .cabal file.
For example, see hpack's own package.yaml and the generated hpack.cabal.
To start using hpack with an existing package, you can use hpack-convert which will generate the package.yaml from an existing .cabal file.
To create a new package that uses hpack, you can use stack's simple-hpack template like so: stack new mypkg simple-hpack.
If you use stack for development, you don't have to call hpack manually to regenerate the .cabal file from an updated package.yaml – stack will do that automatically.
No easy way:
you can use m4 and specify your dependencies once, but then you will need to reprocess your Cabal file through m4 whenever you change it.
you can move the code you are testing out to a library, and then specify the library in your Build-depends for the test. That requires you to install a library even just to run the test.
You can just not put the test in the cabal file at all. Build it with ghc --make, which will pull in dependencies. But then you lose cabal integration.
There is an optional library section for .cabal files, which solves your problem.
name: myprogram
version: 0.1
-- blah blah blah
cabal-version: >=1.9.2
library
build-depends: attoparsec == 0.10.*
, base == 4.3.*
-- long long list of packages
executable myprogram
hs-source-dirs: src
main-is: Main.hs
test-suite test
hs-source-dirs: test, src
type: exitcode-stdio-1.0
main-is: Main.hs
build-depends: QuickCheck == 2.4.*

Resources