How to specify import paths for a frontend plugin

Hi ghc-devs, I’m making a first attempt to make a frontend plugin, to resolve cabal packages in the GHC API. However I’m running into troubles with module resolution in the GHC API, because I can’t control where it will search for modules at all. I've attached a minimal example, with a frontend plugin definition that can’t find modules (Plugin.hs), and an equivalent standalone program that does (Main.hs). Specifically, I'm following a solution Edward Yang published in 2017 (http://blog.ezyang.com/2017/02/how-to-integrate-ghc-api-programs-with-cabal/), where the frontend plugin is called through a helper script that passes flags forwarded from `cabal repl`. To test the plugin directly with GHC, I collected the args through the helper script and filtered them to the minimal set that made the plugin run: ghc --frontend Plugin -itarget -package-db dist-newstyle/packagedb/ghc-8.6.5 Plugin -plugin-package sandbox -hide-all-packages This, as well as the full argument set, would complain that it can't find the target module under `./target/A.hs`: <no location info>: error: module ‘A’ cannot be found locally It does when the import path arg `-itarget` is absolute. Still, its `importPaths` are what I expect: [".", "target"], and the standalone program finds the target module with the same `importPaths`. I've tested this in GHC 8.6.5, 8.4.2 and 8.2.2, making me sure I'm just missing something, but I haven’t found help in the docs yet. I really appreciate some help to draw my hours over this to a close! Thanks, Derek PS the full invocation of the plugin (with absolute paths swapped with relative ones, except `-itarget` which was relative to begin with) is: ghc --frontend Plugin -plugin-package sandbox -fbuilding-cabal-package -O0 -outputdir dist-newstyle/build/x86_64-osx/ghc-8.6.5/sandbox-0.1.0.0/build -odir dist-newstyle/build/x86_64-osx/ghc-8.6.5/sandbox-0.1.0.0/build -hidir dist-newstyle/build/x86_64-osx/ghc-8.6.5/sandbox-0.1.0.0/build -stubdir dist-newstyle/build/x86_64-osx/ghc-8.6.5/sandbox-0.1.0.0/build -i -idist-newstyle/build/x86_64-osx/ghc-8.6.5/sandbox-0.1.0.0/build -i. -itarget -idist-newstyle/build/x86_64-osx/ghc-8.6.5/sandbox-0.1.0.0/build/autogen -idist-newstyle/build/x86_64-osx/ghc-8.6.5/sandbox-0.1.0.0/build/global-autogen -Idist-newstyle/build/x86_64-osx/ghc-8.6.5/sandbox-0.1.0.0/build/autogen -Idist-newstyle/build/x86_64-osx/ghc-8.6.5/sandbox-0.1.0.0/build/global-autogen -Idist-newstyle/build/x86_64-osx/ghc-8.6.5/sandbox-0.1.0.0/build -optP-include -optPdist-newstyle/build/x86_64-osx/ghc-8.6.5/sandbox-0.1.0.0/build/autogen/cabal_macros.h -this-unit-id sandbox-0.1.0.0-inplace -hide-all-packages -Wmissing-home-modules -no-user-package-db -package-db /Users/derek-lam/.cabal/store/ghc-8.6.5/package.db -package-db dist-newstyle/packagedb/ghc-8.6.5 -package-db dist-newstyle/build/x86_64-osx/ghc-8.6.5/sandbox-0.1.0.0/package.conf.inplace -package-id base-4.12.0.0 -package-id ghc-8.6.5 -XHaskell2010 Plugin -hide-all-packages

Derek Lam
Hi ghc-devs,
Hi Derek,
I’m making a first attempt to make a frontend plugin, to resolve cabal packages in the GHC API. However I’m running into troubles with module resolution in the GHC API, because I can’t control where it will search for modules at all. I've attached a minimal example, with a frontend plugin definition that can’t find modules (Plugin.hs), and an equivalent standalone program that does (Main.hs).
Specifically, I'm following a solution Edward Yang published in 2017 (http://blog.ezyang.com/2017/02/how-to-integrate-ghc-api-programs-with-cabal/), where the frontend plugin is called through a helper script that passes flags forwarded from `cabal repl`. To test the plugin directly with GHC, I collected the args through the helper script and filtered them to the minimal set that made the plugin run:
ghc --frontend Plugin -itarget -package-db dist-newstyle/packagedb/ghc-8.6.5 Plugin -plugin-package sandbox -hide-all-packages
This, as well as the full argument set, would complain that it can't find the target module under `./target/A.hs`:
<no location info>: error: module ‘A’ cannot be found locally
It does when the import path arg `-itarget` is absolute.
By "it does" do you mean "it still fails"?
Still, its `importPaths` are what I expect: [".", "target"], and the standalone program finds the target module with the same `importPaths`. I've tested this in GHC 8.6.5, 8.4.2 and 8.2.2, making me sure I'm just missing something, but I haven’t found help in the docs yet. I really appreciate some help to draw my hours over this to a close!
Hmm, very interesting. If I recall correctly, the relevant codepath in GHC is Finder.findImportedModule which should find the module via Finder.findHomeModule. Unfortunately, in my cursory look I didn't see any obvious issues; it looks like this might require a build of GHC and a bit of debugging. If you can produce a minimal, concrete reproducer (e.g. your plugin and a set of specific instructions to reproduce the issue) it's possible I can have a look. Cheers, - Ben

Hi Ben,
Thanks for the pointer. I looked for the error call and it does indeed look like the path from the error in GhcMake.downsweep feeds from GhcMake.summariseModule and then Finder.findImportedModule. A cursory look at Finder seems to suggest that the importPaths retrieved in findInstalledHomeModule go untouched to the doesFileExist through searchPathExts. The working directories, at least as seen in the plugin body, is the directory of execution as expected, and is the same as the standalone program, but I could certainly be missing the whole picture in Finder.
I've attached a package that demonstrates what I've tested so far, along with Edward Yang's original solution I was following.
1. The standalone executable runs with `cabal run standalone`.
2. The plugin runs via ghc with the same command from the last email:
ghc --frontend Plugin -itarget -package-db dist-newstyle/packagedb/ghc-8.6.5 Plugin -plugin-package plugin-test -hide-all-packages
3. Running the plugin per Edward Yang's solution needs to `cabal build` the wrapper and lib first, then invoking via `cabal repl target -w` with an absolute path to the plugin executable:
cabal repl target -w "$(pwd)/dist-newstyle/build/<build-target>/ghc-<ghc-version>/plugin-test-0.1.0.0/x/plugin-wrapper/build/plugin-wrapper/plugin-wrapper"
...at least that's the path on my distribution. (Unfortunately it seems resolving the plugin by name alone doesn't seem to work >= 8.4.2).
In case 1, it works. In cases 2 and 3, I get "error: module ‘A’ cannot be found locally".
By the way, by "it does" I meant it does work when I use an absolute path.
Hope this sheds some light! Thanks so much,
Derek
On 2020-01-06, 07:32, "Ben Gamari"
participants (2)
-
Ben Gamari
-
Derek Lam