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

One-component configure, fixes #2802.

Described in: https://github.com/ghc-proposals/ghc-proposals/pull/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: default avatarEdward Z. Yang <ezyang@cs.stanford.edu>
parent a06460c3
...@@ -108,6 +108,17 @@ extra-source-files: ...@@ -108,6 +108,17 @@ extra-source-files:
tests/PackageTests/Configure/include/HsZlibConfig.h.in tests/PackageTests/Configure/include/HsZlibConfig.h.in
tests/PackageTests/Configure/zlib.buildinfo.in tests/PackageTests/Configure/zlib.buildinfo.in
tests/PackageTests/Configure/zlib.cabal 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/CopyAssumeDepsUpToDate.cabal
tests/PackageTests/CopyAssumeDepsUpToDate/Main.hs tests/PackageTests/CopyAssumeDepsUpToDate/Main.hs
tests/PackageTests/CopyAssumeDepsUpToDate/P.hs tests/PackageTests/CopyAssumeDepsUpToDate/P.hs
......
...@@ -421,11 +421,14 @@ overallDependencies enabled (TargetSet targets) = mconcat depss ...@@ -421,11 +421,14 @@ overallDependencies enabled (TargetSet targets) = mconcat depss
where where
(depss, _) = unzip $ filter (removeDisabledSections . snd) targets (depss, _) = unzip $ filter (removeDisabledSections . snd) targets
removeDisabledSections :: PDTagged -> Bool removeDisabledSections :: PDTagged -> Bool
removeDisabledSections (Lib l) = componentEnabled enabled (CLib l) -- UGH. The embedded componentName in the 'Component's here is
removeDisabledSections (SubLib _ l) = componentEnabled enabled (CLib l) -- BLANK. I don't know whose fault this is but I'll use the tag
removeDisabledSections (Exe _ e) = componentEnabled enabled (CExe e) -- instead. -- ezyang
removeDisabledSections (Test _ t) = componentEnabled enabled (CTest t) removeDisabledSections (Lib _) = componentNameEnabled enabled CLibName
removeDisabledSections (Bench _ b) = componentEnabled enabled (CBench b) 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 removeDisabledSections PDNull = True
-- Apply extra constraints to a dependency map. -- Apply extra constraints to a dependency map.
......
...@@ -579,7 +579,6 @@ defaultUserHooks = autoconfUserHooks { ...@@ -579,7 +579,6 @@ defaultUserHooks = autoconfUserHooks {
-- https://github.com/haskell/cabal/issues/158 -- https://github.com/haskell/cabal/issues/158
where oldCompatPostConf args flags pkg_descr lbi where oldCompatPostConf args flags pkg_descr lbi
= do let verbosity = fromFlag (configVerbosity flags) = do let verbosity = fromFlag (configVerbosity flags)
noExtraFlags args
confExists <- doesFileExist "configure" confExists <- doesFileExist "configure"
when confExists $ when confExists $
runConfigureScript verbosity runConfigureScript verbosity
...@@ -610,7 +609,6 @@ autoconfUserHooks ...@@ -610,7 +609,6 @@ autoconfUserHooks
where defaultPostConf :: Args -> ConfigFlags -> PackageDescription -> LocalBuildInfo -> IO () where defaultPostConf :: Args -> ConfigFlags -> PackageDescription -> LocalBuildInfo -> IO ()
defaultPostConf args flags pkg_descr lbi defaultPostConf args flags pkg_descr lbi
= do let verbosity = fromFlag (configVerbosity flags) = do let verbosity = fromFlag (configVerbosity flags)
noExtraFlags args
confExists <- doesFileExist "configure" confExists <- doesFileExist "configure"
if confExists if confExists
then runConfigureScript verbosity then runConfigureScript verbosity
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
module Distribution.Simple.BuildTarget ( module Distribution.Simple.BuildTarget (
-- * Main interface -- * Main interface
readTargetInfos, readTargetInfos,
readBuildTargets, -- in case you don't have LocalBuildInfo
-- * Build targets -- * Build targets
BuildTarget(..), BuildTarget(..),
...@@ -998,3 +999,7 @@ checkBuildTargets verbosity pkg_descr lbi targets = do ...@@ -998,3 +999,7 @@ checkBuildTargets verbosity pkg_descr lbi targets = do
formatReason cn DisabledAllBenchmarks = formatReason cn DisabledAllBenchmarks =
"Cannot process the " ++ cn ++ " because benchmarks are not " "Cannot process the " ++ cn ++ " because benchmarks are not "
++ "enabled. Re-run configure with the flag --enable-benchmarks" ++ "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,20 +1138,17 @@ installLib :: Verbosity ...@@ -1138,20 +1138,17 @@ installLib :: Verbosity
-> Library -> Library
-> ComponentLocalBuildInfo -> ComponentLocalBuildInfo
-> IO () -> 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: -- copy .hi files over:
whenRegistered $ do whenVanilla $ copyModuleFiles "hi"
whenVanilla $ copyModuleFiles "hi" whenProf $ copyModuleFiles "p_hi"
whenProf $ copyModuleFiles "p_hi" whenShared $ copyModuleFiles "dyn_hi"
whenShared $ copyModuleFiles "dyn_hi"
-- copy the built library files over: -- copy the built library files over:
whenRegistered $ do whenVanilla $ installOrdinary builtDir targetDir vanillaLibName
whenVanilla $ installOrdinary builtDir targetDir vanillaLibName whenProf $ installOrdinary builtDir targetDir profileLibName
whenProf $ installOrdinary builtDir targetDir profileLibName whenGHCi $ installOrdinary builtDir targetDir ghciLibName
whenGHCi $ installOrdinary builtDir targetDir ghciLibName whenShared $ installShared builtDir dynlibTargetDir sharedLibName
whenRegisteredOrDynExecutable $ do
whenShared $ installShared builtDir dynlibTargetDir sharedLibName
where where
builtDir = componentBuildDir lbi clbi builtDir = componentBuildDir lbi clbi
...@@ -1189,17 +1186,6 @@ installLib verbosity lbi targetDir dynlibTargetDir _builtDir pkg lib clbi = do ...@@ -1189,17 +1186,6 @@ installLib verbosity lbi targetDir dynlibTargetDir _builtDir pkg lib clbi = do
whenGHCi = when (hasLib && withGHCiLib lbi) whenGHCi = when (hasLib && withGHCiLib lbi)
whenShared = when (hasLib && withSharedLib 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 -- Registering
......
...@@ -25,6 +25,7 @@ module Distribution.Simple.InstallDirs ( ...@@ -25,6 +25,7 @@ module Distribution.Simple.InstallDirs (
InstallDirs(..), InstallDirs(..),
InstallDirTemplates, InstallDirTemplates,
defaultInstallDirs, defaultInstallDirs,
defaultInstallDirs',
combineInstallDirs, combineInstallDirs,
absoluteInstallDirs, absoluteInstallDirs,
CopyDest(..), CopyDest(..),
...@@ -156,7 +157,17 @@ type InstallDirTemplates = InstallDirs PathTemplate ...@@ -156,7 +157,17 @@ type InstallDirTemplates = InstallDirs PathTemplate
-- Default installation directories -- Default installation directories
defaultInstallDirs :: CompilerFlavor -> Bool -> Bool -> IO InstallDirTemplates 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 <- installPrefix <-
if userInstall if userInstall
then getAppUserDataDirectory "cabal" then getAppUserDataDirectory "cabal"
......
...@@ -88,12 +88,13 @@ import qualified Data.ByteString.Lazy.Char8 as BS.Char8 ...@@ -88,12 +88,13 @@ import qualified Data.ByteString.Lazy.Char8 as BS.Char8
register :: PackageDescription -> LocalBuildInfo register :: PackageDescription -> LocalBuildInfo
-> RegisterFlags -- ^Install in the user's database?; verbose -> RegisterFlags -- ^Install in the user's database?; verbose
-> IO () -> 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 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 doRegister = do
targets <- readTargetInfos verbosity pkg_descr lbi (regArgs flags) targets <- readTargetInfos verbosity pkg_descr lbi (regArgs flags)
......
...@@ -391,6 +391,7 @@ data ConfigFlags = ConfigFlags { ...@@ -391,6 +391,7 @@ data ConfigFlags = ConfigFlags {
-- frameworks (OS X only) -- frameworks (OS X only)
configExtraIncludeDirs :: [FilePath], -- ^ path to search for header files configExtraIncludeDirs :: [FilePath], -- ^ path to search for header files
configIPID :: Flag String, -- ^ explicit IPID to be used configIPID :: Flag String, -- ^ explicit IPID to be used
configCID :: Flag ComponentId, -- ^ explicit CID to be used
configDistPref :: Flag FilePath, -- ^"dist" prefix configDistPref :: Flag FilePath, -- ^"dist" prefix
configCabalFilePath :: Flag FilePath, -- ^ Cabal file to use configCabalFilePath :: Flag FilePath, -- ^ Cabal file to use
...@@ -677,6 +678,11 @@ configureOptions showOrParseArgs = ...@@ -677,6 +678,11 @@ configureOptions showOrParseArgs =
configIPID (\v flags -> flags {configIPID = v}) configIPID (\v flags -> flags {configIPID = v})
(reqArgFlag "IPID") (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"] ,option "" ["extra-lib-dirs"]
"A list of directories to search for external libraries" "A list of directories to search for external libraries"
configExtraLibDirs (\v flags -> flags {configExtraLibDirs = v}) configExtraLibDirs (\v flags -> flags {configExtraLibDirs = v})
......
...@@ -164,7 +164,7 @@ emptyUserHooks ...@@ -164,7 +164,7 @@ emptyUserHooks
readDesc = return Nothing, readDesc = return Nothing,
hookedPreProcessors = [], hookedPreProcessors = [],
hookedPrograms = [], hookedPrograms = [],
preConf = rn, preConf = rn',
confHook = (\_ _ -> return (error "No local build info generated during configure. Over-ride empty configure hook.")), confHook = (\_ _ -> return (error "No local build info generated during configure. Over-ride empty configure hook.")),
postConf = ru, postConf = ru,
preBuild = rn', preBuild = rn',
......
...@@ -15,6 +15,7 @@ module Distribution.Types.ComponentEnabledSpec ( ...@@ -15,6 +15,7 @@ module Distribution.Types.ComponentEnabledSpec (
import Prelude () import Prelude ()
import Distribution.Compat.Prelude import Distribution.Compat.Prelude
import Distribution.Text
import Distribution.Types.Component -- TODO: maybe remove me? import Distribution.Types.Component -- TODO: maybe remove me?
import Distribution.Types.ComponentName import Distribution.Types.ComponentName
...@@ -50,10 +51,9 @@ import Distribution.Types.ComponentName ...@@ -50,10 +51,9 @@ import Distribution.Types.ComponentName
-- --
-- @since 2.0.0.0 -- @since 2.0.0.0
data ComponentEnabledSpec data ComponentEnabledSpec
= ComponentEnabledSpec { = ComponentEnabledSpec { testsEnabled :: Bool,
testsEnabled :: Bool, benchmarksEnabled :: Bool }
benchmarksEnabled :: Bool | OneComponentEnabledSpec ComponentName
}
deriving (Generic, Read, Show) deriving (Generic, Read, Show)
instance Binary ComponentEnabledSpec instance Binary ComponentEnabledSpec
...@@ -91,11 +91,16 @@ componentDisabledReason enabled comp ...@@ -91,11 +91,16 @@ componentDisabledReason enabled comp
-- @since 2.0.0.0 -- @since 2.0.0.0
componentNameDisabledReason :: ComponentEnabledSpec -> ComponentName componentNameDisabledReason :: ComponentEnabledSpec -> ComponentName
-> Maybe ComponentDisabledReason -> Maybe ComponentDisabledReason
componentNameDisabledReason enabled (CTestName _) componentNameDisabledReason
| not (testsEnabled enabled) = Just DisabledAllTests ComponentEnabledSpec{ testsEnabled = False } (CTestName _)
componentNameDisabledReason enabled (CBenchName _) = Just DisabledAllTests
| not (benchmarksEnabled enabled) = Just DisabledAllBenchmarks componentNameDisabledReason
componentNameDisabledReason _ _ = Nothing 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. -- | A reason explaining why a component is disabled.
-- --
...@@ -103,3 +108,4 @@ componentNameDisabledReason _ _ = Nothing ...@@ -103,3 +108,4 @@ componentNameDisabledReason _ _ = Nothing
data ComponentDisabledReason = DisabledComponent data ComponentDisabledReason = DisabledComponent
| DisabledAllTests | DisabledAllTests
| DisabledAllBenchmarks | DisabledAllBenchmarks
| DisabledAllButOne String
...@@ -66,6 +66,10 @@ ...@@ -66,6 +66,10 @@
internal use. internal use.
* Macros in 'cabal_macros.h' are now ifndef'd, so that they * Macros in 'cabal_macros.h' are now ifndef'd, so that they
don't cause an error if the macro is already defined. (#3041) 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
<https://github.com/ghc-proposals/ghc-proposals/pull/4>
1.24.0.0 Ryan Thomas <ryan@ryant.org> March 2016 1.24.0.0 Ryan Thomas <ryan@ryant.org> March 2016
* Support GHC 8. * Support GHC 8.
......
...@@ -410,6 +410,35 @@ is passed the `--with-hc-pkg`, `--prefix`, `--bindir`, `--libdir`, ...@@ -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 value of the `--with-compiler` option is passed in a `--with-hc` option
and all options specified with `--configure-option=` are passed on. 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 ### ### Programs used for building ###
The following options govern the programs used to process the source The following options govern the programs used to process the source
...@@ -753,6 +782,19 @@ be controlled with the following command line options. ...@@ -753,6 +782,19 @@ be controlled with the following command line options.
To reset the stack, use `--package-db=clear`. 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_ `--default-user-config=` _file_
: Allows a "default" `cabal.config` freeze file to be passed in : 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 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. ...@@ -954,6 +996,18 @@ be controlled with the following command line options.
for libraries it is also saved in the package registration for libraries it is also saved in the package registration
information and used when compiling modules that use the library. 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_] `--allow-newer`[=_pkgs_], `--allow-older`[=_pkgs_]
: Selectively relax upper or lower bounds in dependencies without : Selectively relax upper or lower bounds in dependencies without
editing the package description respectively. editing the package description respectively.
......
module Main where
main :: IO ()
main = putStrLn "Hello, Haskell!"
name: Exe
version: 0.1.0.0
license: BSD3
author: Edward Z. Yang
maintainer: ezyang@cs.stanford.edu
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
version: 0.1.0.0
license: BSD3
author: Edward Z. Yang
maintainer: ezyang@cs.stanford.edu
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
Markdown is supported
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