Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Another module than given in main-is is picked as main module #10832

Open
andreasabel opened this issue Mar 15, 2025 · 1 comment
Open

Another module than given in main-is is picked as main module #10832

andreasabel opened this issue Mar 15, 2025 · 1 comment
Labels
re: main Concerning the `main-is` field type: bug

Comments

@andreasabel
Copy link
Member

andreasabel commented Mar 15, 2025

If the module in main-is has a name and there is another module that has no explicit name (no module header), then the other module is picked as main module.

Bar.hs

main = putStrLn "I am the shady main..."

Foo.hs

module Foo where

main = putStrLn "I am the real main!"

wrong-main.cabal

cabal-version: 1.12
name:           wrong-main
version:        0.0.0
build-type:     Simple

executable wrong-main
  main-is: Foo.hs
  other-modules:
      Bar
      Paths_wrong_main
  hs-source-dirs:
      ./
  build-depends:
      base
  default-language: Haskell2010
$ cabal run
...                                                                                                       
I am the shady main...

Packaged reproducer: wrong-main.tgz

Analysis: It seems Cabal calls GHC this way:

ghc --make -fbuilding-cabal-package -O -static ...  -XHaskell2010 ./Foo.hs Bar Paths_wrong_main ...

The correct result can be obtained by adding -main-is Foo:

ghc --make -main-is Foo Bar.hs Foo.hs    

I suppose the difficulty is to extract the module name Foo from Foo.hs, since -main-is does not accept a file, just a qualified (module) name.

(I am having a dejavu here, but I couldn't find a report for this issue.)

Stack has the same problem:

@phadej
Copy link
Collaborator

phadej commented Mar 17, 2025

I think the real issue is that

 other-modules:
      Bar

is accepted, while Bar.hs contains module Main. there aren't module Bar.

And I don't have a good solution to this problem.

I thought long ago, that if GHC accepted arguments something like Bar:path/to/SomeFile.hs, then it would solve this issue; and also make it possible to turn automatic module discovery in GHC (which would allow components to share hs-source-dirs). In this case GHC should complain if module name and given module paths don't agree.

Then we allow different syntax for main-is, matching the above main-is: Foo:Foo.hs, and treat old variants, i.e.
main-is: Foo.hs as if they were main-is: Main:Foo.hs.

TL;DR, the core problem is that Cabal and GHC have to no way to communicate module <-> path mapping; and Cabal has to "reverse-engineer" what GHC is doing, instead of being explicit, and just telling GHC where to look for the sources.

I.e. I think this is GHC design issue. Parsing Haskell files to figure out module names is not something Cabal should even consider doing. (For example there could be custom literate preprocessor, or even just complicated CPP)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
re: main Concerning the `main-is` field type: bug
Projects
None yet
Development

No branches or pull requests

2 participants