Skip to content

Commit

Permalink
One-component configure, fixes haskell#2802.
Browse files Browse the repository at this point in the history
Described in: ghc-proposals/ghc-proposals#4

./Setup configure now takes an argument to specify a specific
component name that should solely be configured.

Most of the gyrations in Configure are all about making it so that
we can feed in internal dependencies via --dependency.

I dropped the package name match sanity check to handle convenience
library package name munging.  Consider an internal library named
'q' in package 'p'.  When we install it to the package database,
we munged the package name into 'z-p-z-q', so that it doesn't
conflict with the actual package named 'q'.  Now consider when
we feed it in with --dependency q=p-0.1-hash-q.  Previously,
Cabal checked that the 'q' in --dependency matched the package
name in the database... which it doesn't. So I dropped the check.

I also had to make register/copy unconditionally install internal
libraries; otherwise you can't refer to them from later builds.

Also a miscellaneous refactor: convenience libraries are printed with a
"header" stanza now (not really a stanza header).

Signed-off-by: Edward Z. Yang <[email protected]>
  • Loading branch information
ezyang committed Aug 21, 2016
1 parent 2cfd810 commit 9441c52
Show file tree
Hide file tree
Showing 29 changed files with 417 additions and 144 deletions.
11 changes: 11 additions & 0 deletions Cabal/Cabal.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,17 @@ extra-source-files:
tests/PackageTests/Configure/include/HsZlibConfig.h.in
tests/PackageTests/Configure/zlib.buildinfo.in
tests/PackageTests/Configure/zlib.cabal
tests/PackageTests/ConfigureComponent/Exe/Bad.hs
tests/PackageTests/ConfigureComponent/Exe/Exe.cabal
tests/PackageTests/ConfigureComponent/Exe/Good.hs
tests/PackageTests/ConfigureComponent/SubLib/Lib.cabal
tests/PackageTests/ConfigureComponent/SubLib/Lib.hs
tests/PackageTests/ConfigureComponent/SubLib/exe/Exe.hs
tests/PackageTests/ConfigureComponent/Test/Lib.hs
tests/PackageTests/ConfigureComponent/Test/Test.cabal
tests/PackageTests/ConfigureComponent/Test/testlib/TestLib.hs
tests/PackageTests/ConfigureComponent/Test/testlib/testlib.cabal
tests/PackageTests/ConfigureComponent/Test/tests/Test.hs
tests/PackageTests/CopyAssumeDepsUpToDate/CopyAssumeDepsUpToDate.cabal
tests/PackageTests/CopyAssumeDepsUpToDate/Main.hs
tests/PackageTests/CopyAssumeDepsUpToDate/P.hs
Expand Down
13 changes: 8 additions & 5 deletions Cabal/Distribution/PackageDescription/Configuration.hs
Original file line number Diff line number Diff line change
Expand Up @@ -421,11 +421,14 @@ overallDependencies enabled (TargetSet targets) = mconcat depss
where
(depss, _) = unzip $ filter (removeDisabledSections . snd) targets
removeDisabledSections :: PDTagged -> Bool
removeDisabledSections (Lib l) = componentEnabled enabled (CLib l)
removeDisabledSections (SubLib _ l) = componentEnabled enabled (CLib l)
removeDisabledSections (Exe _ e) = componentEnabled enabled (CExe e)
removeDisabledSections (Test _ t) = componentEnabled enabled (CTest t)
removeDisabledSections (Bench _ b) = componentEnabled enabled (CBench b)
-- UGH. The embedded componentName in the 'Component's here is
-- BLANK. I don't know whose fault this is but I'll use the tag
-- instead. -- ezyang
removeDisabledSections (Lib _) = componentNameEnabled enabled CLibName
removeDisabledSections (SubLib t _) = componentNameEnabled enabled (CSubLibName t)
removeDisabledSections (Exe t _) = componentNameEnabled enabled (CExeName t)
removeDisabledSections (Test t _) = componentNameEnabled enabled (CTestName t)
removeDisabledSections (Bench t _) = componentNameEnabled enabled (CBenchName t)
removeDisabledSections PDNull = True

-- Apply extra constraints to a dependency map.
Expand Down
2 changes: 0 additions & 2 deletions Cabal/Distribution/Simple.hs
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,6 @@ defaultUserHooks = autoconfUserHooks {
-- https://github.com/haskell/cabal/issues/158
where oldCompatPostConf args flags pkg_descr lbi
= do let verbosity = fromFlag (configVerbosity flags)
noExtraFlags args
confExists <- doesFileExist "configure"
when confExists $
runConfigureScript verbosity
Expand Down Expand Up @@ -610,7 +609,6 @@ autoconfUserHooks
where defaultPostConf :: Args -> ConfigFlags -> PackageDescription -> LocalBuildInfo -> IO ()
defaultPostConf args flags pkg_descr lbi
= do let verbosity = fromFlag (configVerbosity flags)
noExtraFlags args
confExists <- doesFileExist "configure"
if confExists
then runConfigureScript verbosity
Expand Down
5 changes: 5 additions & 0 deletions Cabal/Distribution/Simple/BuildTarget.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
module Distribution.Simple.BuildTarget (
-- * Main interface
readTargetInfos,
readBuildTargets, -- in case you don't have LocalBuildInfo

-- * Build targets
BuildTarget(..),
Expand Down Expand Up @@ -998,3 +999,7 @@ checkBuildTargets verbosity pkg_descr lbi targets = do
formatReason cn DisabledAllBenchmarks =
"Cannot process the " ++ cn ++ " because benchmarks are not "
++ "enabled. Re-run configure with the flag --enable-benchmarks"
formatReason cn (DisabledAllButOne cn') =
"Cannot process the " ++ cn ++ " because this package was "
++ "configured only to build " ++ cn' ++ ". Re-run configure "
++ "with the argument " ++ cn
265 changes: 169 additions & 96 deletions Cabal/Distribution/Simple/Configure.hs

Large diffs are not rendered by default.

30 changes: 8 additions & 22 deletions Cabal/Distribution/Simple/GHC.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1138,20 +1138,17 @@ installLib :: Verbosity
-> Library
-> ComponentLocalBuildInfo
-> IO ()
installLib verbosity lbi targetDir dynlibTargetDir _builtDir pkg lib clbi = do
installLib verbosity lbi targetDir dynlibTargetDir _builtDir _pkg lib clbi = do
-- copy .hi files over:
whenRegistered $ do
whenVanilla $ copyModuleFiles "hi"
whenProf $ copyModuleFiles "p_hi"
whenShared $ copyModuleFiles "dyn_hi"
whenVanilla $ copyModuleFiles "hi"
whenProf $ copyModuleFiles "p_hi"
whenShared $ copyModuleFiles "dyn_hi"

-- copy the built library files over:
whenRegistered $ do
whenVanilla $ installOrdinary builtDir targetDir vanillaLibName
whenProf $ installOrdinary builtDir targetDir profileLibName
whenGHCi $ installOrdinary builtDir targetDir ghciLibName
whenRegisteredOrDynExecutable $ do
whenShared $ installShared builtDir dynlibTargetDir sharedLibName
whenVanilla $ installOrdinary builtDir targetDir vanillaLibName
whenProf $ installOrdinary builtDir targetDir profileLibName
whenGHCi $ installOrdinary builtDir targetDir ghciLibName
whenShared $ installShared builtDir dynlibTargetDir sharedLibName

where
builtDir = componentBuildDir lbi clbi
Expand Down Expand Up @@ -1189,17 +1186,6 @@ installLib verbosity lbi targetDir dynlibTargetDir _builtDir pkg lib clbi = do
whenGHCi = when (hasLib && withGHCiLib lbi)
whenShared = when (hasLib && withSharedLib lbi)

-- Some files (e.g. interface files) are completely unnecessary when
-- we are not actually going to register the library. A library is
-- not registered if there is no "public library", e.g. in the case
-- that we have an internal library and executables, but no public
-- library.
whenRegistered = when (hasPublicLib pkg)

-- However, we must always install dynamic libraries when linking
-- dynamic executables, because we'll try to load them!
whenRegisteredOrDynExecutable = when (hasPublicLib pkg || (hasExes pkg && withDynExe lbi))

-- -----------------------------------------------------------------------------
-- Registering

Expand Down
13 changes: 12 additions & 1 deletion Cabal/Distribution/Simple/InstallDirs.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ module Distribution.Simple.InstallDirs (
InstallDirs(..),
InstallDirTemplates,
defaultInstallDirs,
defaultInstallDirs',
combineInstallDirs,
absoluteInstallDirs,
CopyDest(..),
Expand Down Expand Up @@ -156,7 +157,17 @@ type InstallDirTemplates = InstallDirs PathTemplate
-- Default installation directories

defaultInstallDirs :: CompilerFlavor -> Bool -> Bool -> IO InstallDirTemplates
defaultInstallDirs comp userInstall _hasLibs = do
defaultInstallDirs = defaultInstallDirs' False

defaultInstallDirs' :: Bool {- use external internal deps -}
-> CompilerFlavor -> Bool -> Bool -> IO InstallDirTemplates
defaultInstallDirs' True comp userInstall hasLibs = do
dflt <- defaultInstallDirs' False comp userInstall hasLibs
-- Be a bit more hermetic about per-component installs
return dflt { datasubdir = toPathTemplate $ "$abi" </> "$libname",
docdir = toPathTemplate $ "$datadir" </> "doc" </> "$abi" </> "$libname"
}
defaultInstallDirs' False comp userInstall _hasLibs = do
installPrefix <-
if userInstall
then getAppUserDataDirectory "cabal"
Expand Down
11 changes: 6 additions & 5 deletions Cabal/Distribution/Simple/Register.hs
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,13 @@ import qualified Data.ByteString.Lazy.Char8 as BS.Char8
register :: PackageDescription -> LocalBuildInfo
-> RegisterFlags -- ^Install in the user's database?; verbose
-> IO ()
register pkg_descr lbi flags = when (hasPublicLib pkg_descr) doRegister
register pkg_descr lbi flags =
-- Duncan originally asked for us to not register/install files
-- when there was no public library. But with per-component
-- configure, we legitimately need to install internal libraries
-- so that we can get them. So just unconditionally install.
doRegister
where
-- We do NOT register libraries outside of the inplace database
-- if there is no public library, since no one else can use it
-- usefully (they're not public.) If we start supporting scoped
-- packages, we'll have to relax this.
doRegister = do
targets <- readTargetInfos verbosity pkg_descr lbi (regArgs flags)

Expand Down
6 changes: 6 additions & 0 deletions Cabal/Distribution/Simple/Setup.hs
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ data ConfigFlags = ConfigFlags {
-- frameworks (OS X only)
configExtraIncludeDirs :: [FilePath], -- ^ path to search for header files
configIPID :: Flag String, -- ^ explicit IPID to be used
configCID :: Flag ComponentId, -- ^ explicit CID to be used

configDistPref :: Flag FilePath, -- ^"dist" prefix
configCabalFilePath :: Flag FilePath, -- ^ Cabal file to use
Expand Down Expand Up @@ -677,6 +678,11 @@ configureOptions showOrParseArgs =
configIPID (\v flags -> flags {configIPID = v})
(reqArgFlag "IPID")

,option "" ["cid"]
"Installed component ID to compile this component as"
(fmap display . configCID) (\v flags -> flags {configCID = fmap ComponentId v})
(reqArgFlag "CID")

,option "" ["extra-lib-dirs"]
"A list of directories to search for external libraries"
configExtraLibDirs (\v flags -> flags {configExtraLibDirs = v})
Expand Down
2 changes: 1 addition & 1 deletion Cabal/Distribution/Simple/UserHooks.hs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ emptyUserHooks
readDesc = return Nothing,
hookedPreProcessors = [],
hookedPrograms = [],
preConf = rn,
preConf = rn',
confHook = (\_ _ -> return (error "No local build info generated during configure. Over-ride empty configure hook.")),
postConf = ru,
preBuild = rn',
Expand Down
24 changes: 15 additions & 9 deletions Cabal/Distribution/Types/ComponentEnabledSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module Distribution.Types.ComponentEnabledSpec (

import Prelude ()
import Distribution.Compat.Prelude
import Distribution.Text

import Distribution.Types.Component -- TODO: maybe remove me?
import Distribution.Types.ComponentName
Expand Down Expand Up @@ -50,10 +51,9 @@ import Distribution.Types.ComponentName
--
-- @since 2.0.0.0
data ComponentEnabledSpec
= ComponentEnabledSpec {
testsEnabled :: Bool,
benchmarksEnabled :: Bool
}
= ComponentEnabledSpec { testsEnabled :: Bool,
benchmarksEnabled :: Bool }
| OneComponentEnabledSpec ComponentName
deriving (Generic, Read, Show)
instance Binary ComponentEnabledSpec

Expand Down Expand Up @@ -91,15 +91,21 @@ componentDisabledReason enabled comp
-- @since 2.0.0.0
componentNameDisabledReason :: ComponentEnabledSpec -> ComponentName
-> Maybe ComponentDisabledReason
componentNameDisabledReason enabled (CTestName _)
| not (testsEnabled enabled) = Just DisabledAllTests
componentNameDisabledReason enabled (CBenchName _)
| not (benchmarksEnabled enabled) = Just DisabledAllBenchmarks
componentNameDisabledReason _ _ = Nothing
componentNameDisabledReason
ComponentEnabledSpec{ testsEnabled = False } (CTestName _)
= Just DisabledAllTests
componentNameDisabledReason
ComponentEnabledSpec{ benchmarksEnabled = False } (CBenchName _)
= Just DisabledAllBenchmarks
componentNameDisabledReason ComponentEnabledSpec{} _ = Nothing
componentNameDisabledReason (OneComponentEnabledSpec cname) c
| c == cname = Nothing
| otherwise = Just (DisabledAllButOne (display cname))

-- | A reason explaining why a component is disabled.
--
-- @since 2.0.0.0
data ComponentDisabledReason = DisabledComponent
| DisabledAllTests
| DisabledAllBenchmarks
| DisabledAllButOne String
4 changes: 4 additions & 0 deletions Cabal/changelog
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@
* New './Setup configure' flag '--cabal-file', allowing multiple
.cabal files in a single directory (#3553). Primarily intended for
internal use.
* './Setup configure' now accepts a single argument specifying
the component to be configured. The semantics of this mode
of operation are described in
<https://github.com/ghc-proposals/ghc-proposals/pull/4>

1.24.0.0 Ryan Thomas <[email protected]> March 2016
* Support GHC 8.
Expand Down
54 changes: 54 additions & 0 deletions Cabal/doc/installing-packages.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,35 @@ is passed the `--with-hc-pkg`, `--prefix`, `--bindir`, `--libdir`,
value of the `--with-compiler` option is passed in a `--with-hc` option
and all options specified with `--configure-option=` are passed on.

In Cabal 2.0, support for a single positional argument was added to `setup configure`
This makes Cabal configure a the specific component to be
configured. Specified names can be qualified with `lib:` or
`exe:` in case just a name is ambiguous (as would be the case
for a package named `p` which has a library and an executable
named `p`.) This has the following effects:

* Subsequent invocations of `build`, `register`, etc. operate only
on the configured component.

* Cabal requires all "internal" dependencies (e.g., an executable
depending on a library defined in the same package) must be
found in the set of databases via `--package-db` (and related flags):
these dependencies are assumed to be up-to-date. A dependency can
be explicitly specified using `--dependency` simply by giving
the name of the internal library; e.g., the dependency for an
internal library named `foo` is given as `--dependency=pkg-internal=pkg-1.0-internal-abcd`.

* Only the dependencies needed for the requested component are
required. Similarly, when `--exact-configuration` is specified,
it's only necessary to specify `--dependency` for the component.
(As mentioned previously, you *must* specify internal dependencies
as well.)

* Internal `build-tools` dependencies are expected to be in the `PATH`
upon subsequent invocations of `setup`.

Full details can be found in the [Componentized Cabal proposal](https://github.com/ezyang/ghc-proposals/blob/master/proposals/0000-componentized-cabal.rst).

### Programs used for building ###

The following options govern the programs used to process the source
Expand Down Expand Up @@ -753,6 +782,19 @@ be controlled with the following command line options.

To reset the stack, use `--package-db=clear`.

`--ipid=`_ipid_
: Specifies the _installed package identifier_ of the package to be
built; this identifier is passed on to GHC and serves as the basis
for linker symbols and the `id` field in a `ghc-pkg` registration.
When a package has multiple components, the actual component
identifiers are derived off of this identifier (e.g., an
internal library `foo` from package `p-0.1-abcd` will get the
identifier `p-0.1-abcd-foo`.

`--cid=`_cid_
: Specifies the _component identifier_ of the component being built;
this is only valid if you are configuring a single component.

`--default-user-config=` _file_
: Allows a "default" `cabal.config` freeze file to be passed in
manually. This file will only be used if one does not exist in the
Expand Down Expand Up @@ -954,6 +996,18 @@ be controlled with the following command line options.
for libraries it is also saved in the package registration
information and used when compiling modules that use the library.

`--dependency`[=_pkgname_=_ipid_]
: Specify that a particular dependency should used for a particular
package name. In particular, it declares that any reference to
_pkgname_ in a `build-depends` should be resolved to _ipid_.

`--exact-configuration`
: This changes Cabal to require every dependency be explicitly
specified using `--dependency`, rather than use Cabal's
(very simple) dependency solver. This is useful for programmatic
use of Cabal's API, where you want to error if you didn't
specify enough `--dependency` flags.

`--allow-newer`[=_pkgs_], `--allow-older`[=_pkgs_]
: Selectively relax upper or lower bounds in dependencies without
editing the package description respectively.
Expand Down
4 changes: 4 additions & 0 deletions Cabal/tests/PackageTests/ConfigureComponent/Exe/Bad.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Main where

main :: IO ()
main = putStrLn "Hello, Haskell!"
18 changes: 18 additions & 0 deletions Cabal/tests/PackageTests/ConfigureComponent/Exe/Exe.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Exe
version: 0.1.0.0
license: BSD3
author: Edward Z. Yang
maintainer: [email protected]
build-type: Simple
cabal-version: >=1.10

executable goodexe
main-is: Good.hs
build-depends: base
default-language: Haskell2010

-- We deliberately don't configure badexe, so that we can build ONLY goodexe
executable badexe
main-is: Bad.hs
build-depends: totally-impossible-dependency-to-fill == 10000.25.6
default-language: Haskell2010
4 changes: 4 additions & 0 deletions Cabal/tests/PackageTests/ConfigureComponent/Exe/Good.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module Main where

main :: IO ()
main = putStrLn "OK"
18 changes: 18 additions & 0 deletions Cabal/tests/PackageTests/ConfigureComponent/SubLib/Lib.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Lib
version: 0.1.0.0
license: BSD3
author: Edward Z. Yang
maintainer: [email protected]
build-type: Simple
cabal-version: >=1.10

library sublib
build-depends: base
exposed-modules: Lib
default-language: Haskell2010

executable exe
main-is: Exe.hs
build-depends: base, sublib
hs-source-dirs: exe
default-language: Haskell2010
2 changes: 2 additions & 0 deletions Cabal/tests/PackageTests/ConfigureComponent/SubLib/Lib.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module Lib where
lib = "OK"
2 changes: 2 additions & 0 deletions Cabal/tests/PackageTests/ConfigureComponent/SubLib/exe/Exe.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import Lib
main = putStrLn lib
2 changes: 2 additions & 0 deletions Cabal/tests/PackageTests/ConfigureComponent/Test/Lib.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module Lib where
lib = "OK"
Loading

0 comments on commit 9441c52

Please sign in to comment.