
Hello all, I am writing a tool that uses the ghc api. It works great when I invoke it on user library code but not for test (and executable) components. Consider a very simple user project with this layout lib/Foo.hs lib/Bar.hs test/FooTest.hs test/TestUtils.hs Let's say that Foo imports from Bar and FooTest imports from TestUtils. To start my tool, which for all intents and purposes is just loading a file into ghc, I obtain the ghc flags from cabal's v2-repl (this is the hie-bios hack). I've been sure to make sure that I grab the flags associated to the relevant component. I feel that I need to justify why I'm doing it this way instead of cabal envfiles: they do not include language extensions and other things of that nature, and don't separate library/test/etc. Let's say the user has compiled the project, with tests enabled. The flags for the library might look something like ... -this-unit-id example-1.0-inplace -hide-all-packages -Wmissing-home-modules -no-user-package-db -package-db -/home/me/.cabal/store/ghc-8.6.5/package.db -package-db -/home/me/example/dist-newstyle/packagedb/ghc-8.6.5 --package-db /home/me/example/dist-newstyle/build/x86_64-linux/ghc-8.6.5/example-1.0/noopt/package.conf.inplace -package-id transformers-0.5.6.2 ... which all makes sense. If I use these flags then loading Foo.hs will fail because it cannot find Bar. These modules are needed for compilation but not listed in your .cabal file's other-modules: Bar Of course I could suppress this by ignoring warnings, but I want to see those modules.... so I have a workaround! I hacked it by changing the -this-unit-id to a -package-id and it all works great because the compiler already has the interface files for Bar in the packagedb. My tool doesn't write any object files, so I think this is safe. However, when I come to running my tool on test directories, there is no -this-unit-id from v2-repl. I know what the package-id is (from Cabal's plan.json) but it doesn't exist in my packagedb, so I can't re-use my hack. These modules are needed for compilation but not listed in your .cabal file's other-modules: TestUtils And I'm back where I started. So my question is: which flags do I need to provide to the ghc api so that a module can see the interfaces of other modules in the same component? I'm guessing my -this-unit-id hack is horrible and I shouldn't be doing that. What is the correct thing to do? -- Best regards, Sam

Rahul Muttineni has given me some guidance. I wasn't loading all the
module names that are provided as arguments to ghc. Now I am.
I'm now able to load my file and do the analysis I want. But it is
*much* slower than when I treat the home modules as a package.
I presume it is slower because lots of modules are now being loaded
instead of just the one I care about. I'm even seeing errors such as
"Variable not in scope" in some of the modules that I don't care about
(loading seems to do a lot of work) and presumably compile errors in
downstream modules will impact me as well.
1. Is there a way to tell ghc to prefer interface files instead of
source files, if it finds them, for a TargetModule?
2. Is it possible to prune the list of targets such that it is only the
file I am interested in and its dependencies? Ideally I'd like to
load just the file I care about and have everything else
automatically load.
PS: another hack that we've been discussing is to create and register an
ad-hoc packagedb for test (and executable) components. It doesn't seem
to be trivial to do this, unless cabal-install has a hidden command that
can create conf files for an arbitrary component. The advantage here is
that I can load only the file I care about, and ghc takes care of
automatically loading all the dependencies (even if they are in the same
package). Of course, those dependencies must have been compiled but
that's the UX I'm going for.
Sam Halliday
Hello all,
I am writing a tool that uses the ghc api. It works great when I invoke it on user library code but not for test (and executable) components.
Consider a very simple user project with this layout
lib/Foo.hs lib/Bar.hs test/FooTest.hs test/TestUtils.hs
Let's say that Foo imports from Bar and FooTest imports from TestUtils.
To start my tool, which for all intents and purposes is just loading a file into ghc, I obtain the ghc flags from cabal's v2-repl (this is the hie-bios hack). I've been sure to make sure that I grab the flags associated to the relevant component. I feel that I need to justify why I'm doing it this way instead of cabal envfiles: they do not include language extensions and other things of that nature, and don't separate library/test/etc.
Let's say the user has compiled the project, with tests enabled.
The flags for the library might look something like
... -this-unit-id example-1.0-inplace -hide-all-packages -Wmissing-home-modules -no-user-package-db -package-db -/home/me/.cabal/store/ghc-8.6.5/package.db -package-db -/home/me/example/dist-newstyle/packagedb/ghc-8.6.5 --package-db /home/me/example/dist-newstyle/build/x86_64-linux/ghc-8.6.5/example-1.0/noopt/package.conf.inplace -package-id transformers-0.5.6.2 ...
which all makes sense. If I use these flags then loading Foo.hs will fail because it cannot find Bar.
These modules are needed for compilation but not listed in your .cabal file's other-modules: Bar
Of course I could suppress this by ignoring warnings, but I want to see those modules.... so I have a workaround! I hacked it by changing the -this-unit-id to a -package-id and it all works great because the compiler already has the interface files for Bar in the packagedb. My tool doesn't write any object files, so I think this is safe.
However, when I come to running my tool on test directories, there is no -this-unit-id from v2-repl. I know what the package-id is (from Cabal's plan.json) but it doesn't exist in my packagedb, so I can't re-use my hack.
These modules are needed for compilation but not listed in your .cabal file's other-modules: TestUtils
And I'm back where I started.
So my question is: which flags do I need to provide to the ghc api so that a module can see the interfaces of other modules in the same component? I'm guessing my -this-unit-id hack is horrible and I shouldn't be doing that. What is the correct thing to do?
-- Best regards, Sam
-- Best regards, Sam

Hi, On Tue, Aug 27, 2019 at 06:35:03PM +0100, Sam Halliday wrote:
1. Is there a way to tell ghc to prefer interface files instead of source files, if it finds them, for a TargetModule?
I think targetAllowObjCode=True [1] should do that. If you're using gussTarget and your module name doesn't have a '*' at the beginning that should be the default though. [1]: https://hackage.haskell.org/package/ghc-8.6.5/docs/GHC.html#v:targetAllowObj... --Daniel

Ha! I knew about that flag but thought it was talking about OUTPUT
object code. Thank you so much, I will try that now.
Daniel Gröber
Hi,
On Tue, Aug 27, 2019 at 06:35:03PM +0100, Sam Halliday wrote:
1. Is there a way to tell ghc to prefer interface files instead of source files, if it finds them, for a TargetModule?
I think targetAllowObjCode=True [1] should do that. If you're using gussTarget and your module name doesn't have a '*' at the beginning that should be the default though.
[1]: https://hackage.haskell.org/package/ghc-8.6.5/docs/GHC.html#v:targetAllowObj...
--Daniel
-- Best regards, Sam
participants (2)
-
Daniel Gröber
-
Sam Halliday