How to use local packages with Stack?

I tried to add package B in package A’s stack.yaml in extra-deps with path given in stack sdist for B. And I can import "package B" Lib in A’s Main.hs, but in Lib.hs, there is an error like

Could not find module ‘Lib’
Perhaps you meant
    ......

how to solve it? and is there any more complete resource for haskell tools other than official doc worth reading?

Thanks

I don’t have a direct answer for you, but a google search for the error message, like
stack "Could not find module 'Lib'", will usually get you unstuck. Also no, there’s no more complete docs for the tools than their official user guides & support channels.

You can add it in your packages list:

packages:
  - .
  - yourdep

This assumes your package.yaml is next to your stack.yaml, and the dep is in yourdep as a subdirectory.

@tionway, I understand that you want

  • two local packages, packageA and packageB
  • where the main library of each exposes a module named Lib
  • where packageA is a dependency of packageB
  • where packageA can be treated as an immutable extra-dep rather than as a mutable project package.

We see from Stack’s documentation that a local archive file of a package can be an extra-dep.

So:

> stack new packageA
> stack sdist packageA # Create an archive file for packageA
...
Wrote sdist-format compressed archive to
D:\Users\mike\Code\Haskell\packageA\.stack-work\dist\f24b2e15\packageA-0.1.0.0.tar.gz.
...
> stack new packageB
> cd packageB
> # Edit the packageB project, see further below for details
> stack build # Build packageB library and executable
...
> stack exec -- packageB-exe # Execute the built packageB executable
someFunc
someFunc

I edit the packageB project as follows (see above):

Set packageA as a dependency in the package description file for packageB (extract):

# package.yaml for packageB
...
dependencies:
- base >= 4.7 && < 5
- packageA # Add as dependency
...

Set the packageA archive file as an extra-dep in the Stack project-level configuration file:

# stack.yaml of the packageB project
snapshot: lts-24.25

extra-deps:
- D:\Users\mike\Code\Haskell\packageA\.stack-work\dist\f24b2e15\packageA-0.1.0.0.tar.gz

Edit the packageB src\Lib.hs source file:

{-# LANGUAGE PackageImports #-}

module Lib
    ( someFunc
    ) where

-- We need to qualify the import with the package name, given the clashes:
import "packageA" Lib ( someFunc )

Edit the packageB app\Main.hs source file:

{-# LANGUAGE PackageImports #-}

module Main (main) where

-- We need to qualify the imports with package names, given the clashes:
import qualified "packageA" Lib as A
import           "packageB" Lib

main :: IO ()
main = do
  A.someFunc  -- from packageA
  someFunc    -- from packageB
4 Likes

Alternatively, if what you want is:

  • two local packages, packageA and packageB
  • where the main library of each exposes a module named Lib
  • where packageA is a dependency of packageB
  • where packageA can be treated as a mutable project package (rather than as an immutable extra-dep)

then the solution is the same, except (1) you no longer need a local archive file for packageA - so no use of stack sdist and (2) for the Stack project-level configuration file for the packageB project. The latter now becomes (no extra-dep added to the snapshot):

# stack.yaml of the packageB project
snapshot: lts-24.25

packages:
- . # packageB
- ../packageA # Relative path to the packageA package's root directory

As packageA is now specified as a project package of the packageB project, it generates possible build targets for that project (in addition to those of the packageB project package):

> stack ide targets
packageA:lib
packageA:exe:packageA-exe
packageA:test:packageA-test
packageB:lib
packageB:exe:packageB-exe
packageB:test:packageB-test
2 Likes

As a second alternative, if what you want is:

  • two local packages, packageA and packageB
  • where the main library of each exposes a module named Lib
  • where packageA is a dependency of packageB
  • where packageA can be treated as a mutable extra-dep (rather than as immutable)

then the solution is the same as the first, except (1) you no longer need a local archive file for packageA - so, again, no use of stack sdist and (2) for the Stack project-level configuration file for the packageB project. The latter now becomes (an extra-dep added to the snapshot):

# stack.yaml of the packageB project
snapshot: lts-24.25

extra-deps:
- ../packageA # Relative path to the packageA package's root directory

As packageA is not a project package of the packageB project, it does not generate possible build targets for that project:

> stack ide targets
packageB:lib
packageB:exe:packageB-exe
packageB:test:packageB-test
2 Likes

it works! thanks.
And it seems the key is where to write the dependency. I wrote it under

executable:
    ...
    dependencies:
        - package B
        - package A

and it should be written under

dependencies:
  - base >= 4.7 && < 5
  - package A

I don’t understand the differences here

Each component of a Haskell package (libraries, executables, test suites, benchmarks) (described in a section/stanza of a package description file) can have different direct dependencies on other Haskell packages (as well as direct dependencies in common, such as on the base package).

You were specifying that an executable component of packageB had a direct dependency on packageA (and the main library component of packageB), but what about the direct dependencies of the main library component of packageB? They were not fully specified.

Where components of a package have direct dependencies in common, the Hpack package description format allows the use of the dependencies key at the top level of the package description. The top-level value of that key is merged with the per-section values of that key, see:

Instead of using a top-level key to keep things short, I could have written (extract):

# package.yaml for packageB
...
library:
   ...
  dependencies:
  - packageA # Add as a dependency of the main library
  ...

executables:
  packageB-exe:
    ...
    dependencies:
    - packageA # Add as a dependency of the executable
    ...
2 Likes