Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does "legacy fallback" mean when cabal is building packages?

When using cabal to build a Haskell package, it appears to mark some packages as legacy fallback:

$ cabal build
Resolving dependencies...
Build profile: -w ghc-9.0.1 -O1
In order, the following will be built (use -v for more details):
 - appar-0.1.8 (lib:appar) (requires build)
 - auto-update-0.1.6 (lib) (requires build)
 - base-compat-0.11.2 (lib) (requires build)
...
Building     base-orphans-0.8.4 (lib)
Building     appar-0.1.8 (all, legacy fallback)
Downloaded   memory-0.16.0
Downloading  cryptonite-0.29
Installing   base-orphans-0.8.4 (lib)
Downloaded   cryptonite-0.29
Downloading  some-1.0.3
...

You can see that for some libraries, they are specifically marked (lib), but other libraries are marked (all, legacy fallback).

What is the difference between these? What does legacy fallback mean?


I am using cabal-install version 3.4.0.0:

$ cabal --version
cabal-install version 3.4.0.0
compiled using version 3.4.0.0 of the Cabal library 
like image 682
illabout Avatar asked Jun 29 '21 06:06

illabout


Video Answer


1 Answers

I took a dive in the source code. The error message comes form here:

    dispname = case elabPkgOrComp pkg of
        ElabPackage _ -> prettyShow pkgid
            ++ " (all, legacy fallback)"
        ElabComponent comp -> prettyShow pkgid
            ++ " (" ++ maybe "custom" prettyShow (compComponentName comp) ++ ")"

So I started looking for places where ElabPackage is constructed. I found this:

    elaborateSolverToPackage
        ...
      where
        ...
        elab1 = elab0 {
                elabUnitId = newSimpleUnitId pkgInstalledId,
                elabComponentId = pkgInstalledId,
                elabLinkedInstantiatedWith = Map.empty,
                elabPkgOrComp = ElabPackage $ ElaboratedPackage {..},
                elabModuleShape = modShape
            }

This in turn is used here:

    elaborateSolverToComponents mapDep spkg@(SolverPackage _ _ _ deps0 exe_deps0)
        = case mkComponentsGraph (elabEnabledSpec elab0) pd of
           Right g -> do
            ...
            let not_per_component_reasons = why_not_per_component src_comps
            if null not_per_component_reasons
                then return comps
                else do checkPerPackageOk comps not_per_component_reasons
                        return [elaborateSolverToPackage spkg g $
                                comps ++ maybeToList setupComponent]

Now the why_not_per_component is very interesting as that function determines when to use the legacy fallback. It is defined here:

        -- You are eligible to per-component build if this list is empty
        why_not_per_component g
            = cuz_buildtype ++ cuz_spec ++ cuz_length ++ cuz_flag ++ cuz_coverage

There in the code right below that we can see that it can be caused by these reasons:

  • The build-type is Custom or Configure
  • The cabal-version is less than 1.8
  • There are no buildable components
  • You passed the --disable-per-component flag.
  • Program coverage is enabled

So for the appar library it is because the cabal-version is 1.6 which is lower than 1.8, see https://github.com/kazu-yamamoto/appar/blob/v0.1.8/appar.cabal#L10.

like image 83
Noughtmare Avatar answered Dec 02 '22 07:12

Noughtmare