Skip to content

Duplicate component name in build path. #10965

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
angerman opened this issue May 18, 2025 · 7 comments
Open

Duplicate component name in build path. #10965

angerman opened this issue May 18, 2025 · 7 comments

Comments

@angerman
Copy link
Collaborator

angerman commented May 18, 2025

Ref.: #4548 When building sublibraries with cabal today, you end up with build paths like:

$pkg/l/$comp/build/$comp/

note the duplicate $lib in there.

Tracking this down, leads us to two commits by @ezyang almost a decade ago.

on Mar 30, 2016 8e3c2d7
introduced the componentBuildDir which added the $comp as a suffix to the $buildDir.

$pkg/l/$comp/build/$comp/
                   ^^^^^

(this is lib:Cabal).

on Aug 21, 2016 d9bf678
Changed the

distBuildRootDirectory </> display pkgid

to also include a c/$comp suffix. This was later modified by @hvr to have distinct single letter names for different components. E.g. l for library.

$pkg/l/$comp/build/$comp/
     ^^^^^^^

(this is cabal-install).

Thus we now have $comp redundantly twice in the path. Also the buildPath we pass to runConfigureScript (in ConfigureScript.hs), via ConfigFlags:CommonSetupFlags:setupDistPref is $pkg/l/$comp/build.

It seems to me we've basically changed the component build path twice; while we only need to change it once to make it unique per component. As such I'm proposing to conceptually revert the componentBuildDir change from 8e3c2d7. And leave $pkg/l/$comp/build to be the build directory. This will also transparently make build-type: Configure work for components. We already run the configure script in the $pkg/l/$comp folder per component.

@angerman
Copy link
Collaborator Author

This of course is some lib:Cabal vs cabal-install thing again 🙄

@angerman
Copy link
Collaborator Author

After some further reflection this will be a lot more involved to get right, simply because Setup.hs and cabal-install workflows do it significantly differently.

With a Setup.hs (to support Configure)

import Distribution.Simple
main = defaultMainWithHooks autoconfUserHooks

we have two invocations:

runghc Setup.hs configure lib:foo

and

runghc Setup.hs build lib:foo

now there is no guarantee you ran configure lib:foo

runghc Setup.hs configure
runghc Setup.hs build lib:foo

will also work. The configure script is run once (during the configure step).

On the other hand when building components with cabal-install, we'll run configure for each component separately, also in separate folders. Just with the confusion of running it in $pkg/l/$comp/build/ instead of $pkg/l/$comp/build/$comp/. Which then means any folders expected to be relative during configure are not.

Over all Configure is at the package level, so having configure be executed per component might be undesirable as well.

@angerman
Copy link
Collaborator Author

While experimenting with this further, I noticed something interesting

$ runghc Setup.hs configure 
Configuring test-pkg-0.1.0.0...
configure: WARNING: unrecognized options: --with-compiler
configure: creating ./config.status
config.status: creating test-pkg.buildinfo
config.status: creating include/test.h
configure: WARNING: unrecognized options: --with-compiler
Error: Setup.hs: Missing dependency on a foreign library:
* Missing (or bad) header file: test.h
This problem can usually be solved by installing the system package that
provides this library (you may need the "-dev" version). If the library is
already installed but in a non-standard location then you can use the flags
--extra-include-dirs= and --extra-lib-dirs= to specify where it is.If the
library file does exist, it may contain errors that are caught by the C
compiler at the preprocessing stage. In this case you can re-run configure
with the verbosity flag -v3 to see the error messages.
If the header file does exist, it may contain errors that are caught by the C
compiler at the preprocessing stage. In this case you can re-run configure
with the verbosity flag -v3 to see the error messages.

vs.

$ runghc Setup.hs configure lib:foo
Configuring library 'foo' for test-pkg-0.1.0.0..
configure: WARNING: unrecognized options: --with-compiler
configure: creating ./config.status
config.status: creating test-pkg.buildinfo
config.status: creating include/test.h
config.status: include/test.h is unchanged
configure: WARNING: unrecognized options: --with-compiler

we don't even pick up the .buildinfo file for components today, due to the $comp part in dist/build/$comp.

Arguably Configure with Setup.hs is broken already today for components.

@angerman
Copy link
Collaborator Author

angerman commented May 18, 2025

Futher we find that if we try to configure a package with only sublibraries, (no main library), cabal will even bail out with:

Error: [Cabal-8004]
The buildinfo contains info for a library, but the package does not have a library.

, if we produce a buildinfo file.

This stems from

sanityCheckHookedBuildInfo
  :: Verbosity -> PackageDescription -> HookedBuildInfo -> IO ()
sanityCheckHookedBuildInfo
  verbosity
  (PackageDescription{library = Nothing})
  (Just _, _) =
    dieWithException verbosity $ NoLibraryForPackage

with

type HookedBuildInfo = (Maybe BuildInfo, [(UnqualComponentName, BuildInfo)])

Thusly, I think we can safely assume that Configure sensibly only ever applies to the main library of any cabal file. Notably the documentation talks about this.

Therefore and as #4548 also somewhat alluded to, the only sensible thing to do seems to be to restrict Configure to the library stanza, and have everything else have to depend on that library if needed. Even running configure for a component makes no sense in cabal.

Therefore, I'll proceed to just null build-type Configure on component in cabal-install. Not sure what to do about lib:Cabal though, we'd still want to run Configure for the main library.

NOTE: this does not address the duplication in the path though.

@mpickering
Copy link
Collaborator

mpickering commented May 21, 2025

Can you summarise what the problem of this ticket is? I don't see immediately why having the component name in the build path twice is a problem, is it an aesthetic issue?

I was also reminded of this issue with buildinfo, #10238, but I am not sure that is relevant either.

It seems the problem might actually something to do with sublibraries and Configure build-type?

@mpickering mpickering reopened this May 21, 2025
@ulysses4ever
Copy link
Collaborator

I'd prefer to not have the component name duplicated in the build path if possible. It's not only pure aesthetics. In the ideal world you'd never want to read these paths, but in reality I do have to read them often, and having junk in the paths make my life harder because of the added length and, therefore, cognitive load.

@angerman
Copy link
Collaborator Author

It's not just aesthetic, it's also about path-lengths. Not all operating systems permit infinitely long paths. The other is, that yes, under component builds, the configure script is run in a folder that's not the root of the package being built.

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