Commit a090a494 authored by Edward Z. Yang's avatar Edward Z. Yang
Browse files

One-component configure, fixes #2802.

Described in:

./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: default avatarEdward Z. Yang <>
parent a06460c3
......@@ -108,6 +108,17 @@ extra-source-files:
......@@ -421,11 +421,14 @@ overallDependencies enabled (TargetSet targets) = mconcat depss
(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.
......@@ -579,7 +579,6 @@ defaultUserHooks = autoconfUserHooks {
where oldCompatPostConf args flags pkg_descr lbi
= do let verbosity = fromFlag (configVerbosity flags)
noExtraFlags args
confExists <- doesFileExist "configure"
when confExists $
runConfigureScript verbosity
......@@ -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
......@@ -12,6 +12,7 @@
module Distribution.Simple.BuildTarget (
-- * Main interface
readBuildTargets, -- in case you don't have LocalBuildInfo
-- * Build targets
......@@ -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
This diff is collapsed.
......@@ -1138,19 +1138,16 @@ 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"
-- 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
......@@ -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
......@@ -25,6 +25,7 @@ module Distribution.Simple.InstallDirs (
......@@ -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"
......@@ -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.
-- 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)
......@@ -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
......@@ -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})
......@@ -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',
......@@ -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
......@@ -50,10 +51,9 @@ import Distribution.Types.ComponentName
-- @since
data ComponentEnabledSpec
= ComponentEnabledSpec {
testsEnabled :: Bool,
benchmarksEnabled :: Bool
= ComponentEnabledSpec { testsEnabled :: Bool,
benchmarksEnabled :: Bool }
| OneComponentEnabledSpec ComponentName
deriving (Generic, Read, Show)
instance Binary ComponentEnabledSpec
......@@ -91,11 +91,16 @@ componentDisabledReason enabled comp
-- @since
componentNameDisabledReason :: ComponentEnabledSpec -> ComponentName
-> Maybe ComponentDisabledReason
componentNameDisabledReason enabled (CTestName _)
| not (testsEnabled enabled) = Just DisabledAllTests
componentNameDisabledReason enabled (CBenchName _)
| not (benchmarksEnabled enabled) = Just DisabledAllBenchmarks
componentNameDisabledReason _ _ = Nothing
ComponentEnabledSpec{ testsEnabled = False } (CTestName _)
= Just DisabledAllTests
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.
......@@ -103,3 +108,4 @@ componentNameDisabledReason _ _ = Nothing
data ComponentDisabledReason = DisabledComponent
| DisabledAllTests
| DisabledAllBenchmarks
| DisabledAllButOne String
......@@ -66,6 +66,10 @@
internal use.
* Macros in 'cabal_macros.h' are now ifndef'd, so that they
don't cause an error if the macro is already defined. (#3041)
* './Setup configure' now accepts a single argument specifying
the component to be configured. The semantics of this mode
of operation are described in
<> Ryan Thomas <> March 2016
* Support GHC 8.
......@@ -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](
### Programs used for building ###
The following options govern the programs used to process the source
......@@ -753,6 +782,19 @@ be controlled with the following command line options.
To reset the stack, use `--package-db=clear`.
: 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`.
: 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
......@@ -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.
: 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_.
: 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.
module Main where
main :: IO ()
main = putStrLn "Hello, Haskell!"
name: Exe
license: BSD3
author: Edward Z. Yang
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
module Main where
main :: IO ()
main = putStrLn "OK"
name: Lib
license: BSD3
author: Edward Z. Yang
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
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment