ghc --make module hierarchy - haskell

I'm trying to build a standalone program for the first time in Haskell, and am having trouble figuring out how to get ghc --make working with the directory organization of my liking. As the moment I have the following tree:
readme.md
src/
Main.hs
Ciphers/
Affine.hs
Shift.hs
Substitution.hs
Tests/
HCTests.hs
With the following imports:
Main.hs:
module Main where
import Tests.HCTests
import Ciphers.Affine
import Ciphers.Shift
import Ciphers.Substitution
HCTests.hs
module Tests.HCTests (unitTests) where
import Ciphers.Substitution
import Ciphers.Affine
import Ciphers.Shift
Affine.hs
module Affine (
affineEnc,
affineDec,
) where
Shift.hs
module Shift (
shiftEnc,
shiftDec
) where
import Affine
Substitution.hs
module Substitution (
substitutionEnc,
substitutionDec,
) where
Based on this - https://en.wikibooks.org/wiki/Haskell/Standalone_programs - It seems to me the following command should at least properly handle the imports in main, although I'm unclear whether the imports in HCTests will work (it seems to me if I read this properly - Specifying "Up The Tree" Haskell Modules - they should).
The command, which I run in the base directory, is:
ghc -O2 --make -i src -o crypto Main.hs
Fails with error:
target `src' is not a module name or a source file
Edit
I have an additional question. Thanks to Zeta's answer, I've got that sorted, however when I run it, I get the following error:
src/Ciphers/Substitution.hs:5:8:
File name does not match module name:
Saw: `Substitution'
Expected: `Ciphers.Substitution'
So my assumption is that I'd solve this via:
Substitution.hs
module Ciphers.Substitution (
substitutionEnc,
substitutionDec,
) where
My question is how then can I handle that Shift.hs needs to import Affine.hs, while I still want both Ciphers.Shift and Ciphers.Affine?

You may not separate the command line option -i and the search path with whitespace, since -i with following whitespace resets the search path.
Use
ghc -O2 --make -isrc -o crypto Main.hs
or
ghc -O2 --make -i./src -o crypto Main.hs
instead.

Related

Could not load module 'System.Random'

I could not add System.Random module to use it my source haskell file.
import System.Random
This is the error produced by stack ghc:
/Users/admin1/Haskell/PROJECTS/L4/src/Lib4.hs:32:1: error:
Could not load module ‘System.Random’
It is a member of the hidden package ‘random-1.1’.
You can run ‘:set -package random’ to expose it.
(Note: this unloads all the modules in the current scope.)
Use -v (or `:set -v` in ghci) to see a list of the files searched for.
|
32 | import System.Random
| ^^^^^^^^^^^^^^^^^^^^
Failed, five modules loaded.
Thank you very much in advance.
P.S. I am using Stack and GHC versions: Version 2.3.1, Git revision x86_64 hpack-0.33.0, ghc-8.8.3 on Mac OSX
As the error says:
It is a member of the hidden package ‘random-1.1’.
This likely means that you did not list it in the build-depends, and thus it is not exposed to your modules.
You can alter the .cabal file, and add it, for example:
-- project.cabal file
-- …
executable …
-- …
build-depends:
base >= 4.7 && < 5
, random >= 1.1
-- , …

GHC compiles to .o and .hi but no executable

I've been working on a small file which I've been compiling and running as I go. My directory contains Log.hs and LogAnalysis.hs.
LogAnalysis.hs looks like this:
{-# OPTIONS_GHC -Wall #-}
module LogAnalysis where
import Log
parseMessage :: String -> LogMessage
--some code...
main :: IO ()
main = do
putStrLn (show (parseMessage ("Some log message text")))
When I compile the LogAnalysis.hs with GHC I was getting an executable, along with some other binary files:
$ ll
Log.hi
Log.hs
Log.o
LogAnalysis <-- this is the executable which has disappeared
LogAnalysis.hi
LogAnalysis.hs
LogAnalysis.o
I made some small changes and now when I run ghc LogAnalysis.hs I get only the .hi and .o files but no executable. The output is:
[1 of 2] Compiling Log ( Log.hs, Log.o )
[2 of 2] Compiling LogAnalysis ( LogAnalysis.hs, LogAnalysis.o )
I'm not even sure what I changed, but it wasn't anything major. Any idea what could be triggering this? Is there some way to force GHC to produce an executable?
Specs: GHC 8.8.3, macOS 10.15.5
Since I was declaring the file as a module not named Main, GHC by default doesn't create an executable. In order to compile this module into an executable, we can use GHC's main-is flag. (Thanks to Krantz in the comments and Willem Van Onsem's answer here for this.) So compiling with
ghc -main-is LogAnalysis LogAnalysis.hs
gives the output
[2 of 2] Compiling LogAnalysis ( LogAnalysis.hs, LogAnalysis.o )
Linking LogAnalysis ...
So GHC has linked the executable LogAnalysis which is the desired result.
There is an easier way to fix it, delete the second line:
module LogAnalysis where
I believe that when you define it as a module, ghc understands that it is just a module that will be imported in another file so it doesn't create an executable.

Can "-main-is" ghc's option be use via OPTIONS_GHC pragma?

Given MyModule.hs
$ cat MyModule.hs
{-# OPTIONS_GHC -main-is MyModule.main #-}
module MyModule where
main = print "MyModule.Main"
I can make an executable app with -main-is options
$ ghc -o app -main-is MyModule.main MyModule.hs
[1 of 1] Compiling MyModule ( MyModule.hs, MyModule.o ) [flags changed]
Linking app ...
But when I ommit -main-is option and hope ghc will use OPTIONS_GHC pragma, it doesn't work.
$ ghc -o app MyModule.hs
[1 of 1] Compiling MyModule ( MyModule.hs, MyModule.o )
<no location info>: error:
output was redirected with -o, but no output will be generated
because there is no Main module.
The document mention -main-is as dynamic option type which mean it should be possible to use via the pragma (ref)
Question:
Can -main-is be use via OPTIONS_GHC pragma?
Did I use the pragma wrong way?

How do I install and test a Haskell package that I'm developing locally?

I'm developing a Haskell package and would like to test it as if it were an installed package. That is, I'd like to be able to install it among my other packages and then either import or :m +.
I can successfully build my package and (apparently) can successfully install it using
cabal install
which reports
Resolving dependencies...
Configuring Exos-0.0.1.0...
Building Exos-0.0.1.0...
Installed Exos-0.0.1.0
but all attempts to import the package then fail with something like (e.g. in GHCi)
<no location info>:
Could not find module ‘Exos’
It is not a module in the current program, or in any known package.
even though I can see a populated Exos-0.0.1.0 folder in my Haskell lib directory. (Even "uninstalling" fails with ghc-pkg unregister, which reports ghc-pkg: cannot find package Exos-0.0.1.0.)
How do I install and test a package that I'm developing locally, so that it behaves like part of my collection of installed Haskell packages — specifically so that I can import it (and "uninstall" it) like any other?
My package has the structure
Exos.cabal
Exos/
Cryo/
Exos.hs
Exos/
Display.hs
Core.hs
with (relevant) contents in Exos.cabal
name: Exos
version: 0.0.1.0
build-type: Simple
- ...
library
exposed-modules: Cryo.Exos,
Cryo.Exos.Display
other-modules: Cryo.Exos.Core
-- other-extensions:
build-depends: base >=4.8,
containers >= 0.5.5.1,
split >= 0.2.2,
MissingH >= 1.3.0.1
-- hs-source-dirs:
default-language: Haskell2010
in Exos.hs
module Cryo.Exos
(
f,
g,
otherFunc
) where
import Cryo.Exos.Core
-- ...
in Core.hs
module Cryo.Exos.Core where
-- ...
and in Display.hs
module Cryo.Exos.Display
(
showSomething,
showSomethingElse
) where
import Data.Char
-- ...
import Cryo.Exos.Core
import Cryo.Exos
FWIW, inside my IDE, I can write an and successfully run "Application" with the following section in the above .cabal file
executable enigma-hs
main-is: Main.hs
build-depends: base >=4.8,
Exos
hs-source-dirs: tests
default-language: Haskell2010
and the following (relevant) code in Exos/tests/Main.hs
module Main where
import System.IO
import Cryo.Exos
import Cryo.Exos.Display
main :: IO ()
main = do
putStr $ showSomething
putStr $ showSomethingElse
-- ...
The error is a simple one: If you look at the Main.hs example where you have successfully imported the module you have
import Cryos.Expos
and not
import Expos -- wrong
that's because, the module you are importing is Cryos.Expos from the package Expos.

GHCI can't load module if both package-conf and source path contains it

I encounter a strange situation in GHCI, don't know if anyone observed similar case. For some module, when I have it in the search path both by -package-conf, and also by -i, GHCI fails when I try to import the module with 'module is not loaded: FooModule'.
:module loads it fine however
or I can do :load FooModule, :m to clear the import list, and then import FooModule
or I can remove the path from -i and then it imports fine
Tracked this to be the otherwise -> modNotLoadedError m loc case in GHC, where otherwise ~ modulePackageId = this_pkg (the meaning of which I don't know).
This is not entirely systematic, there are some module which are both in package and source path, but can be imported.
GHC only knows about packages that are installed. To see which packages are installed, use the ghc-pkg list command:
$ ghc-pkg list
/usr/lib/ghc-6.12.1/package.conf.d:
Cabal-1.7.4
array-0.2.0.1
base-3.0.3.0
base-4.2.0.0
bin-package-db-0.0.0.0
binary-0.5.0.1
bytestring-0.9.1.4
containers-0.2.0.1
directory-1.0.0.2
(dph-base-0.4.0)
(dph-par-0.4.0)
(dph-prim-interface-0.4.0)
(dph-prim-par-0.4.0)
(dph-prim-seq-0.4.0)
(dph-seq-0.4.0)
extensible-exceptions-0.1.1.0
ffi-1.0
filepath-1.1.0.1
(ghc-6.12.1)
ghc-prim-0.1.0.0
haskeline-0.6.2
haskell98-1.0.1.0
hpc-0.5.0.2
integer-gmp-0.1.0.0
mtl-1.1.0.2
old-locale-1.0.0.1
old-time-1.0.0.1
pretty-1.0.1.0
process-1.0.1.1
random-1.0.0.1
rts-1.0
syb-0.1.0.0
template-haskell-2.4.0.0
terminfo-0.3.1
time-1.1.4
unix-2.3.1.0
utf8-string-0.3.4

Resources