Enlico
Enlico

Reputation: 28490

How to avoid listing A as build dependency for internal library/executable E just because E depends on internal library L which depends on A?

I have a directory structure like this

.
├── Main.hs
├── mynot.cabal
├── Notification.hs
└── Server.hs

where mynot.cabal looks like this

cabal-version:   3.0
name:            mynot
version:         0.1.0.0

common common
    default-language: GHC2021
    build-depends: base

executable mynot
    import: common
    main-is: Main.hs
    build-depends: dbus
                 , async
                 , containers
                 , extra
                 , flow
    other-modules: Server
                 , Notification

library server
    import: common
    exposed-modules: Server
    build-depends: async
                 , containers
                 , dbus
                 , extra
                 , flow
    other-modules: Notification

library notification
    import: common
    exposed-modules: Notification
    build-depends: containers
                 , dbus
                 , extra

but extra is really only needed by Notification.hs, and I have no clue why I need to list it also under the other stanzas for cabal build to succeed.

I found this, and gave it a try, e.g via

$ mkdir exe
$ mv Main.hs exe/.

and then adding hs-source-dirs: exe in the executable stanza, but the build fails like this

Resolving dependencies...
Build profile: -w ghc-9.4.8 -O1
In order, the following will be built (use -v for more details):
 - mynot-0.1.0.0 (exe:mynot) (configuration changed)
 - mynot-0.1.0.0 (lib:notification) (configuration changed)
 - mynot-0.1.0.0 (lib:server) (configuration changed)
Configuring executable 'mynot' for mynot-0.1.0.0..
Configuring library 'notification' for mynot-0.1.0.0..
Configuring library 'server' for mynot-0.1.0.0..
Preprocessing library 'notification' for mynot-0.1.0.0..
Building library 'notification' for mynot-0.1.0.0..
Preprocessing executable 'mynot' for mynot-0.1.0.0..
Error: cabal-3.10.2.1: can't find source for Server in exe,
/home/enrico/mynot/dist-newstyle/build/x86_64-linux/ghc-9.4.8/mynot-0.1.0.0/x/mynot/build/mynot/autogen,
/home/enrico/mynot/dist-newstyle/build/x86_64-linux/ghc-9.4.8/mynot-0.1.0.0/x/mynot/build/global-autogen

Preprocessing library 'server' for mynot-0.1.0.0..
Building library 'server' for mynot-0.1.0.0..
Error: cabal: Failed to build exe:mynot from mynot-0.1.0.0.

Is something wrong with my project or just something missing in it?

Upvotes: 2

Views: 101

Answers (1)

Noughtmare
Noughtmare

Reputation: 10695

When you use a different hs-source-dirs then that will also influence where cabal will look for the other-modules.

Instead of using other-modules like that, you should add the components to each others build-depends like this:

executable mynot
    import: common
    main-is: Main.hs
    build-depends: dbus
                 , async
                 , containers
                 , flow
                 , mynot:server
                 , mynot:notification
    hs-source-dirs: exe

library server
    import: common
    exposed-modules: Server
    build-depends: async
                 , containers
                 , dbus
                 , flow
                 , mynot:notification
    hs-source-dirs: server

library notification
    import: common
    exposed-modules: Notification
    build-depends: containers
                 , dbus
                 , extra
    hs-source-dirs: notification

And you do apparently need to create directories for each component, so the file structure should look like this:

.
├── exe/Main.hs
├── mynot.cabal
├── notification/Notification.hs
└── server/Server.hs

Of course you can use different names for the directories if you change the hs-source-dirs fields too.

Generally, you want each module to be listed in only a single component. Otherwise each component will rebuild that module separately.

Upvotes: 4

Related Questions