Commit 450d6bc4 authored by Ben Gamari's avatar Ben Gamari 🐢

Split sections support for GHC

Add --enable-split-sections flag and pipe it through to the GHC backend. Note
that some of the implementation here could be made a bit more precise:
-split-sections and -split-objs are mutually exlusive yet the types don't
currently reflect this.

Fixes #4819.
parent 4cc38b8c
......@@ -811,6 +811,11 @@ checkGhcOptions pkg =
++ "Check that it is giving a real benefit "
++ "and not just imposing longer compile times on your users."
, checkFlags ["-split-sections"] $
PackageBuildWarning $
"'ghc-options: -split-sections' is not needed. "
++ "Use the --enable-split-sections configure flag."
, checkFlags ["-split-objs"] $
PackageBuildWarning $
"'ghc-options: -split-objs' is not needed. "
......
......@@ -606,11 +606,31 @@ configure (pkg_descr0, pbi) cfg = do
installedPackageSet
comp
-- Decide if we're going to compile with split sections.
split_sections :: Bool <-
if not (fromFlag $ configSplitSections cfg)
then return False
else case compilerFlavor comp of
GHC | compilerVersion comp >= mkVersion [8,0]
-> return True
GHCJS
-> return True
_ -> do warn verbosity
("this compiler does not support " ++
"--enable-split-sections; ignoring")
return False
-- Decide if we're going to compile with split objects.
split_objs :: Bool <-
if not (fromFlag $ configSplitObjs cfg)
then return False
else case compilerFlavor comp of
_ | split_sections
-> do warn verbosity
("--enable-split-sections and " ++
"--enable-split-objs are mutually" ++
"exclusive; ignoring the latter")
return False
GHC | compilerVersion comp >= mkVersion [6,5]
-> return True
GHCJS
......@@ -708,6 +728,7 @@ configure (pkg_descr0, pbi) cfg = do
withDebugInfo = fromFlag $ configDebugInfo cfg,
withGHCiLib = fromFlagOrDefault ghciLibByDefault $
configGHCiLib cfg,
splitSections = split_sections,
splitObjs = split_objs,
stripExes = fromFlag $ configStripExes cfg,
stripLibs = fromFlag $ configStripLibs cfg,
......
......@@ -354,6 +354,7 @@ componentGhcOptions verbosity implInfo lbi bi clbi odir =
ghcOptWarnMissingHomeModules = toFlag $ flagWarnMissingHomeModules implInfo,
ghcOptPackageDBs = withPackageDB lbi,
ghcOptPackages = toNubListR $ mkGhcOptPackages clbi,
ghcOptSplitSections = toFlag (splitSections lbi),
ghcOptSplitObjs = toFlag (splitObjs lbi),
ghcOptSourcePathClear = toFlag True,
ghcOptSourcePath = toNubListR $ [odir] ++ (hsSourceDirs bi)
......
......@@ -197,6 +197,9 @@ data GhcOptions = GhcOptions {
-- | Automatically add profiling cost centers; the @ghc -fprof-auto*@ flags.
ghcOptProfilingAuto :: Flag GhcProfAuto,
-- | Use the \"split sections\" feature; the @ghc -split-sections@ flag.
ghcOptSplitSections :: Flag Bool,
-- | Use the \"split object files\" feature; the @ghc -split-objs@ flag.
ghcOptSplitObjs :: Flag Bool,
......@@ -350,6 +353,7 @@ renderGhcOptions comp _platform@(Platform _arch os) opts
| flagProfAuto implInfo -> ["-fprof-auto-exported"]
| otherwise -> ["-auto"]
, [ "-split-sections" | flagBool ghcOptSplitObjs ]
, [ "-split-objs" | flagBool ghcOptSplitObjs ]
, case flagToMaybe (ghcOptHPCDir opts) of
......
......@@ -336,6 +336,7 @@ data ConfigFlags = ConfigFlags {
configUserInstall :: Flag Bool, -- ^The --user\/--global flag
configPackageDBs :: [Maybe PackageDB], -- ^Which package DBs to use
configGHCiLib :: Flag Bool, -- ^Enable compiling library for GHCi
configSplitSections :: Flag Bool, -- ^Enable -split-sections with GHC
configSplitObjs :: Flag Bool, -- ^Enable -split-objs with GHC
configStripExes :: Flag Bool, -- ^Enable executable stripping
configStripLibs :: Flag Bool, -- ^Enable library stripping
......@@ -405,6 +406,7 @@ instance Eq ConfigFlags where
&& equal configUserInstall
&& equal configPackageDBs
&& equal configGHCiLib
&& equal configSplitSections
&& equal configSplitObjs
&& equal configStripExes
&& equal configStripLibs
......@@ -456,6 +458,7 @@ defaultConfigFlags progDb = emptyConfigFlags {
#else
configGHCiLib = NoFlag,
#endif
configSplitSections = Flag False,
configSplitObjs = Flag False, -- takes longer, so turn off by default
configStripExes = Flag True,
configStripLibs = Flag True,
......@@ -637,6 +640,11 @@ configureOptions showOrParseArgs =
configGHCiLib (\v flags -> flags { configGHCiLib = v })
(boolOpt [] [])
,option "" ["split-sections"]
"compile library code such that unneeded definitions can be dropped from the final executable (GHC 7.8+)"
configSplitSections (\v flags -> flags { configSplitSections = v })
(boolOpt [] [])
,option "" ["split-objs"]
"split library into smaller objects to reduce binary sizes (GHC 6.6+)"
configSplitObjs (\v flags -> flags { configSplitObjs = v })
......
......@@ -150,6 +150,7 @@ data LocalBuildInfo = LocalBuildInfo {
withOptimization :: OptimisationLevel, -- ^Whether to build with optimization (if available).
withDebugInfo :: DebugInfoLevel, -- ^Whether to emit debug info (if available).
withGHCiLib :: Bool, -- ^Whether to build libs suitable for use with GHCi.
splitSections :: Bool, -- ^Use -split-sections with GHC, if available
splitObjs :: Bool, -- ^Use -split-objs with GHC, if available
stripExes :: Bool, -- ^Whether to strip executables during install
stripLibs :: Bool, -- ^Whether to strip libraries during install
......
......@@ -20,6 +20,7 @@
* Support for GHC's numeric -g debug levels (#4673).
* Added elif-conditionals to .cabal syntax (#4750).
* Support for building with Win32 version 2.6 (#4835).
* Compilation with section splitting is now supported via the '--enable-split-sections' flag (#4819)
* TODO
......
......@@ -1120,10 +1120,29 @@ Object code options
The command line variant of this flag is ``--enable-debug-info`` and
``--disable-debug-info``.
.. cfg-field:: split-sections: boolean
--enable-split-sections
--disable-split-sections
:synopsis: Use GHC's split sections feature.
:since: 2.1
:default: False
Use the GHC ``-split-sections`` feature when building the library. This
reduces the final size of the executables that use the library by
allowing them to link with only the bits that they use rather than
the entire library. The downside is that building the library takes
longer and uses a bit more memory.
This feature is supported by GHC 8.0 and later.
The command line variant of this flag is ``--enable-split-sections`` and
``--disable-split-sections``.
.. cfg-field:: split-objs: boolean
--enable-split-objs
--disable-split-objs
:synopsis: Use GHC split objects feature.
:synopsis: Use GHC's split objects feature.
:default: False
......@@ -1133,6 +1152,9 @@ Object code options
the entire library. The downside is that building the library takes
longer and uses considerably more memory.
It is generally recommend that you use ``split-sections`` instead
of ``split-objs`` where possible.
The command line variant of this flag is ``--enable-split-objs`` and
``--disable-split-objs``.
......
......@@ -324,6 +324,7 @@ instance Semigroup SavedConfig where
-- TODO: NubListify
configPackageDBs = lastNonEmpty configPackageDBs,
configGHCiLib = combine configGHCiLib,
configSplitSections = combine configSplitSections,
configSplitObjs = combine configSplitObjs,
configStripExes = combine configStripExes,
configStripLibs = combine configStripLibs,
......
......@@ -202,6 +202,7 @@ data PackageHashConfigInputs = PackageHashConfigInputs {
pkgHashCoverage :: Bool,
pkgHashOptimization :: OptimisationLevel,
pkgHashSplitObjs :: Bool,
pkgHashSplitSections :: Bool,
pkgHashStripLibs :: Bool,
pkgHashStripExes :: Bool,
pkgHashDebugInfo :: DebugInfoLevel,
......@@ -280,6 +281,7 @@ renderPackageHashInputs PackageHashInputs{
, opt "hpc" False display pkgHashCoverage
, opt "optimisation" NormalOptimisation (show . fromEnum) pkgHashOptimization
, opt "split-objs" False display pkgHashSplitObjs
, opt "split-sections" False display pkgHashSplitSections
, opt "stripped-lib" False display pkgHashStripLibs
, opt "stripped-exe" True display pkgHashStripExes
, opt "debug-info" NormalDebugInfo (show . fromEnum) pkgHashDebugInfo
......
......@@ -341,6 +341,7 @@ convertLegacyPerPackageFlags configFlags installFlags haddockFlags =
configProgPrefix = packageConfigProgPrefix,
configProgSuffix = packageConfigProgSuffix,
configGHCiLib = packageConfigGHCiLib,
configSplitSections = packageConfigSplitSections,
configSplitObjs = packageConfigSplitObjs,
configStripExes = packageConfigStripExes,
configStripLibs = packageConfigStripLibs,
......@@ -577,6 +578,7 @@ convertToLegacyAllPackageConfig
configUserInstall = mempty, --projectConfigUserInstall,
configPackageDBs = mempty, --projectConfigPackageDBs,
configGHCiLib = mempty,
configSplitSections = mempty,
configSplitObjs = mempty,
configStripExes = mempty,
configStripLibs = mempty,
......@@ -644,6 +646,7 @@ convertToLegacyPerPackageConfig PackageConfig {..} =
configUserInstall = mempty,
configPackageDBs = mempty,
configGHCiLib = packageConfigGHCiLib,
configSplitSections = packageConfigSplitSections,
configSplitObjs = packageConfigSplitObjs,
configStripExes = packageConfigStripExes,
configStripLibs = packageConfigStripLibs,
......@@ -911,7 +914,7 @@ legacyPackageConfigFieldDescrs =
, "shared", "static", "executable-dynamic"
, "profiling", "executable-profiling"
, "profiling-detail", "library-profiling-detail"
, "library-for-ghci", "split-objs"
, "library-for-ghci", "split-objs", "split-sections"
, "executable-stripping", "library-stripping"
, "tests", "benchmarks"
, "coverage", "library-coverage"
......
......@@ -243,6 +243,7 @@ data PackageConfig
packageConfigExtraFrameworkDirs :: [FilePath],
packageConfigExtraIncludeDirs :: [FilePath],
packageConfigGHCiLib :: Flag Bool,
packageConfigSplitSections :: Flag Bool,
packageConfigSplitObjs :: Flag Bool,
packageConfigStripExes :: Flag Bool,
packageConfigStripLibs :: Flag Bool,
......
......@@ -1690,6 +1690,7 @@ elaborateInstallPlan verbosity platform compiler compilerprogdb pkgConfigDB
elabOptimization = perPkgOptionFlag pkgid NormalOptimisation packageConfigOptimization
elabSplitObjs = perPkgOptionFlag pkgid False packageConfigSplitObjs
elabSplitSections = perPkgOptionFlag pkgid False packageConfigSplitSections
elabStripLibs = perPkgOptionFlag pkgid False packageConfigStripLibs
elabStripExes = perPkgOptionFlag pkgid False packageConfigStripExes
elabDebugInfo = perPkgOptionFlag pkgid NoDebugInfo packageConfigDebugInfo
......@@ -3081,6 +3082,7 @@ setupHsConfigureFlags (ReadyPackage elab@ElaboratedConfiguredPackage{..})
configLibCoverage = mempty
configOptimization = toFlag elabOptimization
configSplitSections = toFlag elabSplitSections
configSplitObjs = toFlag elabSplitObjs
configStripExes = toFlag elabStripExes
configStripLibs = toFlag elabStripLibs
......@@ -3416,6 +3418,7 @@ packageHashConfigInputs
pkgHashProfExeDetail = elabProfExeDetail,
pkgHashCoverage = elabCoverage,
pkgHashOptimization = elabOptimization,
pkgHashSplitSections = elabSplitSections,
pkgHashSplitObjs = elabSplitObjs,
pkgHashStripLibs = elabStripLibs,
pkgHashStripExes = elabStripExes,
......
......@@ -241,6 +241,7 @@ data ElaboratedConfiguredPackage
elabCoverage :: Bool,
elabOptimization :: OptimisationLevel,
elabSplitObjs :: Bool,
elabSplitSections :: Bool,
elabStripLibs :: Bool,
elabStripExes :: Bool,
elabDebugInfo :: DebugInfoLevel,
......
......@@ -440,6 +440,7 @@ filterConfigureFlags flags cabalLibVersion
configVerbosity = fmap verboseNoTimestamp (configVerbosity flags_latest)
-- Cabal < 2.1 doesn't know about --<enable|disable>-static
, configStaticLib = NoFlag
, configSplitSections = NoFlag
}
flags_1_25_0 = flags_2_1_0 {
......
......@@ -531,7 +531,7 @@ instance Arbitrary PackageConfig where
<*> shortListOf 5 arbitraryShortToken
<*> shortListOf 5 arbitraryShortToken
<*> shortListOf 5 arbitraryShortToken
<*> arbitrary
<*> arbitrary <*> arbitrary
<*> arbitrary <*> arbitrary
<*> arbitrary <*> arbitrary
<*> arbitrary <*> arbitrary
......@@ -575,7 +575,8 @@ instance Arbitrary PackageConfig where
, packageConfigExtraFrameworkDirs = x17
, packageConfigExtraIncludeDirs = x18
, packageConfigGHCiLib = x19
, packageConfigSplitObjs = x20
, packageConfigSplitSections = x20
, packageConfigSplitObjs = x20_1
, packageConfigStripExes = x21
, packageConfigStripLibs = x22
, packageConfigTests = x23
......@@ -619,7 +620,8 @@ instance Arbitrary PackageConfig where
, packageConfigExtraFrameworkDirs = map getNonEmpty x17'
, packageConfigExtraIncludeDirs = map getNonEmpty x18'
, packageConfigGHCiLib = x19'
, packageConfigSplitObjs = x20'
, packageConfigSplitSections = x20'
, packageConfigSplitObjs = x20_1'
, packageConfigStripExes = x21'
, packageConfigStripLibs = x22'
, packageConfigTests = x23'
......@@ -646,7 +648,7 @@ instance Arbitrary PackageConfig where
(x05', x42', x06', x07', x08', x09'),
(x10', x11', x12', x13', x14'),
(x15', x16', x17', x18', x19')),
((x20', x21', x22', x23', x24'),
((x20', x20_1', x21', x22', x23', x24'),
(x25', x26', x27', x28', x29'),
(x30', x31', x32', (x33', x33_1'), x34'),
(x35', x36', x37', x38', x39'),
......@@ -659,7 +661,7 @@ instance Arbitrary PackageConfig where
map NonEmpty x17,
map NonEmpty x18,
x19)),
((x20, x21, x22, x23, x24),
((x20, x20_1, x21, x22, x23, x24),
(x25, x26, x27, x28, x29),
(x30, x31, x32, (x33, x33_1), x34),
(x35, x36, fmap NonEmpty x37, x38, fmap NonEmpty x39),
......
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