Meaning of -i and -hidir

Dear devs, I'm confused about the meaning of -hidir and -i. Here's my experiment with both ghc-9.2.0 and ghc-8.10.4.
$ find ./Main.hs ./lib/Lib.hs
$ ghc -dynamic-too -c lib/Lib.hs -odir odir -hidir hidir_Lib
$ ghc -dynamic-too -c Main.hs -odir odir -ihidir_Lib -hidir hidir_Main
Main.hs:3:1: error: Bad interface file: hidir_Main/Lib.hi hidir_Main/Lib.hi: openBinaryFile: does not exist (No such file or directory) | 3 | import Lib | ^^^^^^^^^^
If I only use -hidir, it still fails with another error
$ ghc -dynamic-too -c Main.hs -odir odir -hidir hidir_Lib
Main.hs:7:29: error: Variable not in scope: f | 7 | main = print $(runIO (print f) >> [| True |]) | ^
If I use both -i and -hidir pointing to the same folder, then it works!
$ ghc -dynamic-too -c Main.hs -odir odir -ihidir_Lib -hidir hidir_Lib
Now, is this behavior a bug or a feature? And if it is a bug, what is the expected behavior? Programs copied below. Thank you! Facundo
$ cat lib/Lib.hs module Lib where
f :: Int f = 1
$ cat Main.hs {-# LANGUAGE TemplateHaskell #-}
import Lib import Language.Haskell.TH http://language.haskell.th/
main :: IO () main = print $(runIO (print f) >> [| True |])

This looks like a bug. -hidir documentation says
Redirects all generated interface files into ⟨dir⟩, instead of the default. Please also note that when doing incremental compilation (by ghc --make or ghc -c), this directory is where GHC looks into to find interface files.
And documentation for -i doesn't mention looking for interface files. So by doing % ghc -dynamic-too -c lib/Lib.hs -odir odir -hidir hidir_Lib % ghc -dynamic-too -c Main.hs -odir odir -hidir hidir_Main -ihidir_Lib 1 % ghc odir/Lib.o odir/Main.o -o Demo % ./Demo True everything compiles, TH is run, and demo works. The result files are % find . . ./Demo ./Main.hs ./hidir_Main ./hidir_Main/Main.dyn_hi ./hidir_Main/Main.hi ./odir ./odir/Main.dyn_o ./odir/Main.o ./odir/Lib.dyn_o ./odir/Lib.o ./hidir_Lib ./hidir_Lib/Lib.dyn_hi ./hidir_Lib/Lib.hi ./lib ./lib/Lib.hs --- The confusing error is caused by Lib module in libiserv: https://hackage.haskell.org/package/libiserv which GHC picks! If we rename your Lib module to Library, the error is way better: Could not find module ‘Library’ I also tried using same -hidir when compiling both modules, then GHC still cannot find the Library interface, even the documentation says it should. Please open a GHC issue at https://gitlab.haskell.org/ghc/ghc/-/issues - Oleg On 22.10.2021 19.16, Domínguez, Facundo wrote:
Dear devs,
I'm confused about the meaning of -hidir and -i. Here's my experiment with both ghc-9.2.0 and ghc-8.10.4.
$ find ./Main.hs ./lib/Lib.hs
$ ghc -dynamic-too -c lib/Lib.hs -odir odir -hidir hidir_Lib
$ ghc -dynamic-too -c Main.hs -odir odir -ihidir_Lib -hidir hidir_Main
Main.hs:3:1: error: Bad interface file: hidir_Main/Lib.hi hidir_Main/Lib.hi: openBinaryFile: does not exist (No such file or directory) | 3 | import Lib | ^^^^^^^^^^
If I only use -hidir, it still fails with another error
$ ghc -dynamic-too -c Main.hs -odir odir -hidir hidir_Lib
Main.hs:7:29: error: Variable not in scope: f | 7 | main = print $(runIO (print f) >> [| True |]) | ^
If I use both -i and -hidir pointing to the same folder, then it works!
$ ghc -dynamic-too -c Main.hs -odir odir -ihidir_Lib -hidir hidir_Lib
Now, is this behavior a bug or a feature? And if it is a bug, what is the expected behavior?
Programs copied below.
Thank you! Facundo
$ cat lib/Lib.hs module Lib where
f :: Int f = 1
$ cat Main.hs {-# LANGUAGE TemplateHaskell #-}
import Lib import Language.Haskell.TH http://language.haskell.th/
main :: IO () main = print $(runIO (print f) >> [| True |])
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

I would assume the -i is for include c header search paths but I could be
wrong
On Sat, Oct 23, 2021 at 6:00 AM Oleg Grenrus
This looks like a bug.
-hidir documentation says
Redirects all generated interface files into ⟨dir⟩, instead of the default. Please also note that when doing incremental compilation (by ghc --make or ghc -c), this directory is where GHC looks into to find interface files.
And documentation for -i doesn't mention looking for interface files.
So by doing
% ghc -dynamic-too -c lib/Lib.hs -odir odir -hidir hidir_Lib % ghc -dynamic-too -c Main.hs -odir odir -hidir hidir_Main -ihidir_Lib 1 % ghc odir/Lib.o odir/Main.o -o Demo % ./Demo True
everything compiles, TH is run, and demo works. The result files are
% find . . ./Demo ./Main.hs ./hidir_Main ./hidir_Main/Main.dyn_hi ./hidir_Main/Main.hi ./odir ./odir/Main.dyn_o ./odir/Main.o ./odir/Lib.dyn_o ./odir/Lib.o ./hidir_Lib ./hidir_Lib/Lib.dyn_hi ./hidir_Lib/Lib.hi ./lib ./lib/Lib.hs
---
The confusing error is caused by Lib module in libiserv: https://hackage.haskell.org/package/libiserv which GHC picks!
If we rename your Lib module to Library, the error is way better: Could not find module ‘Library’
I also tried using same -hidir when compiling both modules, then GHC still cannot find the Library interface, even the documentation says it should.
Please open a GHC issue at https://gitlab.haskell.org/ghc/ghc/-/issues
- Oleg On 22.10.2021 19.16, Domínguez, Facundo wrote:
Dear devs,
I'm confused about the meaning of -hidir and -i. Here's my experiment with both ghc-9.2.0 and ghc-8.10.4.
$ find ./Main.hs ./lib/Lib.hs
$ ghc -dynamic-too -c lib/Lib.hs -odir odir -hidir hidir_Lib
$ ghc -dynamic-too -c Main.hs -odir odir -ihidir_Lib -hidir hidir_Main
Main.hs:3:1: error: Bad interface file: hidir_Main/Lib.hi hidir_Main/Lib.hi: openBinaryFile: does not exist (No such file or directory) | 3 | import Lib | ^^^^^^^^^^
If I only use -hidir, it still fails with another error
$ ghc -dynamic-too -c Main.hs -odir odir -hidir hidir_Lib
Main.hs:7:29: error: Variable not in scope: f | 7 | main = print $(runIO (print f) >> [| True |]) | ^
If I use both -i and -hidir pointing to the same folder, then it works!
$ ghc -dynamic-too -c Main.hs -odir odir -ihidir_Lib -hidir hidir_Lib
Now, is this behavior a bug or a feature? And if it is a bug, what is the expected behavior?
Programs copied below.
Thank you! Facundo
$ cat lib/Lib.hs module Lib where
f :: Int f = 1
$ cat Main.hs {-# LANGUAGE TemplateHaskell #-}
import Lib import Language.Haskell.TH http://language.haskell.th/
main :: IO () main = print $(runIO (print f) >> [| True |])
_______________________________________________ ghc-devs mailing listghc-devs@haskell.orghttp://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

I would expect that to be -I and for -i to specify module paths (which
might well mean .hi).
On Sat, Oct 23, 2021 at 2:32 PM Carter Schonwald
I would assume the -i is for include c header search paths but I could be wrong
On Sat, Oct 23, 2021 at 6:00 AM Oleg Grenrus
wrote: This looks like a bug.
-hidir documentation says
Redirects all generated interface files into ⟨dir⟩, instead of the default. Please also note that when doing incremental compilation (by ghc --make or ghc -c), this directory is where GHC looks into to find interface files.
And documentation for -i doesn't mention looking for interface files.
So by doing
% ghc -dynamic-too -c lib/Lib.hs -odir odir -hidir hidir_Lib % ghc -dynamic-too -c Main.hs -odir odir -hidir hidir_Main -ihidir_Lib 1 % ghc odir/Lib.o odir/Main.o -o Demo % ./Demo True
everything compiles, TH is run, and demo works. The result files are
% find . . ./Demo ./Main.hs ./hidir_Main ./hidir_Main/Main.dyn_hi ./hidir_Main/Main.hi ./odir ./odir/Main.dyn_o ./odir/Main.o ./odir/Lib.dyn_o ./odir/Lib.o ./hidir_Lib ./hidir_Lib/Lib.dyn_hi ./hidir_Lib/Lib.hi ./lib ./lib/Lib.hs
---
The confusing error is caused by Lib module in libiserv: https://hackage.haskell.org/package/libiserv which GHC picks!
If we rename your Lib module to Library, the error is way better: Could not find module ‘Library’
I also tried using same -hidir when compiling both modules, then GHC still cannot find the Library interface, even the documentation says it should.
Please open a GHC issue at https://gitlab.haskell.org/ghc/ghc/-/issues
- Oleg On 22.10.2021 19.16, Domínguez, Facundo wrote:
Dear devs,
I'm confused about the meaning of -hidir and -i. Here's my experiment with both ghc-9.2.0 and ghc-8.10.4.
$ find ./Main.hs ./lib/Lib.hs
$ ghc -dynamic-too -c lib/Lib.hs -odir odir -hidir hidir_Lib
$ ghc -dynamic-too -c Main.hs -odir odir -ihidir_Lib -hidir hidir_Main
Main.hs:3:1: error: Bad interface file: hidir_Main/Lib.hi hidir_Main/Lib.hi: openBinaryFile: does not exist (No such file or directory) | 3 | import Lib | ^^^^^^^^^^
If I only use -hidir, it still fails with another error
$ ghc -dynamic-too -c Main.hs -odir odir -hidir hidir_Lib
Main.hs:7:29: error: Variable not in scope: f | 7 | main = print $(runIO (print f) >> [| True |]) | ^
If I use both -i and -hidir pointing to the same folder, then it works!
$ ghc -dynamic-too -c Main.hs -odir odir -ihidir_Lib -hidir hidir_Lib
Now, is this behavior a bug or a feature? And if it is a bug, what is the expected behavior?
Programs copied below.
Thank you! Facundo
$ cat lib/Lib.hs module Lib where
f :: Int f = 1
$ cat Main.hs {-# LANGUAGE TemplateHaskell #-}
import Lib import Language.Haskell.TH http://language.haskell.th/
main :: IO () main = print $(runIO (print f) >> [| True |])
_______________________________________________ ghc-devs mailing listghc-devs@haskell.orghttp://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
-- brandon s allbery kf8nh allbery.b@gmail.com

Could be! I’m far from a computer much of this week
On Sat, Oct 23, 2021 at 2:36 PM Brandon Allbery
I would expect that to be -I and for -i to specify module paths (which might well mean .hi).
On Sat, Oct 23, 2021 at 2:32 PM Carter Schonwald < carter.schonwald@gmail.com> wrote:
I would assume the -i is for include c header search paths but I could be wrong
On Sat, Oct 23, 2021 at 6:00 AM Oleg Grenrus
wrote: This looks like a bug.
-hidir documentation says
Redirects all generated interface files into ⟨dir⟩, instead of the default. Please also note that when doing incremental compilation (by ghc --make or ghc -c), this directory is where GHC looks into to find interface files.
And documentation for -i doesn't mention looking for interface files.
So by doing
% ghc -dynamic-too -c lib/Lib.hs -odir odir -hidir hidir_Lib % ghc -dynamic-too -c Main.hs -odir odir -hidir hidir_Main -ihidir_Lib 1 % ghc odir/Lib.o odir/Main.o -o Demo % ./Demo True
everything compiles, TH is run, and demo works. The result files are
% find . . ./Demo ./Main.hs ./hidir_Main ./hidir_Main/Main.dyn_hi ./hidir_Main/Main.hi ./odir ./odir/Main.dyn_o ./odir/Main.o ./odir/Lib.dyn_o ./odir/Lib.o ./hidir_Lib ./hidir_Lib/Lib.dyn_hi ./hidir_Lib/Lib.hi ./lib ./lib/Lib.hs
---
The confusing error is caused by Lib module in libiserv: https://hackage.haskell.org/package/libiserv which GHC picks!
If we rename your Lib module to Library, the error is way better: Could not find module ‘Library’
I also tried using same -hidir when compiling both modules, then GHC still cannot find the Library interface, even the documentation says it should.
Please open a GHC issue at https://gitlab.haskell.org/ghc/ghc/-/issues
- Oleg On 22.10.2021 19.16, Domínguez, Facundo wrote:
Dear devs,
I'm confused about the meaning of -hidir and -i. Here's my experiment with both ghc-9.2.0 and ghc-8.10.4.
$ find ./Main.hs ./lib/Lib.hs
$ ghc -dynamic-too -c lib/Lib.hs -odir odir -hidir hidir_Lib
$ ghc -dynamic-too -c Main.hs -odir odir -ihidir_Lib -hidir hidir_Main
Main.hs:3:1: error: Bad interface file: hidir_Main/Lib.hi hidir_Main/Lib.hi: openBinaryFile: does not exist (No such file or directory) | 3 | import Lib | ^^^^^^^^^^
If I only use -hidir, it still fails with another error
$ ghc -dynamic-too -c Main.hs -odir odir -hidir hidir_Lib
Main.hs:7:29: error: Variable not in scope: f | 7 | main = print $(runIO (print f) >> [| True |]) | ^
If I use both -i and -hidir pointing to the same folder, then it works!
$ ghc -dynamic-too -c Main.hs -odir odir -ihidir_Lib -hidir hidir_Lib
Now, is this behavior a bug or a feature? And if it is a bug, what is the expected behavior?
Programs copied below.
Thank you! Facundo
$ cat lib/Lib.hs module Lib where
f :: Int f = 1
$ cat Main.hs {-# LANGUAGE TemplateHaskell #-}
import Lib import Language.Haskell.TH http://language.haskell.th/
main :: IO () main = print $(runIO (print f) >> [| True |])
_______________________________________________ ghc-devs mailing listghc-devs@haskell.orghttp://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
-- brandon s allbery kf8nh allbery.b@gmail.com

The behavior of `-hidir` and `-i` changed in response to this issue:
https://gitlab.haskell.org/ghc/ghc/-/issues/16500
We just ran into this and I think the change is unfortunate. I don't think
`-hidir` (a flag about output) should override the input search flag. I
would like it to at least merge the two so it searches both the `-hidir`
and the `-i`s rather than overriding. Reverting the change would be fine
too (I think) because you can always specify the same path as `-hidir` and
`-i`. As it is now, you can control *both* the input and the output.
On Sat, Oct 23, 2021 at 4:26 PM Carter Schonwald
Could be! I’m far from a computer much of this week
On Sat, Oct 23, 2021 at 2:36 PM Brandon Allbery
wrote: I would expect that to be -I and for -i to specify module paths (which might well mean .hi).
On Sat, Oct 23, 2021 at 2:32 PM Carter Schonwald < carter.schonwald@gmail.com> wrote:
I would assume the -i is for include c header search paths but I could be wrong
On Sat, Oct 23, 2021 at 6:00 AM Oleg Grenrus
wrote: This looks like a bug.
-hidir documentation says
Redirects all generated interface files into ⟨dir⟩, instead of the default. Please also note that when doing incremental compilation (by ghc --make or ghc -c), this directory is where GHC looks into to find interface files.
And documentation for -i doesn't mention looking for interface files.
So by doing
% ghc -dynamic-too -c lib/Lib.hs -odir odir -hidir hidir_Lib % ghc -dynamic-too -c Main.hs -odir odir -hidir hidir_Main -ihidir_Lib 1 % ghc odir/Lib.o odir/Main.o -o Demo % ./Demo True
everything compiles, TH is run, and demo works. The result files are
% find . . ./Demo ./Main.hs ./hidir_Main ./hidir_Main/Main.dyn_hi ./hidir_Main/Main.hi ./odir ./odir/Main.dyn_o ./odir/Main.o ./odir/Lib.dyn_o ./odir/Lib.o ./hidir_Lib ./hidir_Lib/Lib.dyn_hi ./hidir_Lib/Lib.hi ./lib ./lib/Lib.hs
---
The confusing error is caused by Lib module in libiserv: https://hackage.haskell.org/package/libiserv which GHC picks!
If we rename your Lib module to Library, the error is way better: Could not find module ‘Library’
I also tried using same -hidir when compiling both modules, then GHC still cannot find the Library interface, even the documentation says it should.
Please open a GHC issue at https://gitlab.haskell.org/ghc/ghc/-/issues
- Oleg On 22.10.2021 19.16, Domínguez, Facundo wrote:
Dear devs,
I'm confused about the meaning of -hidir and -i. Here's my experiment with both ghc-9.2.0 and ghc-8.10.4.
$ find ./Main.hs ./lib/Lib.hs
$ ghc -dynamic-too -c lib/Lib.hs -odir odir -hidir hidir_Lib
$ ghc -dynamic-too -c Main.hs -odir odir -ihidir_Lib -hidir hidir_Main
Main.hs:3:1: error: Bad interface file: hidir_Main/Lib.hi hidir_Main/Lib.hi: openBinaryFile: does not exist (No such file or directory) | 3 | import Lib | ^^^^^^^^^^
If I only use -hidir, it still fails with another error
$ ghc -dynamic-too -c Main.hs -odir odir -hidir hidir_Lib
Main.hs:7:29: error: Variable not in scope: f | 7 | main = print $(runIO (print f) >> [| True |]) | ^
If I use both -i and -hidir pointing to the same folder, then it works!
$ ghc -dynamic-too -c Main.hs -odir odir -ihidir_Lib -hidir hidir_Lib
Now, is this behavior a bug or a feature? And if it is a bug, what is the expected behavior?
Programs copied below.
Thank you! Facundo
$ cat lib/Lib.hs module Lib where
f :: Int f = 1
$ cat Main.hs {-# LANGUAGE TemplateHaskell #-}
import Lib import Language.Haskell.TH http://language.haskell.th/
main :: IO () main = print $(runIO (print f) >> [| True |])
_______________________________________________ ghc-devs mailing listghc-devs@haskell.orghttp://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
-- brandon s allbery kf8nh allbery.b@gmail.com
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

The issue uses consistency with -odir and -hieDir as a rationalization. I think it's not quite right because inputs can have a search path while outputs don't, but if it is true that -odir simultaneously sets the output and input dir for `*.o`, that seems confusing too. Shouldn't -odir set *only* output, and all inputs should either be lumped under the `-i` search path, or even split up into separate flags as outputs are? If you are building in --make mode then you will naturally want to read .o files from the last place you wrote them, but in that case you can explicitly say so. I'm not actually advocating for this since I don't have a use for it at the moment, and I don't want to potentially break every single user of ghc --make, but it seemed to me that the argument for consistency could run the other direction. I think this issue is coming up due to a mismatch between the traditional Make style builds which assume a single mutable input and output directory, and the newer functional / hermetic style builds which require immutable inputs and a mutable output. It's a familiar concept, just transposed to the file system!

Thanks everyone for your thoughts. I have opened an issue here:
https://gitlab.haskell.org/ghc/ghc/-/issues/20569
Best,
Facundo
On Sat, Oct 23, 2021 at 11:18 PM Evan Laforge
The issue uses consistency with -odir and -hieDir as a rationalization. I think it's not quite right because inputs can have a search path while outputs don't, but if it is true that -odir simultaneously sets the output and input dir for `*.o`, that seems confusing too. Shouldn't -odir set *only* output, and all inputs should either be lumped under the `-i` search path, or even split up into separate flags as outputs are? If you are building in --make mode then you will naturally want to read .o files from the last place you wrote them, but in that case you can explicitly say so. I'm not actually advocating for this since I don't have a use for it at the moment, and I don't want to potentially break every single user of ghc --make, but it seemed to me that the argument for consistency could run the other direction.
I think this issue is coming up due to a mismatch between the traditional Make style builds which assume a single mutable input and output directory, and the newer functional / hermetic style builds which require immutable inputs and a mutable output. It's a familiar concept, just transposed to the file system! _______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
participants (6)
-
Brandon Allbery
-
Carter Schonwald
-
Domínguez, Facundo
-
Evan Laforge
-
Oleg Grenrus
-
Ryan Yates