diff --git a/Cabal/doc/nix-local-build.rst b/Cabal/doc/nix-local-build.rst index cf94b1898b1..e6d0b7b2132 100644 --- a/Cabal/doc/nix-local-build.rst +++ b/Cabal/doc/nix-local-build.rst @@ -861,7 +861,7 @@ The following settings control the behavior of the dependency solver: Package configuration options ----------------------------- -Package options affect the building of specific packages. There are two +Package options affect the building of specific packages. There are three ways a package option can be specified: - They can be specified at the top-level, in which case they apply only @@ -871,6 +871,11 @@ ways a package option can be specified: apply to the build of the package, whether or not it is local or external. +- They can be specified inside an ``all-packages`` stanza, in which case they + apply to all packages, local ones from the project and also external + dependencies. + + For example, the following options specify that :cfg-field:`optimization` should be turned off for all local packages, and that ``bytestring`` (possibly an external dependency) should be built with ``-fno-state-hack``:: diff --git a/cabal-install/Distribution/Client/ProjectConfig/Legacy.hs b/cabal-install/Distribution/Client/ProjectConfig/Legacy.hs index 8893dccf90a..b4f2af997db 100644 --- a/cabal-install/Distribution/Client/ProjectConfig/Legacy.hs +++ b/cabal-install/Distribution/Client/ProjectConfig/Legacy.hs @@ -102,6 +102,7 @@ data LegacyProjectConfig = LegacyProjectConfig { legacyPackagesNamed :: [Dependency], legacySharedConfig :: LegacySharedConfig, + legacyAllConfig :: LegacyPackageConfig, legacyLocalConfig :: LegacyPackageConfig, legacySpecificConfig :: MapMappend PackageName LegacyPackageConfig } deriving Generic @@ -226,6 +227,7 @@ convertLegacyProjectConfig legacyPackagesNamed, legacySharedConfig = LegacySharedConfig globalFlags configShFlags configExFlags installSharedFlags, + legacyAllConfig, legacyLocalConfig = LegacyPackageConfig configFlags installPerPkgFlags haddockFlags, legacySpecificConfig @@ -238,15 +240,18 @@ convertLegacyProjectConfig projectPackagesNamed = legacyPackagesNamed, projectConfigBuildOnly = configBuildOnly, - projectConfigShared = configAllPackages, + projectConfigShared = configPackagesShared, projectConfigProvenance = mempty, + projectConfigAllPackages = configAllPackages, projectConfigLocalPackages = configLocalPackages, projectConfigSpecificPackage = fmap perPackage legacySpecificConfig } where + configAllPackages = convertLegacyPerPackageFlags g i h + where LegacyPackageConfig g i h = legacyAllConfig configLocalPackages = convertLegacyPerPackageFlags configFlags installPerPkgFlags haddockFlags - configAllPackages = convertLegacyAllPackageFlags + configPackagesShared= convertLegacyAllPackageFlags globalFlags (configFlags <> configShFlags) configExFlags installSharedFlags configBuildOnly = convertLegacyBuildOnlyFlags @@ -436,6 +441,7 @@ convertToLegacyProjectConfig projectPackagesOptional, projectPackagesRepo, projectPackagesNamed, + projectConfigAllPackages, projectConfigLocalPackages, projectConfigSpecificPackage } = @@ -445,6 +451,8 @@ convertToLegacyProjectConfig legacyPackagesRepo = projectPackagesRepo, legacyPackagesNamed = projectPackagesNamed, legacySharedConfig = convertToLegacySharedConfig projectConfig, + legacyAllConfig = convertToLegacyPerPackageConfig + projectConfigAllPackages, legacyLocalConfig = convertToLegacyAllPackageConfig projectConfig <> convertToLegacyPerPackageConfig projectConfigLocalPackages, @@ -1030,6 +1038,7 @@ legacyPackageConfigFieldDescrs = legacyPackageConfigSectionDescrs :: [SectionDescr LegacyProjectConfig] legacyPackageConfigSectionDescrs = [ packageRepoSectionDescr + , allPackagesOptionsSectionDescr , packageSpecificOptionsSectionDescr , liftSection legacyLocalConfig @@ -1074,26 +1083,58 @@ packageRepoSectionDescr = } } +-- | The definitions of all the fields that can appear in the @package pkgfoo@ +-- and @all-packages@ sections of the @cabal.project@-format files. +-- +packageSpecificOptionsFieldDescrs :: [FieldDescr LegacyPackageConfig] +packageSpecificOptionsFieldDescrs = + legacyPackageConfigFieldDescrs + ++ programOptionsFieldDescrs + (configProgramArgs . legacyConfigureFlags) + (\args pkgconf -> pkgconf { + legacyConfigureFlags = (legacyConfigureFlags pkgconf) { + configProgramArgs = args + } + } + ) + ++ liftFields + legacyConfigureFlags + (\flags pkgconf -> pkgconf { + legacyConfigureFlags = flags + } + ) + programLocationsFieldDescrs + +-- | The definition of the @all-packages@ sections of the +-- @cabal.project@-format files. This is the one that applies to all packages +-- used anywhere by the project, locally or as dependencies. +-- +allPackagesOptionsSectionDescr :: SectionDescr LegacyProjectConfig +allPackagesOptionsSectionDescr = + SectionDescr { + sectionName = "all-packages", + sectionFields = packageSpecificOptionsFieldDescrs, + sectionSubsections = [], + sectionGet = (\x->[("", x)]) + . legacyAllConfig, + sectionSet = + \lineno unused pkgsconf projconf -> do + unless (null unused) $ + syntaxError lineno "the section 'all-packages' takes no arguments" + return projconf { + legacyAllConfig = legacyAllConfig projconf <> pkgsconf + }, + sectionEmpty = mempty + } + +-- | The definition of the @package pkgfoo@ sections of the @cabal.project@-format +-- files. This section is per-package name. +-- packageSpecificOptionsSectionDescr :: SectionDescr LegacyProjectConfig packageSpecificOptionsSectionDescr = SectionDescr { sectionName = "package", - sectionFields = legacyPackageConfigFieldDescrs - ++ programOptionsFieldDescrs - (configProgramArgs . legacyConfigureFlags) - (\args pkgconf -> pkgconf { - legacyConfigureFlags = (legacyConfigureFlags pkgconf) { - configProgramArgs = args - } - } - ) - ++ liftFields - legacyConfigureFlags - (\flags pkgconf -> pkgconf { - legacyConfigureFlags = flags - } - ) - programLocationsFieldDescrs, + sectionFields = packageSpecificOptionsFieldDescrs, sectionSubsections = [], sectionGet = \projconf -> [ (display pkgname, pkgconf) diff --git a/cabal-install/Distribution/Client/ProjectConfig/Types.hs b/cabal-install/Distribution/Client/ProjectConfig/Types.hs index ec125ac03bc..73353f636c0 100644 --- a/cabal-install/Distribution/Client/ProjectConfig/Types.hs +++ b/cabal-install/Distribution/Client/ProjectConfig/Types.hs @@ -113,6 +113,10 @@ data ProjectConfig projectConfigShared :: ProjectConfigShared, projectConfigProvenance :: Set ProjectConfigProvenance, + -- | Configuration to be applied to *all* packages, + -- whether named in `cabal.project` or not. + projectConfigAllPackages :: PackageConfig, + -- | Configuration to be applied to *local* packages; i.e., -- any packages which are explicitly named in `cabal.project`. projectConfigLocalPackages :: PackageConfig, diff --git a/cabal-install/Distribution/Client/ProjectPlanning.hs b/cabal-install/Distribution/Client/ProjectPlanning.hs index 8e7020bcd05..c49bb114bee 100644 --- a/cabal-install/Distribution/Client/ProjectPlanning.hs +++ b/cabal-install/Distribution/Client/ProjectPlanning.hs @@ -590,6 +590,7 @@ rebuildInstallPlan verbosity , ElaboratedSharedConfig ) phaseElaboratePlan ProjectConfig { projectConfigShared, + projectConfigAllPackages, projectConfigLocalPackages, projectConfigSpecificPackage, projectConfigBuildOnly @@ -617,6 +618,7 @@ rebuildInstallPlan verbosity sourcePackageHashes defaultInstallDirs projectConfigShared + projectConfigAllPackages projectConfigLocalPackages (getMapMappend projectConfigSpecificPackage) let instantiatedPlan = instantiateInstallPlan elaboratedPlan @@ -1142,6 +1144,7 @@ elaborateInstallPlan -> InstallDirs.InstallDirTemplates -> ProjectConfigShared -> PackageConfig + -> PackageConfig -> Map PackageName PackageConfig -> LogProgress (ElaboratedInstallPlan, ElaboratedSharedConfig) elaborateInstallPlan verbosity platform compiler compilerprogdb pkgConfigDB @@ -1151,6 +1154,7 @@ elaborateInstallPlan verbosity platform compiler compilerprogdb pkgConfigDB sourcePackageHashes defaultInstallDirs sharedPackageConfig + allPackagesConfig localPackagesConfig perPackageConfig = do x <- elaboratedInstallPlan @@ -1758,14 +1762,17 @@ elaborateInstallPlan verbosity platform compiler compilerprogdb pkgConfigDB lookupPerPkgOption :: (Package pkg, Monoid m) => pkg -> (PackageConfig -> m) -> m - lookupPerPkgOption pkg f - -- the project config specifies values that apply to packages local to - -- but by default non-local packages get all default config values - -- the project, and can specify per-package values for any package, - | isLocalToProject pkg = local `mappend` perpkg - | otherwise = perpkg + lookupPerPkgOption pkg f = + -- This is where we merge the options from the project config that + -- apply to all packages, all project local packages, and to specific + -- named packages + global `mappend` local `mappend` perpkg where - local = f localPackagesConfig + global = f allPackagesConfig + local | isLocalToProject pkg + = f localPackagesConfig + | otherwise + = mempty perpkg = maybe mempty f (Map.lookup (packageName pkg) perPackageConfig) inplacePackageDbs = storePackageDbs diff --git a/cabal-install/changelog b/cabal-install/changelog index 1f6347261d9..a015ecfd66a 100644 --- a/cabal-install/changelog +++ b/cabal-install/changelog @@ -53,6 +53,8 @@ line, the last one is now preferred, so e.g. '-f+dev -f-dev' is now equivalent to '-f-dev' (#4452). * Removed support for building cabal-install with GHC < 7.10 (#4870). + * New 'all-packages' section in 'cabal.project' files that applies + options to all packages, not just those local to the project. 2.0.0.1 Mikhail Glushenkov December 2017 * Support for GHC's numeric -g debug levels (#4673). diff --git a/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs b/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs index 23c76e27742..ec5ddabdcf9 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs @@ -284,6 +284,7 @@ instance Arbitrary ProjectConfig where <*> arbitrary <*> arbitrary <*> arbitrary + <*> arbitrary <*> (MapMappend . fmap getNonMEmpty . Map.fromList <$> shortListOf 3 arbitrary) -- package entries with no content are equivalent to @@ -297,7 +298,8 @@ instance Arbitrary ProjectConfig where , projectConfigShared = x5 , projectConfigProvenance = x6 , projectConfigLocalPackages = x7 - , projectConfigSpecificPackage = x8 } = + , projectConfigSpecificPackage = x8 + , projectConfigAllPackages = x9 } = [ ProjectConfig { projectPackages = x0' , projectPackagesOptional = x1' , projectPackagesRepo = x2' @@ -307,10 +309,11 @@ instance Arbitrary ProjectConfig where , projectConfigProvenance = x6' , projectConfigLocalPackages = x7' , projectConfigSpecificPackage = (MapMappend - (fmap getNonMEmpty x8')) } - | ((x0', x1', x2', x3'), (x4', x5', x6', x7', x8')) + (fmap getNonMEmpty x8')) + , projectConfigAllPackages = x9' } + | ((x0', x1', x2', x3'), (x4', x5', x6', x7', x8', x9')) <- shrink ((x0, x1, x2, x3), - (x4, x5, x6, x7, fmap NonMEmpty (getMapMappend x8))) + (x4, x5, x6, x7, fmap NonMEmpty (getMapMappend x8), x9)) ] newtype PackageLocationString