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

Allow stack build to target sub-libraries #6042

Open
philderbeast opened this issue Jan 22, 2023 · 6 comments
Open

Allow stack build to target sub-libraries #6042

philderbeast opened this issue Jan 22, 2023 · 6 comments

Comments

@philderbeast
Copy link
Contributor

philderbeast commented Jan 22, 2023

Could we add lib as a comptype in docs section for target syntax?

  • component. Instead of referring to an entire package and letting Stack decide which components to build, you select individual components from inside a package. This can be done for more fine-grained control over which test suites to run, or to have a faster compilation cycle. There are multiple ways to refer to a specific component (provided for convenience):

packagename:comptype:compname is the most explicit. The available comptypes are exe, test, and bench.
SOURCE: Target syntax

There's no mention of lib as comptype but I can use it.

$ stack repl stack:lib
stack> initial-build-steps (lib)
Configuring GHCi with the following packages: stack
GHCi, version 9.2.5: https://www.haskell.org/ghc/  :? for help
[  1 of 117] Compiling Network.HTTP.StackClient
...
[117 of 117] Compiling Stack.Ls
Ok, 117 modules loaded.
ghci>

I see it listed as a packagename:comptype target:

$ stack ide targets
stack:lib
stack:exe:stack
stack:exe:stack-integration-test
stack:test:stack-test

The library name is the same as the package name but we can't use that as a packagename:comptype:compname target.

$ stack repl stack:lib:stack
Error: [S-6948]
TargetParseException ["Directory not found: stack:lib:stack"]
Note that to specify options to be passed to GHCi, use the '--ghci-options' flag.

When we support multiple library packages we'll need to be able to specify the compname of libraries. Before that feature lands we could allow compname for libraries.

@mpilgrem
Copy link
Member

mpilgrem commented Jan 22, 2023

@philderbeast, it looks to me that that documentation is indeed incomplete, because it does not discuss packagename:lib.

Some further notes for my own use:

  • My simple test is stack new sublib with the package.yaml file edited to replace the public library with an internal library named my-lib:

    internal-libraries:
      my-lib:
        source-dirs: src

    Building that with the version of Stack in the master branch yields:

    Warning: SubLibrary dependency is not supported, this will almost certainly fail.
    Building all executables for `sublib' once. After a successful build of all of them, only specified executables will be rebuilt.
    sublib> configure (internal-lib + exe)
    Configuring sublib-0.1.0.0...
    sublib> build (internal-lib + exe)
    Preprocessing library 'my-lib' for sublib-0.1.0.0..
    Building library 'my-lib' for sublib-0.1.0.0..
    [1 of 2] Compiling Lib
    [2 of 2] Compiling Paths_sublib
    Preprocessing executable 'sublib-exe' for sublib-0.1.0.0..
    Building executable 'sublib-exe' for sublib-0.1.0.0..
    [1 of 2] Compiling Main
    [2 of 2] Compiling Paths_sublib
    Linking .stack-work\dist\8a54c84f\build\sublib-exe\sublib-exe.exe ...
    sublib> copy/register
    Installing internal library my-lib in C:\Users\mikep\Documents\Code\Haskell\sublib\.stack- 
    work\install\b0212ea3\lib\x86_64-windows-ghc-9.2.5\sublib-0.1.0.0-5SwOnzRGzitA9U58Nrua6j-my-lib
    Installing executable sublib-exe in C:\Users\mikep\Documents\Code\Haskell\sublib\.stack-work\install\b0212ea3\bin
    

    In this case, the initial warning seems misplaced, as the build does not fail.

    The initial warning is generated by Stack.Build.checkSubLibraryDependencies; perhaps it is no longer applicable?

  • Type Stack.Build.Target.RawTarget has a data constructor RTComponent.

  • There is also Stack.Build.Target.resolveRawTarget, which accepts (among other things) RawTarget and yields a ResolveResult (including, among other things, Maybe NamedComponent).

  • Type Stack.Types.NamedComponent.NamedComponent does have a data constructor CLib (for a public library) and also CInternalLib !Text (for a named internal library).

  • There is also Stack.Build.Target.parseRawTarget which has (extract below) where the internal library is currently filtered out:

    parsePackageComponent =
      case T.splitOn ":" t of
        [pname, "lib"]
          | Just pname' <- parsePackageName (T.unpack pname) ->
              Just $ RTPackageComponent pname' $ ResolvedComponent CLib
        [pname, cname]
          | Just pname' <- parsePackageName (T.unpack pname) ->
              Just $ RTPackageComponent pname' $ UnresolvedComponent cname
        [pname, typ, cname]
          | Just pname' <- parsePackageName (T.unpack pname)
          , Just wrapper <- parseCompType typ ->
              Just $ RTPackageComponent pname' $ ResolvedComponent $ wrapper cname
        _ -> Nothing
    
    parseCompType t' =
      case t' of
        "exe" -> Just CExe
        "test" -> Just CTest
        "bench" -> Just CBench
        _ -> Nothing
  • Adding "lib" to parseCompType allows the component to be specified, but then Stack does not recognise it as being in the package:

    While parsing, Stack encountered the error:

        Component internal-lib:my-lib does not exist in package foo.
    
  • Extending Stack.Types.Config.ppComponents can include internal libraries (extract):

    -- | All components available in the given 'ProjectPackage'
    ppComponents :: MonadIO m => ProjectPackage -> m (Set NamedComponent)
    ppComponents pp = do
      gpd <- ppGPD pp
      pure $ Set.fromList $ concat
        [ maybe []  (const [CLib]) (C.condLibrary gpd)
        , go CInternalLib (fst <$> C.condSubLibraries gpd)
        , go CExe   (fst <$> C.condExecutables gpd)
        , go CTest  (fst <$> C.condTestSuites gpd)
        , go CBench (fst <$> C.condBenchmarks gpd)
        ]
     where
      go :: (T.Text -> NamedComponent)
         -> [C.UnqualComponentName]
         -> [NamedComponent]
      go wrapper = map (wrapper . T.pack . C.unUnqualComponentName)

Then Stack complains:

❯ stack build foo:lib:my-lib
Error: [S-7086]
The following components have 'buildable: False' set in the Cabal configuration, and so cannot be targets:
    foo:exe:my-lib
To resolve this, either provide flags such that these components are buildable, or only specify buildable targets.

@mpilgrem
Copy link
Member

@philderbeast, I've improved the existing online documentation.

@mpilgrem mpilgrem changed the title Is lib a comptype and can we target them by name? Allow stack build to target sub-libraries Mar 18, 2024
@wraithm
Copy link
Contributor

wraithm commented Apr 11, 2024

I don't know if this should be a separate issue, but I'm having trouble getting sub-libs into HLS. I suspect it's related to this issue.

@mpilgrem
Copy link
Member

@theobat, currently, Stack's target syntax my-package:lib targets all of the library components of package my-package. Given the changes you have already made, do you think it would be difficult to change things so that my-package:lib targets only the main library and (eg) my-package:lib:my-sub-library targets the named library my-sub-library?

@theobat
Copy link
Contributor

theobat commented Apr 17, 2024

yes, this is a significant change, mainly because of how the cache system was built in stack, it's package based so building anything less than "all the libraries" means we have to deal with partial values in the cache. I don't remember all the details, but this is somewhat orthogonal to the component based builds : using component based builds, using package based builds we can also build "partially" a package.
Note that for component based builds I made a change in the cache system that is a step in the right direction for this, but it's only a step, dealing with partial cache values is going to be the real thing here.

@mpilgrem
Copy link
Member

@theobat, many thanks. I'll add 'the cache system' to my list of things I need to understand!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants