diff --git a/Cabal/Distribution/PackageDescription/Check.hs b/Cabal/Distribution/PackageDescription/Check.hs index c53fa1ad057..e724e212cb1 100644 --- a/Cabal/Distribution/PackageDescription/Check.hs +++ b/Cabal/Distribution/PackageDescription/Check.hs @@ -1030,6 +1030,7 @@ checkPaths pkg = ++ [ (path, "license-file") | path <- licenseFiles pkg ] ++ concat [ [ (path, "c-sources") | path <- cSources bi ] + ++ [ (path, "cxx-sources") | path <- cxxSources bi ] ++ [ (path, "js-sources") | path <- jsSources bi ] ++ [ (path, "install-includes") | path <- installIncludes bi ] ++ [ (path, "hs-source-dirs") | path <- hsSourceDirs bi ] diff --git a/Cabal/Distribution/PackageDescription/FieldGrammar.hs b/Cabal/Distribution/PackageDescription/FieldGrammar.hs index 33daf5d6dbd..845b9efde3c 100644 --- a/Cabal/Distribution/PackageDescription/FieldGrammar.hs +++ b/Cabal/Distribution/PackageDescription/FieldGrammar.hs @@ -361,11 +361,13 @@ buildInfoFieldGrammar = BuildInfo ^^^ availableSince [2,0] <*> monoidalFieldAla "cpp-options" (alaList' NoCommaFSep Token') L.cppOptions <*> monoidalFieldAla "cc-options" (alaList' NoCommaFSep Token') L.ccOptions + <*> monoidalFieldAla "cxx-options" (alaList' NoCommaFSep Token') L.cxxOptions <*> monoidalFieldAla "ld-options" (alaList' NoCommaFSep Token') L.ldOptions <*> monoidalFieldAla "pkgconfig-depends" (alaList CommaFSep) L.pkgconfigDepends <*> monoidalFieldAla "frameworks" (alaList' FSep Token) L.frameworks <*> monoidalFieldAla "extra-framework-dirs" (alaList' FSep FilePathNT) L.extraFrameworkDirs <*> monoidalFieldAla "c-sources" (alaList' VCat FilePathNT) L.cSources + <*> monoidalFieldAla "cxx-sources" (alaList' VCat FilePathNT) L.cxxSources <*> monoidalFieldAla "js-sources" (alaList' VCat FilePathNT) L.jsSources <*> hsSourceDirsGrammar <*> monoidalFieldAla "other-modules" (alaList' VCat MQuoted) L.otherModules diff --git a/Cabal/Distribution/PackageDescription/Parse.hs b/Cabal/Distribution/PackageDescription/Parse.hs index b0e316cff5c..1a562eadbab 100644 --- a/Cabal/Distribution/PackageDescription/Parse.hs +++ b/Cabal/Distribution/PackageDescription/Parse.hs @@ -441,6 +441,9 @@ binfoFieldDescrs = , spaceListField "cc-options" showToken parseTokenQ' ccOptions (\val binfo -> binfo{ccOptions=val}) + , spaceListField "cxx-options" + showToken parseTokenQ' + cxxOptions (\val binfo -> binfo{cxxOptions=val}) , spaceListField "ld-options" showToken parseTokenQ' ldOptions (\val binfo -> binfo{ldOptions=val}) @@ -456,6 +459,9 @@ binfoFieldDescrs = , listFieldWithSep vcat "c-sources" showFilePath parseFilePathQ cSources (\paths binfo -> binfo{cSources=paths}) + , listFieldWithSep vcat "cxx-sources" + showFilePath parseFilePathQ + cxxSources (\paths binfo -> binfo{cxxSources=paths}) , listFieldWithSep vcat "js-sources" showFilePath parseFilePathQ jsSources (\paths binfo -> binfo{jsSources=paths}) diff --git a/Cabal/Distribution/Simple/Build.hs b/Cabal/Distribution/Simple/Build.hs index 6c6c7c2d646..09552ceb452 100644 --- a/Cabal/Distribution/Simple/Build.hs +++ b/Cabal/Distribution/Simple/Build.hs @@ -201,7 +201,7 @@ buildComponent verbosity numJobs pkg_descr lbi suffixes setupMessage' verbosity "Building" (packageId pkg_descr) (componentLocalName clbi) (maybeComponentInstantiatedWith clbi) let libbi = libBuildInfo lib - lib' = lib { libBuildInfo = addExtraCSources libbi extras } + lib' = lib { libBuildInfo = addExtraCxxSources (addExtraCSources libbi extras) extras } buildLib verbosity numJobs pkg_descr lbi lib' clbi let oneComponentRequested (OneComponentRequestedSpec _) = True @@ -329,6 +329,15 @@ addExtraCSources bi extras = bi { cSources = new } exs = Set.fromList extras +-- | Add extra C++ sources generated by preprocessing to build +-- information. +addExtraCxxSources :: BuildInfo -> [FilePath] -> BuildInfo +addExtraCxxSources bi extras = bi { cxxSources = new } + where new = Set.toList $ old `Set.union` exs + old = Set.fromList $ cxxSources bi + exs = Set.fromList extras + + replComponent :: Verbosity -> PackageDescription -> LocalBuildInfo diff --git a/Cabal/Distribution/Simple/GHC.hs b/Cabal/Distribution/Simple/GHC.hs index cb0c9ade957..c4a0489a3e5 100644 --- a/Cabal/Distribution/Simple/GHC.hs +++ b/Cabal/Distribution/Simple/GHC.hs @@ -559,7 +559,8 @@ buildOrReplLib forRepl verbosity numJobs pkg_descr lbi lib clbi = do createDirectoryIfMissingVerbose verbosity True libTargetDir -- TODO: do we need to put hs-boot files into place for mutually recursive -- modules? - let cObjs = map (`replaceExtension` objExtension) (cSources libBi) + let cLikeFiles = fromNubListR $ toNubListR (cSources libBi) <> toNubListR (cxxSources libBi) + cObjs = map (`replaceExtension` objExtension) cLikeFiles baseOpts = componentGhcOptions verbosity lbi libBi clbi libTargetDir vanillaOpts = baseOpts `mappend` mempty { ghcOptMode = toFlag GhcModeMake, @@ -644,6 +645,39 @@ buildOrReplLib forRepl verbosity numJobs pkg_descr lbi lib clbi = do else do vanilla; shared whenProfLib (runGhcProg profOpts) + -- build any C++ sources seperately + unless (not has_code || null (cxxSources libBi)) $ do + info verbosity "Building C++ Sources..." + sequence_ + [ do let baseCxxOpts = Internal.componentCxxGhcOptions verbosity implInfo + lbi libBi clbi libTargetDir filename + vanillaCxxOpts = if isGhcDynamic + then baseCxxOpts { ghcOptFPic = toFlag True } + else baseCxxOpts + profCxxOpts = vanillaCxxOpts `mappend` mempty { + ghcOptProfilingMode = toFlag True, + ghcOptObjSuffix = toFlag "p_o" + } + sharedCxxOpts = vanillaCxxOpts `mappend` mempty { + ghcOptFPic = toFlag True, + ghcOptDynLinkMode = toFlag GhcDynamicOnly, + ghcOptObjSuffix = toFlag "dyn_o" + } + odir = fromFlag (ghcOptObjDir vanillaCxxOpts) + createDirectoryIfMissingVerbose verbosity True odir + let runGhcProgIfNeeded cxxOpts = do + needsRecomp <- checkNeedsRecompilation filename cxxOpts + when needsRecomp $ runGhcProg cxxOpts + runGhcProgIfNeeded vanillaCxxOpts + unless forRepl $ + whenSharedLib forceSharedLib (runGhcProgIfNeeded sharedCxxOpts) + unless forRepl $ whenProfLib (runGhcProgIfNeeded profCxxOpts) + | filename <- cxxSources libBi] + + when has_code . ifReplLib $ do + when (null (allLibModules lib clbi)) $ warn verbosity "No exposed modules" + ifReplLib (runGhcProg replOpts) + -- build any C sources unless (not has_code || null (cSources libBi)) $ do info verbosity "Building C Sources..." @@ -679,17 +713,13 @@ buildOrReplLib forRepl verbosity numJobs pkg_descr lbi lib clbi = do -- with ghci, but .c files can depend on .h files generated by ghc by ffi -- exports. - when has_code . ifReplLib $ do - when (null (allLibModules lib clbi)) $ warn verbosity "No exposed modules" - ifReplLib (runGhcProg replOpts) - -- link: when has_code . unless forRepl $ do info verbosity "Linking..." let cProfObjs = map (`replaceExtension` ("p_" ++ objExtension)) - (cSources libBi) + (cSources libBi ++ cxxSources libBi) cSharedObjs = map (`replaceExtension` ("dyn_" ++ objExtension)) - (cSources libBi) + (cSources libBi ++ cxxSources libBi) compiler_id = compilerId (compiler lbi) vanillaLibFilePath = libTargetDir mkLibName uid profileLibFilePath = libTargetDir mkProfLibName uid diff --git a/Cabal/Distribution/Simple/GHC/Internal.hs b/Cabal/Distribution/Simple/GHC/Internal.hs index 7adeb29912c..5c36581cebb 100644 --- a/Cabal/Distribution/Simple/GHC/Internal.hs +++ b/Cabal/Distribution/Simple/GHC/Internal.hs @@ -19,6 +19,7 @@ module Distribution.Simple.GHC.Internal ( targetPlatform, getGhcInfo, componentCcGhcOptions, + componentCxxGhcOptions, componentGhcOptions, mkGHCiLibName, filterGhciFlags, @@ -290,6 +291,40 @@ componentCcGhcOptions verbosity _implInfo lbi bi clbi odir filename = ghcOptObjDir = toFlag odir } + +componentCxxGhcOptions :: Verbosity -> GhcImplInfo -> LocalBuildInfo + -> BuildInfo -> ComponentLocalBuildInfo + -> FilePath -> FilePath + -> GhcOptions +componentCxxGhcOptions verbosity _implInfo lbi bi cxxlbi odir filename = + mempty { + -- Respect -v0, but don't crank up verbosity on GHC if + -- Cabal verbosity is requested. For that, use --ghc-option=-v instead! + ghcOptVerbosity = toFlag (min verbosity normal), + ghcOptMode = toFlag GhcModeCompile, + ghcOptInputFiles = toNubListR [filename], + + ghcOptCppIncludePath = toNubListR $ [autogenComponentModulesDir lbi cxxlbi + ,autogenPackageModulesDir lbi + ,odir] + ++ PD.includeDirs bi, + ghcOptHideAllPackages= toFlag True, + ghcOptPackageDBs = withPackageDB lbi, + ghcOptPackages = toNubListR $ mkGhcOptPackages cxxlbi, + ghcOptCxxOptions = toNubListR $ + (case withOptimization lbi of + NoOptimisation -> [] + _ -> ["-O2"]) ++ + (case withDebugInfo lbi of + NoDebugInfo -> [] + MinimalDebugInfo -> ["-g1"] + NormalDebugInfo -> ["-g"] + MaximalDebugInfo -> ["-g3"]) ++ + PD.cxxOptions bi, + ghcOptObjDir = toFlag odir + } + + componentGhcOptions :: Verbosity -> GhcImplInfo -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo -> FilePath -> GhcOptions diff --git a/Cabal/Distribution/Simple/Program/GHC.hs b/Cabal/Distribution/Simple/Program/GHC.hs index dc470b88855..1e29532d1eb 100644 --- a/Cabal/Distribution/Simple/Program/GHC.hs +++ b/Cabal/Distribution/Simple/Program/GHC.hs @@ -154,6 +154,9 @@ data GhcOptions = GhcOptions { -- | Options to pass through to the C compiler; the @ghc -optc@ flag. ghcOptCcOptions :: NubListR String, + -- | Options to pass through to the C++ compiler. + ghcOptCxxOptions :: NubListR String, + -- | Options to pass through to CPP; the @ghc -optP@ flag. ghcOptCppOptions :: NubListR String, @@ -392,13 +395,16 @@ renderGhcOptions comp _platform@(Platform _arch os) opts , [ "-i" ++ dir | dir <- flags ghcOptSourcePath ] -------------------- - -- C and CPP stuff + + -------------------- + -- CPP, C, and C++ stuff , [ "-I" ++ dir | dir <- flags ghcOptCppIncludePath ] , [ "-optP" ++ opt | opt <- flags ghcOptCppOptions ] , concat [ [ "-optP-include", "-optP" ++ inc] | inc <- flags ghcOptCppIncludes ] , [ "-optc" ++ opt | opt <- flags ghcOptCcOptions ] + , [ "-optc" ++ opt | opt <- flags ghcOptCxxOptions ] ----------------- -- Linker stuff diff --git a/Cabal/Distribution/Types/BuildInfo.hs b/Cabal/Distribution/Types/BuildInfo.hs index 8bf41b80351..9d13111d832 100644 --- a/Cabal/Distribution/Types/BuildInfo.hs +++ b/Cabal/Distribution/Types/BuildInfo.hs @@ -52,11 +52,13 @@ data BuildInfo = BuildInfo { buildToolDepends :: [ExeDependency], cppOptions :: [String], -- ^ options for pre-processing Haskell code ccOptions :: [String], -- ^ options for C compiler + cxxOptions :: [String], -- ^ options for C++ compiler ldOptions :: [String], -- ^ options for linker pkgconfigDepends :: [PkgconfigDependency], -- ^ pkg-config packages that are used frameworks :: [String], -- ^support frameworks for Mac OS X extraFrameworkDirs:: [String], -- ^ extra locations to find frameworks. cSources :: [FilePath], + cxxSources :: [FilePath], jsSources :: [FilePath], hsSourceDirs :: [FilePath], -- ^ where to look for the Haskell module hierarchy otherModules :: [ModuleName], -- ^ non-exposed or non-main modules @@ -95,11 +97,13 @@ instance Monoid BuildInfo where buildToolDepends = [], cppOptions = [], ccOptions = [], + cxxOptions = [], ldOptions = [], pkgconfigDepends = [], frameworks = [], extraFrameworkDirs = [], cSources = [], + cxxSources = [], jsSources = [], hsSourceDirs = [], otherModules = [], @@ -132,11 +136,13 @@ instance Semigroup BuildInfo where buildToolDepends = combine buildToolDepends, cppOptions = combine cppOptions, ccOptions = combine ccOptions, + cxxOptions = combine cxxOptions, ldOptions = combine ldOptions, pkgconfigDepends = combine pkgconfigDepends, frameworks = combineNub frameworks, extraFrameworkDirs = combineNub extraFrameworkDirs, cSources = combineNub cSources, + cxxSources = combineNub cxxSources, jsSources = combineNub jsSources, hsSourceDirs = combineNub hsSourceDirs, otherModules = combineNub otherModules, diff --git a/Cabal/Distribution/Types/BuildInfo/Lens.hs b/Cabal/Distribution/Types/BuildInfo/Lens.hs index ac19c39fe87..b859e087a80 100644 --- a/Cabal/Distribution/Types/BuildInfo/Lens.hs +++ b/Cabal/Distribution/Types/BuildInfo/Lens.hs @@ -43,6 +43,10 @@ class HasBuildInfo a where ccOptions = buildInfo . ccOptions {-# INLINE ccOptions #-} + cxxOptions :: Lens' a [String] + cxxOptions = buildInfo . cxxOptions + {-# INLINE cxxOptions #-} + ldOptions :: Lens' a [String] ldOptions = buildInfo . ldOptions {-# INLINE ldOptions #-} @@ -63,6 +67,10 @@ class HasBuildInfo a where cSources = buildInfo . cSources {-# INLINE cSources #-} + cxxSources :: Lens' a [FilePath] + cxxSources = buildInfo . cxxSources + {-# INLINE cxxSources #-} + jsSources :: Lens' a [FilePath] jsSources = buildInfo . jsSources {-# INLINE jsSources #-} @@ -171,6 +179,9 @@ instance HasBuildInfo BuildInfo where ccOptions f s = fmap (\x -> s { T.ccOptions = x }) (f (T.ccOptions s)) {-# INLINE ccOptions #-} + cxxOptions f s = fmap (\x -> s { T.cxxOptions = x }) (f (T.cxxOptions s)) + {-# INLINE cxxOptions #-} + ldOptions f s = fmap (\x -> s { T.ldOptions = x }) (f (T.ldOptions s)) {-# INLINE ldOptions #-} @@ -186,6 +197,9 @@ instance HasBuildInfo BuildInfo where cSources f s = fmap (\x -> s { T.cSources = x }) (f (T.cSources s)) {-# INLINE cSources #-} + cxxSources f s = fmap (\x -> s { T.cSources = x }) (f (T.cxxSources s)) + {-# INLINE cxxSources #-} + jsSources f s = fmap (\x -> s { T.jsSources = x }) (f (T.jsSources s)) {-# INLINE jsSources #-} diff --git a/Cabal/changelog b/Cabal/changelog index 19f34d62645..49b5bcc3491 100644 --- a/Cabal/changelog +++ b/Cabal/changelog @@ -1,6 +1,8 @@ -*-change-log-*- 2.2.0.0 (current development version) + * Added cxx-options and cxx-sources build info fields for seperate + compilation of C++ source files (#3700) * Remove unused '--allow-newer'/'--allow-older' support (#4527) * Change `rawSystemStdInOut` to use proper type to represent binary and textual data; new 'Distribution.Utils.IOData' module; diff --git a/Cabal/doc/developing-packages.rst b/Cabal/doc/developing-packages.rst index 5781f0d522b..cb82a694251 100644 --- a/Cabal/doc/developing-packages.rst +++ b/Cabal/doc/developing-packages.rst @@ -2024,12 +2024,22 @@ system-dependent values for these fields. source tree. Cabal looks in these directories when attempting to locate files listed in :pkg-field:`includes` and :pkg-field:`install-includes`. - + .. pkg-field:: c-sources: filename list A list of C source files to be compiled and linked with the Haskell files. +.. pkg-field:: cxx-sources: filename list + + A list of C++ source files to be compiled and linked with the Haskell + files. Useful for segregating C and C++ sources when supplying different + command-line arguments to the compiler via the :pkg-field:`cc-options` + and the :pkg-field:`cxx-options` fields. The files listed in the + :pkg-field:`cxx-sources` can reference files listed in the + :pkg-field:`c-sources` field and vice-versa. The object files will be linked + appropriately. + .. pkg-field:: js-sources: filename list A list of JavaScript source files to be linked with the Haskell @@ -2060,6 +2070,18 @@ system-dependent values for these fields. haskell source and other pre-processed Haskell source like .hsc .chs. Does not apply to C code, that's what cc-options is for. +.. pkg-field:: cxx-options: token list + + Command-line arguments to be passed to the compiler when compiling + C++ code. The C++ sources to which these command-line arguments + should be applied can be specified with the :pkg-field:`cxx-sources` + field. Command-line options for C and C++ can be passed separately to + the compiler when compiling both C and C++ sources by segregating the C + and C++ sources with the :pkg-field:`c-sources` and + :pkg-field:`cxx-sources` fields respectively, and providing different + command-line arguments with the :pkg-field:`cc-options` and the + :pkg-field:`cxx-options` fields. + .. pkg-field:: ld-options: token list Command-line arguments to be passed to the linker. Since the diff --git a/cabal-install/changelog b/cabal-install/changelog index 224564943c6..bf1d6a86063 100644 --- a/cabal-install/changelog +++ b/cabal-install/changelog @@ -1,6 +1,13 @@ -*-change-log-*- 2.2.0.0 (current development version) + * New config file field: 'cxx-options' to specify which options to be + passed to the compiler when compiling C++ sources specified by the + 'cxx-sources' field. (#3700) + * New config file field: 'cxx-sources' to specify C++ files to be + compiled separately from C source files. Useful in conjunction with the + 'cxx-options' flag to pass different compiler options to C and C++ + source files. (#3700) * 'cabal configure' now supports '--enable-static' which can be used to build static libaries with GHC via GHC's `-staticlib` flag. * Don't automatically/silently case-correct mispelled package-names