Skip to content

Complete documentation of Hpack's main field #609

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 60 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ This is done to allow compatibility with a wider range of `Cabal` versions.

| Hpack | Cabal | Default | Notes |
| --- | --- | --- | --- |
| `main` | `main-is` | | |
| `main` | `main-is` | | Unlike `Cabal`, also accepts a module name or qualified name (see ['Main' IO action](#main-io-action). |
| `other-modules` | · | All modules in `source-dirs` less `main` less any modules mentioned in `when` | |
| `generated-other-modules` | | | Added to `other-modules` and `autogen-modules`. Since `0.23.0`.

Expand All @@ -341,7 +341,7 @@ This is done to allow compatibility with a wider range of `Cabal` versions.
| Hpack | Cabal | Default | Notes |
| --- | --- | --- | --- |
| | `type` | `exitcode-stdio-1.0` | |
| `main` | `main-is` | | |
| `main` | `main-is` | | Unlike `Cabal`, also accepts a module name or qualified name (see ['Main' IO action](#main-io-action). |
| `other-modules` | · | All modules in `source-dirs` less `main` less any modules mentioned in `when` | |
| `generated-other-modules` | | | Added to `other-modules` and `autogen-modules`. Since `0.23.0`.

Expand All @@ -350,7 +350,7 @@ This is done to allow compatibility with a wider range of `Cabal` versions.
| Hpack | Cabal | Default | Notes |
| --- | --- | --- | --- |
| | `type` | `exitcode-stdio-1.0` | |
| `main` | `main-is` | | |
| `main` | `main-is` | | Unlike `Cabal`, also accepts a module name or qualified name (see ['Main' IO action](#main-io-action). |
| `other-modules` | · | All modules in `source-dirs` less `main` less any modules mentioned in `when` | |
| `generated-other-modules` | | | Added to `other-modules` and `autogen-modules`. Since `0.23.0`.

Expand Down Expand Up @@ -481,6 +481,63 @@ becomes
**Note:** Conditionals with `condition: false` are omitted from the generated
`.cabal` file.

#### 'Main' IO action

By convention, a Haskell program must have a module called `Main` which exports
an IO action named `main`. When the program is executed, the action is
performed. However, GHC's `main-is` option can be used to change the name of the
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
performed. However, GHC's `main-is` option can be used to change the name of the
performed. However, GHC's `-main-is` option can be used to change the name of the

relevant IO action.

Hpack's `main` field accepts a module name, a qualified name or a source file
name. Hpack assumes that anything that does not have the format of the first two
possibilities is a source file name. For the first two possibilities, Hpack
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not entirely accurate. Foo.hs is a valid qualified name. However, we interpreted as a file name.

It's roughly:

  1. If it looks like a Haskell source file (ends in .hs or .lhs), we interpret it as a file path.
  2. If it is a valid qualified name, we take it as a qualified name.
  3. If it is a valid module name, we take it as a module name.
  4. As a fallback we take it as a file path.

Or in other words, Hpack does not accept entry points named hs or lhs.

hpack/src/Hpack/Util.hs

Lines 55 to 61 in e11cf4f

parseMain :: String -> (FilePath, [GhcOption])
parseMain main = case reverse name of
x : _ | isQualifiedIdentifier name && x `notElem` ["hs", "lhs"] -> (intercalate "/" (init name) ++ ".hs", ["-main-is " ++ main])
_ | isModule name -> (intercalate "/" name ++ ".hs", ["-main-is " ++ main])
_ -> (main, [])
where
name = splitOn '.' main

assumes that the relevant source file is named after the module.

For example,

```yaml
executables:
my-app:
main: MyMainModule # A module name
```

becomes

executable my-app
main-is: MyMainModule.hs
ghc-options: -main-is MyMainModule
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't frequently document things in terms of how they desugar to .cabal syntax. Rather we document how they can be used, so that a user does not need to be familiar with Cabal to be able to use Hpack.

I'm not saying this is necessarily bad, just want to bring it up.


and,

```yaml
executables:
my-app:
main: MyMainModule.myMainFunc # A qualified name
```

becomes

executable my-app
main-is: MyMainModule.hs
ghc-options: -main-is MyMainModule.myMainFunc

and,

```yaml
executables:
my-app:
main: MyMainSourceFile.hs # A source file name
```

becomes

executable my-app
main-is: MyMainSourceFile.hs

**Note:** Unlike GHC's `main-is` option, a lower-case identifier is not
accepted as the name of the relevant IO action. Hpack will assume it is a
source file name.

### File globbing

At place where you can specify a list of files you can also use glob patterns.
Expand Down