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

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?

Related

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.

Setting import path in an OPTIONS pragma

According to the GHC 8.4.3 flag reference, the -i flag is dynamic, which means it should be settable by an OPTIONS pragma.
So I tried the following:
.
├── Main.hs
└── imp
└── Imported.hs
Contents of imp/Imported.hs:
module Imported (foo) where
foo :: String
foo = "Foo"
Contents of Main.hs:
{-# OPTIONS_GHC -iimp #-}
import Imported (foo)
main :: IO ()
main = putStrLn foo
However, if I try to run Main.hs using runhaskell, it complains that Imported cannot be found:
$ runhaskell -v Main.hs
...
Main.hs:2:1: error:
Could not find module ‘Imported’
Locations searched:
Imported.hs
Imported.lhs
Imported.hsig
Imported.lhsig
How do I specify the -i flag in an OPTIONS pragma?
This appears to be a regression of a documentation bug that was fixed in 2007 and then re-broken in 2014 when a bunch of "static"s were changed to "dynamic"s in the flag reference table. As per the linked bug report, the -i flag is not fully dynamic. It can be :set in GHCi but can't be specified in an OPTIONS_GHC line.

GHC compilation bug?

Some time ago I devised a little system to make compilation and testing of my Haskell programs a bit more comfortable. My project root looks as follows:
./bin/
./bin/myMain
./bin/test
./interfaces/
./obj/
./src/
./src/makefile
./src/MyLib.hs
./src/myMain.hs
./src/testSuite.hs
myMain is the main module, whose imports are like those:
import MyLib
-- irrelevant content follows
testSuite is similar:
import System.Exit
import Test.HUnit
import MyLib
-- irrelevant content follows
I compile those with two simple commands:
ghc testSuite.hs -o ../bin/test -odir ../obj -hidir ../interfaces
ghc myMain.hs -o ../bin/myMain -odir ../obj -hidir ../interfaces
Now, as I run the first, whole test suite compiles and executes perfectly fine, even if there are any object or intereface files present. However when I run the second to compile main executable, it compiles test binary again unless I run remove object and interface files.
The reason is, as far as I found, that main module produces Main.o and Main.hi, no matter what its name is. Therefore while compiling myMain, GHC sees those files present, so does not recompile main module. The strange part is this is not the case when I compile test suite - in such a case Main is recompiled even if there are objects and interfaces present.
$ ghc testSuite.hs -o ../bin/test -odir ../obj -hidir ../interfaces
[1 of 2] Compiling MyLib ( MyLib.hs, ../obj/MyLib.o )
[2 of 2] Compiling Main ( testSuite.hs, ../obj/Main.o )
Linking ../bin/test ...
$ ghc myMain.hs -o ../bin/myMain -odir ../obj -hidir ../interfaces
Linking ../bin/myMain ...
But when I run main compilation first:
$ ghc myMain.hs -o ../bin/myMain -odir ../obj -hidir ../interfaces
[1 of 2] Compiling MyLib ( MyLib.hs, ../obj/MyLib.o )
[2 of 2] Compiling Main ( myMain.hs, ../obj/Main.o )
Linking ../bin/myMain ...
$ ghc testSuite.hs -o ../bin/test -odir ../obj -hidir ../interfaces
[2 of 2] Compiling Main ( testSuite.hs, ../obj/Main.o ) [Test.HUnit changed]
Linking ../bin/test ...
What's even stranger, the problem disappears when I put aside -odir and -hidir GHC parameters and compile everything in the same directory. Why?
[NOTE:]
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.6.3

ghc --make module hierarchy

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.

How can I import a Haskell module in GHCi?

I am trying to teach myself Haskell from the book Learn You A Haskell for Great Good. I got up to the last section of chapter 7 (Modules), where it tells how to create your own module. I did a copy and paste of the Geometry module given in the book at the beginning of the section. The name of the file is Geometry.hs, as the book suggested, and the file is in the bin directory for ghci, which is where I previously was able to successfully do a load using :l for another .hs file.
When I type the following command in GHCi
import Geometry
I get the following error:
Could not find module 'Geometry' It is not a module in the current
program or in any known package
I must be doing something that is obviously wrong, but I can't figure out what it is.
When you use import ModuleName in GHCi, it works (mostly) in the same way import Data.List works: GHC checks your local package database for the module, loads it, and brings its (exported) contents into scope.
However, Geometry isn't a module of a package installed with ghc-pkg. Therefore, GHC doesn't know that a module Geometry exists at all. Neither does it interactive variant GHCi.
But if you :load a program, things change. GHC will take its used modules into account:
-- Foo.hs
module Foo where
foo :: IO ()
foo = putStrLn "Hello from foo!"
-- Main.hs
module Main where
import Foo (foo)
main :: IO ()
main = foo
$ cd /path/to/your/files
$ ghci
GHCi, version 7.10.2: http://www.haskell.org/ghc/ :? for help
Prelude> import Foo
<no location info>:
Could not find module ‘Foo’
It is not a module in the current program, or in any known package.
Prelude> :l Main.hs
[1 of 2] Compiling Foo ( Foo.hs, interpreted )
[2 of 2] Compiling Main ( Main.hs, interpreted )
Ok, modules loaded: Main, Foo.
*Main> :l Main.hs
*Main> foo
Hello from foo!
*Main> import Foo
*Main Foo> -- module now loaded
As you can see, importing Foo first failed. However, after we've actually loaded the program that uses Foo, we were able to use import Foo in GHCi.
So if you want to use import in GHCi, make sure that GHC can find your module, either by including it in a wrapper or installing it. If you just want to load the module itself, use :load.
TLDR: the Learn you a Haskell book fails to mention that you have to :load the Geometry.hs file first. Then :m to go back to Prelude and then import Geometry works.
It is now also possible to add the lib flag when installing packages, i.e. to run cabal install --lib packagename and then to import the corresponding package directly in GHCi. In the present case, for example cabal install --lib hgeometry would facilitate importing modules from this geometry package.

Resources