ghc-mod under stack complaining about hidden main package - haskell

I have following problem with ghc-mod which prevents me from using ide for some files in a yesod app project.
I install template app as follows:
/tmp$ stack new demo yesod-sqlite && cd demo
/tmp/demo$ stack setup && stack build && stack install ghc-mod
Which yields following stack.yaml (commented lines removed):
resolver: lts-5.6
packages:
- '.'
extra-deps: []
flags: {}
extra-package-dbs: []
And this is a demo.cabal: http://pastebin.com/i4n1TR6W.
Then, running stack exec -- ghc-mod check app/main.hs does not produce errors, but stack exec -- ghc-mod check app/devel.hs has this to say:
app/devel.hs:2:1:Failed to load interface for ‘Application’It is a member of the hidden package ‘demo-0.0.0’.Perhaps you need to add ‘demo’ to the build-depends in your .cabal file.
So the ghc-mod somehow thinks this package is itself hidden? But any other place where project's files are imported by another checks fine, and the application builds and works successfully. The only specifics about this file is using PackageImports language extension:
{-# LANGUAGE PackageImports #-}
import "demo" Application (develMain)
I tried googling the error message but it seems to only come up with regard to external packages and not the one being debugged.

These two files devel.hs and DevelMain.hs are quite special: they are marked as a module of demo in .cabal but they are importing demo as a compiled package, i.e. recursive dependency.
They are not exposed from library demo nor imported anywhere else so won't get compiled when you run stack build, but when you run ghc-mod check on them, they are interpreted in the context of the current project, therefore the recursive dependency will be an issue.
The only purpose of these two otherwise meaningless files is to debug your yesod website in ghci, as the comment in DevelMain.hs stated:
-- | Running your app inside GHCi.
--
-- To start up GHCi for usage with Yesod, first make sure you are in dev mode:
--
-- > cabal configure -fdev
--
-- Note that #yesod devel# automatically sets the dev flag.
-- Now launch the repl:
--
-- > cabal repl --ghc-options="-O0 -fobject-code"
--
-- To start your app, run:
--
-- > :l DevelMain
-- > DevelMain.update
--
-- You can also call #DevelMain.shutdown# to stop the app
--
-- You will need to add the foreign-store package to your .cabal file.
-- It is very light-weight.
--
-- If you don't use cabal repl, you will need
-- to run the following in GHCi or to add it to
-- your .ghci file.
--
-- :set -DDEVELOPMENT
--
-- There is more information about this approach,
-- on the wiki: https://github.com/yesodweb/yesod/wiki/ghci
cabal repl and stack ghci will compile the project beforehand so these two files won't cause any error there.

Related

How to configure .ghci file to import all loaded modules

let say I have a project which is just a bunch of Haskell modules with exercises. I'd like to provide a .ghci which automatically imports all modules into ghci scope. The problem is, I can not run import nor :m +Module.Name within .ghci file.
Clearly cabal repl is reading the .ghci file because options like the prompt are readed. Also it loads modules correctly, but it doesn't bring them into scope (only one gets imported). If I try to add import OtherModule to .ghci file, then I get the error
module is member of hidden package fail-ghci
Perhaps you need to add ‘fail-ghci’ to the build-depends in your .cabal file.
But I can't add fail-ghci to the cabal file, because the library can't depend on itself!!
To reproduce. Create a simple cabal project. For example:
src
|- Module1.hs # include dummy function func1 :: Int
|- Module2.hs # include dummy function func2 :: Int
fail-ghci.cabal
.ghci
The content of fail-ghci.cabal is
name: fail-ghci
version: 0.1.0.0
license: BSD3
license-file: LICENSE
build-type: Simple
library
exposed-modules:
Module1
, Module2
hs-source-dirs:
src
build-depends:
base >=4.7 && <5
default-language: Haskell2010
If you set .ghci as
:set prompt "> " -- Set this option to ensure .ghci is readed by cabal repl
It will work fine and will bring Module1.hs into scope, so func1 is available. But Module2.hs wont be in the scope, If I want to use it I'd need to execute import Module2 or equivalent.
Now, I'd like this to happen automatically when running cabal repl because my project has many modules. The obvious (to me) choice is to modify .ghci as
:set prompt "> " -- Set this option to ensure .ghci is readed by cabal repl
import Module2 -- Equivalent :m +Module2
But the ghci is unable to import the module, despite of that command woring correctly within ghci. What's the correct configuration to do this?
One workaround I like is to add a new module to your project, perhaps called DefaultRepl or similar, that imports everything you want. If you put this at the top of your exposed-modules list, then it will be loaded up when you run cabal repl and bring everything that it imports into scope.
I suppose the problem is simply that cabal executes the commands in your .ghci file before it loads the current project.
Indeed when I cabal repl in a similar project, the startup output is:
Build profile: -w ghc-9.0.2 -O1
In order, the following will be built (use -v for more details):
- fail-ghci-0.1.0.0 (first run)
Preprocessing library for fail-ghci-0.1.0.0..
GHCi, version 9.0.2: https://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /tmp/scratch/.ghci
[1 of 2] Compiling Module1 ( src/Module1.hs, interpreted )
[2 of 2] Compiling Module2 ( src/Module2.hs, interpreted )
Ok, two modules loaded.
ghci>
My guess would be that this is probably because cabal repl starts a ghci session (which loads the .ghci file during startup) and then uses its API to load the project environment. (I was able to confirm that a .ghci file can import modules from packages that are fully installed, rather than from a current project being cabal repld)
I don't know of any way to automatically execute commands after the project has been loaded. But you can have your .ghci file define a shortcut command that will import all the modules you want. That way you have at least have a single quick command to execute once you're in the ghci shell, instead of manually importing everything. Something like this:
:def loadall (const . pure) ":m + *Module1 *Module2"
-- or
:def loadall (const . pure) "import Module1 Module2"
-- or etc
Then you can just enter :loadall at the ghci prompt to get your modules imported.

Compiling a haskell script with external dependencies without cabal

I'm relatively new to Haskell and I realize I might be swimming against the stream here, but nonetheless, I'll ask:
Say I have a short Haskell script:
import Data.List.Split (splitOn)
main :: IO ()
main = do
let orders = splitOn "x" "axbxc"
putStrLn $ head orders
If I used only standard functions I could compile this with ghc <script.hs>. Because I depend on the split package to provide the splitOn function, the compilation fails.
Now, I have no difficulties setting up a cabal project with a project.cabal and a Setup.hs file in order to get this to actually compile. However, this feels like a lot of extra boilerplate for a standalone script.
So, is there a way to compile a single .hs file against some external package? Something similar to what in Python would be done by pip install something, "installing the package into the interpreter", i.e. is there a way to install extra packages "into ghc", so that I for instance only need to provide some extra linking flag to ghc?
The Cabal equivalent of the Stack script in bradrn's answer would be:
#!/usr/bin/env cabal
{- cabal:
build-depends: base
, split
-}
import Data.List.Split (splitOn)
main :: IO ()
main = do
let orders = splitOn "x" "axbxc"
putStrLn $ head orders
The script can be run with cabal run, or directly by giving it execute permission. If need be, version bounds can be added as usual to the build-depends on the top of the script.
(Note this isn't literally a solution without Cabal, as doing this with GHC alone, even if it is possible, wouldn't be worth the trouble. In any case, it certainly avoid the boilerplate of needing multiple files.)
If you use Stack, the simplest way to do this is to write a ‘Stack script’, which is a Haskell file with a description of the required packages in the first line (really an invocation of stack specifying the appropriate command line arguments). An example (slightly modified from the docs):
$ cat turtle-example.hs
-- stack --resolver lts-6.25 script --package turtle
{-# LANGUAGE OverloadedStrings #-}
import Turtle
main = echo "Hello World!"
$ stack ./turtle-example.hs
Completed 5 action(s).
Hello World!
$ stack ./turtle-example.hs
Hello World!
This script uses the turtle package; when run, Stack downloads and builds this dependency, after which it is available in the script. (Note that the second time it is run, turtle has already been built so does not need to be rebuilt again.)
As it happens, the --package command in Stack is not limited to scripts. It can be used with other Stack commands as well! For instance, to compile your program, you should be able to run stack ghc --resolver lts-16.27 --package split -- -ghc-options your-program-name.hs. And stack ghci --package split will give you a GHCi prompt where you can import Data.List.Split.
(Note: This answer focuses on Stack rather than Cabal, simply because I don’t know Cabal very well. However, I believe all this can be done using Cabal as well. For instance, I do know that Cabal has something very similar to the Stack scripts I mentioned above, though I can’t remember the syntax just at the moment.)
EDIT: See #duplode’s answer for how to do this with Cabal.
You can install into the default environment for the current user by doing cabal install --lib split. The package should then be available to ghc and ghci without needing any special options.
More information is at the bottom of this section in the Cabal manual. The v2 commands that it uses are the default now so if you have a fairly new cabal you can just use install rather than v2-install.
I think this is the quintessential entry point to the package management battle in Haskell. It's not there's not enough advice, but there's so much, each with its own caveats and assumptions. Climbing that mountain for the sake of splitOn feels to the newbie like they're Doing It Wrong.
After spending far too much time trying each permutation, I've collated the fine answers here, and many, many others from elsewhere, put them to the test, and summarised the results. The full write up is here.
The pertinent summary of solutions is:
Install globally
You can still do global installs with cabal install --lib the-package.
Use Stack as a run command
You can use stack directly, eg: stack exec --package containers --package optparse-generic [...and so on] -- runghc hello.hs
Create a Stack project
The real deal. Run stack new my-project hraftery/minimal, put your code in Main.hs and your dependencies in my-project.cabal (and maybe stack.yaml - check the article), and then run stack build to automagically pull and build all dependencies.
Use a Stack script
Make your Haskell file itself an executable Stack script. Add -- stack --resolver lts-6.25 script --package the-package to the top of your .hs file and set its executable bit.
For my Edit/Test/Run workflow (eg. using VS Code, GHCi and GHC respectively), I found it pretty clear what works in practice. In summary:
Amongst a chorus of discouragement, Global Installs suit what I know of your use case just fine.
Where Global Installs don't make sense (eg. for managing dependency versions or being portable) a Stack project starting from my minimal template is a smooth transition to a more sophisticated and popular method.

Haskell - could not find module 'Test.QuickCheck'

I'm getting an error that says the module doesn't exist when I try to runhaskell. It's odd because I try to install it first and says its up to date. Any idea how to fix this?
You could try creating the package environment in the local directory that holds your project, like this:
c:\Users\...\ex1haskell> cabal install --lib --package-env . QuickCheck
This should create a file of the form .ghc.environment.xxx in ex1haskell, which hopefully should be picked up by runhaskell/ghci/ghc invocations.
In ghci sessions, a sign that the environment is being picked up is the following message while starting:
Loaded package environment from ...
When the --package-env location is not given explicitly, a default location is used. According to the docs:
By default, it is writing to the global environment in
~/.ghc/$ARCH-$OS-$GHCVER/environments/default. v2-install provides the
--package-env flag to control which of these environments is modified.
But it seems that runhaskell is having problems to find the environment file in that default location.
Note. When creating a package environment, it's possible to specify multiple packages simultaneously, like this:
cabal install --lib --package-env . QuickCheck random aeson transformers
Also, package environments are just text files, so local environments can be deleted and recreated at will. The actual package binaries reside elsewhere and can potentially be reused by cabal.
A Common Environment
It is hard to debug if/when the actual tooling differs so let's first get a unified setup. I'll use docker to get GHC 8 and Cabal 3.x:
docker run --rm -it haskell bash
Understand that this isn't arbitrary or even preemptive. What you have shown - cabal install --lib ... and runhaskell ... does work for sane tool installations. You might have a bad installation or an old version of a tool that has different behavior.
Running a single file with runhaskell
Now we need a project:
root#8a934c302dba:/# mkdir Ex1
root#8a934c302dba:/# cd Ex1
root#8a934c302dba:/Ex1# cat <<EOF >Main.hs
> import Test.QuickCheck
>
> main :: IO ()
> main = print =<< (generate arbitrary :: IO Int)
> EOF
And test failure:
root#8a934c302dba:/Ex1# runhaskell Main.hs
Main.hs:1:1: error:
Could not find module `Test.QuickCheck'
Use -v (or `:set -v` in ghci) to see a list of the files searched for.
|
1 | import Test.QuickCheck
And install the library:
root#8a934c302dba:/Ex1# cabal update && cabal install --lib QuickCheck
And successful run:
root#8a934c302dba:/Ex1# runhaskell Main.hs
15
So my comment above was wrong - we don't need to explicitly list the package as it is already exposed after installation.

Stack: Compile stand-alone source file

Once you've installed Stack, you can use it to install GHC for you. Great!
...now how do I compile a file with it?
To be clear: What you're supposed to do is write a package specification and have Stack build that. But surely there must be a way to trivially compile a tiny helper file inside that project? It seems silly to have to construct an entire project just so I can build a tiny helper program and have it easily runnable from the shell.
I know I can run any Haskell file using Stack. But I cannot for the life of me figure out how to compile the thing...
You can use stack ghc -- <file names> to compile and link a set of files (it's briefly mentioned in Stack's user guide):
You'll sometimes want to just compile (or run) a single Haskell source file, instead of creating an entire Cabal package for it. You can use stack exec ghc or stack exec runghc for that. As simple helpers, we also provide the stack ghc and stack runghc commands, for these common cases.
The -- is to ensure the arguments we pass are sent to ghc, rather than being parsed as arguments to stack exec. It's the same thing as when trying to pass arguments to an executable you've made using the normal stack toolchain: stack exec myExe -foo passes -foo to exec, not myExe, stack exec myExe -- -foo behaves as desired.
For example:
Bar.hs
module Bar where
bar :: Int
bar = 5
Foo.hs
import Bar
main :: IO ()
main = print bar
Compilation (don't even need to specify Bar.hs in the build files, it's sourced automatically):
> stack ghc -- Foo.hs
[1 of 2] Compiling Bar ( Bar.hs, Bar.o )
[2 of 2] Compiling Main ( Foo.hs, Foo.o )
Linking Foo ...
> ./Foo
5
There's no problem with dependencies either - it looks like all the packages installed locally are available to the build (you can use containers or QuickCheck without any additional build params).

Different behavior of cabal repl for library vs. executable

Using cabal repl seems to do nothing at all when used on library projects, but works fine for executable projects. Is this expected behavior that I just don't understand?
If I have a file containing simply
go = putStrLn "test"
and use cabal init with all the defaults (but choose "library" as the type), then running cabal repl just produces the some text about configuring and preprocessing the library and never enters a REPL environment. The exact same steps, but with "executable" selected as the type, puts me right into GHCi as expected.
The code works fine when loaded directly into GHCi.
For cabal repl to load your modules, you have to first name them in code and then specify them in your project's .cabal file as exposed:
-- MyModule.hs
module MyModule where
go = putStrLn "test"
-- MyProject.cabal
name: MyProject
-- other info ...
library
exposed-modules: MyModule
-- other options ...
Then when you run cabal repl, it'll have access to everything in your sandbox (if present) and the exposed modules. It might also work if you specify them as other-modules instead of exposed-modules, but I haven't tried that one out.

Resources