GHC compiles to .o and .hi but no executable - haskell

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.

Related

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?

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.

Haskell GHCI not loading compiled object file

I would like GHCI to load the compiled object code for a module which when compiled is significantly faster than the none compiled version. This was working well when all of the files were in the same directory (no module hierarchies). However, they do not work when the files are in module hierarchies.
Working version MyFile.hs:
import Basic
import Histogram
where Basic.o and Histogram.o are in the same directory as MyFile.hs
Not Working version MyFile.hs:
import Util.Basic
import Util.Histogram
where Basic.o and Histogram.o are in a subdirectory Util. With this version I get the following when loading MyFile.hs:
[1 of 2] Compiling Util.Basic ( Util/Basic.hs, interpreted )
[2 of 2] Compiling Util.Histogram ( Util/Histogram.hs, interpreted )
Ok, modules loaded: Util.Basic, Util.Histogram.
I would like to be able to organize my code in modules but still receive the benefits from using the compiled o files.
Also, it should be noted that the source files have not been changed since the o files were compiled.
Edits:
Here are the contents of each file:
MyFile.hs
import Util.Basic
import Util.Histogram
Util/Basic.hs
module Util.Basic () where
Util/Histogram.hs
module Util.Histogram () where
Files / Compilation:
$:~/programming/haskell/example-error$ ls
MyFile.hs MyFile.hs~ Util
$:~/programming/haskell/example-error$ cd Util
$:~/programming/haskell/example-error/Util$ ls
Basic.hs Basic.hs~ Histogram.hs Histogram.hs~
$:~/programming/haskell/example-error/Util$ ghc *.hs
[1 of 2] Compiling Util.Histogram ( Histogram.hs, Histogram.o )
[2 of 2] Compiling Util.Basic ( Basic.hs, Basic.o )
$:~/programming/haskell/example-error/Util$ ls
Basic.hi Basic.hs~ Histogram.hi Histogram.hs~
Basic.hs Basic.o Histogram.hs Histogram.o
$:~/programming/haskell/example-error/Util$ cd ../
$:~/programming/haskell/example-error$ ghci -ignore-dot-ghci MyFile.hs
GHCi, version 7.4.1: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[1 of 3] Compiling Util.Histogram ( Util/Histogram.hs, interpreted )
[2 of 3] Compiling Util.Basic ( Util/Basic.hs, interpreted )
[3 of 3] Compiling Main ( MyFile.hs, interpreted )
Ok, modules loaded: Util.Basic, Util.Histogram, Main.
*Main>
The Solution that worked as suggested by Daniel:
The fix is to compile the importing file, and the files in the
subdirectory only as a consequence of that, not directly.
The issue is the same as discussed below, the flags changed:
~/.../Util> ghc Other.hs
[1 of 1] Compiling Util.Other ( Other.hs, Other.o )
~/.../Util> cd ..
~/.../src> ghc MyFile.hs
[1 of 2] Compiling Util.Other ( Util/Other.hs, Util/Other.o ) [flags changed]
[2 of 2] Compiling MyFile ( MyFile.hs, MyFile.o )
I haven't found out which flags in particular, or why the flags passed during separate compilation are different than the ones that are passed when compiling as a module chased from the importing module, but they do change, and hence a recompilation is necessary (Specifically, the flag-hash value in the .hi file changes).
The fix is therefore to not compile the modules separately, but to compile them as dependencies of the top-level importer.
Original almost correct guesswork:
I can only partly reproduce that. After compiling and then touching MyFile.hs,
$ ghci-7.4.2 MyFile.hs
-- snip
[1 of 2] Compiling Util.Other ( Util/Other.hs, interpreted )
[2 of 2] Compiling MyFile ( MyFile.hs, interpreted )
Ok, modules loaded: MyFile, Util.Other.
it looks the same as for you, but with 7.6.1, we get a hint (compiling and touching):
$ ghci MyFile.hs
-- snip
[1 of 2] Compiling Util.Other ( Util/Other.hs, interpreted ) [flags changed]
[2 of 2] Compiling MyFile ( MyFile.hs, interpreted )
Ok, modules loaded: MyFile, Util.Other.
The flags changed. I have :set -XNoMonomorphismRestriction in my .ghci file, and the change of flags causes the recompilation.
$ ghci -ignore-dot-ghci MyFile.hs
GHCi, version 7.6.1: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[2 of 2] Compiling MyFile ( MyFile.hs, interpreted )
Ok, modules loaded: MyFile, Util.Other.
Ignoring the offending .ghci with the flag that wasn't given for the compilation, the unchanged Util.Other is not interpreted, the compiled code is used. (With GHC < 7.4, ignoring the .ghci file isn't even necessary.)
If you have a .ghci file in which you set language options (NoMonomorphismRestriction, TypeFamilies, ...) and ghc >= 7.4, you need to ignore the .ghci file when loading the modules.
If that is not the case, the recompilation is not the expected behaviour. Then more information would be necessary to diagnose the problem and find a fix.
A semi-work-around would then be the -fobject-code flag for ghci.

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