2
votes

I'm contributing to an open source project which defines its project setup in a cabal file that looks like this (omitting lots of properties that are not relevant for this problem):

library
  hs-source-dirs:    src
  build-depends:
                     base >= 4.9 && < 5,
                     some-other-deps
  exposed-modules:
                     Data.Foo.Bar,
                     Data.Foo.Baz
  other-modules:
                     Data.Foo.Bar.Internal

test-suite test
  hs-source-dirs:
                     tests
  build-depends:
                     foo-library
  other-modules:
                     Foo.Bar.Tests,
                     Foo.Baz.Tests

Now, in order to test the feature I'm adding, I want the tests to have access to the Data.Foo.Bar.Internal module, but since it's hidden in the library, I can't access it from the tests.

I looked at the cabal docs which suggested adding a third component - an internal library (unfortunately not linkable, but search for "internal libraries"). If I understand the documentation correctly, I should be able to do something like this:

library foo-internal
  hs-source-dirs:    src
  build-depends:
                     base,
                     some-other-deps
  exposed-modules:
                     Data.Foo.Bar.Internal

library
  hs-source-dirs:    src
  build-depends:
                     base >= 4.9 && < 5,
                     foo-internal,
                     some-other-deps
  exposed-modules:
                     Data.Foo.Bar,
                     Data.Foo.Baz

test-suite test
  hs-source-dirs:
                     tests
  build-depends:
                     foo-library,
                     foo-internal
  other-modules:
                     Foo.Bar.Tests,
                     Foo.Baz.Tests

but running stack build here gives me warnings that Data.Foo.Bar.Internal "should be added to exposed-modules or other-modules in ./foo.cabal", and then a build error in the test that seems to be caused by failed unification (it points to a function argument for a function defined in the library, says that its type must be Data.Foo.Bar.Internal.Qux defined in package foo, and that the type foo:Data.Foo.Bar.Internal.Qux don't match).

How can I expose internal modules to the test suite, without exposing them also to consumers of the library?

1
Does it help if you move the .hs files of foo-internal to another hs-source-dirs, say, src-internal? - danidiaz
@danidiaz Possibly; I'm not sure I can do that, though, since it's not my project (and the main point here is to get a PR accepted) but I'll try it out locally to see if it helps. - Tomas Aschan
@danidiaz: Yes, moving the files to a different root seems to work. - Tomas Aschan
I've had the same problem, but I haven't found the exact place in the Cabal user guide that says that different libraries should have different source folders. cabal.readthedocs.io/en/3.4/… - danidiaz

1 Answers

2
votes

As mentioned in the comments, different components (internal libraries, executables) should have modules under different roots.