From a6e427ac9e86ec63572fde702ada0a7fbed7dbb3 Mon Sep 17 00:00:00 2001 From: Alex Washburn Date: Thu, 22 Jun 2017 13:02:18 -0400 Subject: [PATCH 1/6] Initial attempt at adding seperate C++ compilation sources and compiler flags. --- .../Distribution/PackageDescription/Check.hs | 1 + .../Distribution/PackageDescription/Parse.hs | 6 +++ .../PackageDescription/Parsec/FieldDescr.hs | 8 +++- Cabal/Distribution/Simple/Build.hs | 9 +++++ Cabal/Distribution/Simple/GHC.hs | 37 +++++++++++++++++-- Cabal/Distribution/Simple/GHC/Internal.hs | 35 ++++++++++++++++++ Cabal/Distribution/Simple/Program/GHC.hs | 3 ++ Cabal/Distribution/Types/BuildInfo.hs | 6 +++ 8 files changed, 100 insertions(+), 5 deletions(-) diff --git a/Cabal/Distribution/PackageDescription/Check.hs b/Cabal/Distribution/PackageDescription/Check.hs index 341c12763a0..8f561019188 100644 --- a/Cabal/Distribution/PackageDescription/Check.hs +++ b/Cabal/Distribution/PackageDescription/Check.hs @@ -1018,6 +1018,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/Parse.hs b/Cabal/Distribution/PackageDescription/Parse.hs index d8217cb2392..f2372fb1b10 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/PackageDescription/Parsec/FieldDescr.hs b/Cabal/Distribution/PackageDescription/Parsec/FieldDescr.hs index 7055a098cf1..f4fff06d046 100644 --- a/Cabal/Distribution/PackageDescription/Parsec/FieldDescr.hs +++ b/Cabal/Distribution/PackageDescription/Parsec/FieldDescr.hs @@ -438,10 +438,13 @@ binfoFieldDescrs = mixins (\xs binfo -> binfo{mixins=xs}) , spaceListField "cpp-options" showToken parsecToken' - cppOptions (\val binfo -> binfo{cppOptions=val}) + cppOptions (\val binfo -> binfo{cppOptions=val}) , spaceListField "cc-options" showToken parsecToken' ccOptions (\val binfo -> binfo{ccOptions=val}) + , spaceListField "cxx-options" + showToken parsecToken' + cxxOption (\val binfo -> binfo{cxxOptions=val}) , spaceListField "ld-options" showToken parsecToken' ldOptions (\val binfo -> binfo{ldOptions=val}) @@ -457,6 +460,9 @@ binfoFieldDescrs = , listFieldWithSep vcat "c-sources" showFilePath parsecFilePath cSources (\paths binfo -> binfo{cSources=paths}) + , listFieldWithSep vcat "cxx-sources" + showFilePath parsecFilePath + cxxSources (\paths binfo -> binfo{cxxSources=paths}) , listFieldWithSep vcat "js-sources" showFilePath parsecFilePath jsSources (\paths binfo -> binfo{jsSources=paths}) diff --git a/Cabal/Distribution/Simple/Build.hs b/Cabal/Distribution/Simple/Build.hs index 6c6c7c2d646..ed8f663d129 100644 --- a/Cabal/Distribution/Simple/Build.hs +++ b/Cabal/Distribution/Simple/Build.hs @@ -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 455cfed3e1b..8fd7d3793fc 100644 --- a/Cabal/Distribution/Simple/GHC.hs +++ b/Cabal/Distribution/Simple/GHC.hs @@ -642,6 +642,39 @@ buildOrReplLib forRepl verbosity numJobs pkg_descr lbi lib clbi = do else do vanilla; shared when has_code $ 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..." @@ -677,10 +710,6 @@ 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..." diff --git a/Cabal/Distribution/Simple/GHC/Internal.hs b/Cabal/Distribution/Simple/GHC/Internal.hs index c8e4153b337..efb467bb1f7 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.ccOptions 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 6e70a703ecf..4871cb38acc 100644 --- a/Cabal/Distribution/Simple/Program/GHC.hs +++ b/Cabal/Distribution/Simple/Program/GHC.hs @@ -152,6 +152,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, diff --git a/Cabal/Distribution/Types/BuildInfo.hs b/Cabal/Distribution/Types/BuildInfo.hs index 635834a8fb5..d2948361d58 100644 --- a/Cabal/Distribution/Types/BuildInfo.hs +++ b/Cabal/Distribution/Types/BuildInfo.hs @@ -49,11 +49,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 @@ -91,11 +93,13 @@ instance Monoid BuildInfo where buildToolDepends = [], cppOptions = [], ccOptions = [], + cxxOptions = [], ldOptions = [], pkgconfigDepends = [], frameworks = [], extraFrameworkDirs = [], cSources = [], + cxxSources = [], jsSources = [], hsSourceDirs = [], otherModules = [], @@ -127,11 +131,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, From 3b5fedcbef2f4b4358d9562db358019c0a88aa47 Mon Sep 17 00:00:00 2001 From: Alex Washburn Date: Mon, 2 Oct 2017 17:45:42 -0400 Subject: [PATCH 2/6] Correcting build to compile C and C++ sources with seperate options and correctly link to both. --- Cabal/Distribution/PackageDescription/Parsec/FieldDescr.hs | 2 +- Cabal/Distribution/Simple/Build.hs | 2 +- Cabal/Distribution/Simple/GHC.hs | 6 +++--- Cabal/Distribution/Simple/GHC/Internal.hs | 2 +- Cabal/Distribution/Simple/Program/GHC.hs | 5 ++++- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Cabal/Distribution/PackageDescription/Parsec/FieldDescr.hs b/Cabal/Distribution/PackageDescription/Parsec/FieldDescr.hs index f4fff06d046..cae3cf1d02a 100644 --- a/Cabal/Distribution/PackageDescription/Parsec/FieldDescr.hs +++ b/Cabal/Distribution/PackageDescription/Parsec/FieldDescr.hs @@ -444,7 +444,7 @@ binfoFieldDescrs = ccOptions (\val binfo -> binfo{ccOptions=val}) , spaceListField "cxx-options" showToken parsecToken' - cxxOption (\val binfo -> binfo{cxxOptions=val}) + cxxOptions (\val binfo -> binfo{cxxOptions=val}) , spaceListField "ld-options" showToken parsecToken' ldOptions (\val binfo -> binfo{ldOptions=val}) diff --git a/Cabal/Distribution/Simple/Build.hs b/Cabal/Distribution/Simple/Build.hs index ed8f663d129..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 diff --git a/Cabal/Distribution/Simple/GHC.hs b/Cabal/Distribution/Simple/GHC.hs index 8fd7d3793fc..dc1e3ea5639 100644 --- a/Cabal/Distribution/Simple/GHC.hs +++ b/Cabal/Distribution/Simple/GHC.hs @@ -557,7 +557,7 @@ 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 cObjs = map (`replaceExtension` objExtension) (cSources libBi ++ cxxSources libBi) baseOpts = componentGhcOptions verbosity lbi libBi clbi libTargetDir vanillaOpts = baseOpts `mappend` mempty { ghcOptMode = toFlag GhcModeMake, @@ -714,9 +714,9 @@ buildOrReplLib forRepl verbosity numJobs pkg_descr lbi lib clbi = do 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 efb467bb1f7..1d44cdb5c56 100644 --- a/Cabal/Distribution/Simple/GHC/Internal.hs +++ b/Cabal/Distribution/Simple/GHC/Internal.hs @@ -320,7 +320,7 @@ componentCxxGhcOptions verbosity _implInfo lbi bi cxxlbi odir filename = MinimalDebugInfo -> ["-g1"] NormalDebugInfo -> ["-g"] MaximalDebugInfo -> ["-g3"]) ++ - PD.ccOptions bi, + PD.cxxOptions bi, ghcOptObjDir = toFlag odir } diff --git a/Cabal/Distribution/Simple/Program/GHC.hs b/Cabal/Distribution/Simple/Program/GHC.hs index 4871cb38acc..0648f31b040 100644 --- a/Cabal/Distribution/Simple/Program/GHC.hs +++ b/Cabal/Distribution/Simple/Program/GHC.hs @@ -388,13 +388,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 From 5b5c415632b25b8d7fdfb8f190e963831213a356 Mon Sep 17 00:00:00 2001 From: Alex Washburn Date: Tue, 3 Oct 2017 12:08:57 -0400 Subject: [PATCH 3/6] Updating changelog to note new cxx-* build info fields --- Cabal/changelog | 2 ++ 1 file changed, 2 insertions(+) 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; From 96a00e305bc1f86e01feb03f0f7d9bd868ff960f Mon Sep 17 00:00:00 2001 From: Alex Washburn Date: Tue, 3 Oct 2017 14:16:58 -0400 Subject: [PATCH 4/6] Attempting to remove duplicates from the cObj file list. --- Cabal/Distribution/Simple/GHC.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cabal/Distribution/Simple/GHC.hs b/Cabal/Distribution/Simple/GHC.hs index ef94d408bae..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 ++ cxxSources 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, From 914861262a827dc08b20df8320eb979380b5014d Mon Sep 17 00:00:00 2001 From: Alex Washburn Date: Tue, 3 Oct 2017 15:17:34 -0400 Subject: [PATCH 5/6] Adding new cxx-* flags to the cabal-install changelog. --- cabal-install/changelog | 7 +++++++ 1 file changed, 7 insertions(+) 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 From 818aec5305096aed7ed03515df728c9213075a1f Mon Sep 17 00:00:00 2001 From: Alex Washburn Date: Thu, 5 Oct 2017 12:24:17 -0400 Subject: [PATCH 6/6] Adding documentation for 'cxx-options' and 'cxx-sources' fields [ci skip] --- Cabal/doc/developing-packages.rst | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) 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