From 80f0a6521f876bcc88fcb56346e40c092709fb2c Mon Sep 17 00:00:00 2001 From: Finley McIlwaine Date: Tue, 15 Aug 2023 16:21:15 -0600 Subject: [PATCH 1/4] Do not use tmp dirs for Haddock, add --haddock-version-cpp, and more Haddock no longer writes compilation files by default, so we do not need to pass tmp dirs for `-hidir`, `-stubdir`, and `-odir` via `--optghc`. Indeed, we do not *want* to do so, since it results in recompilation for every invocation of Haddock via Cabal. This commit stops this from happening for haddock versions >= 2.28 (when Hi Haddock was introduced). This commit also stops the default definition of the `__HADDOCK_VERSION__` macro when invoking GHC through haddock. Since a very limited set of users may still depend on this macro, we introduce the `--haddock-version-cpp` flag and `haddock-version-cpp:` cabal.project field, which enable the definition of the `__HADDOCK_VERSION__` macro when invoking GHC through Haddock. This will almost guarantee recompilation during documentation generation due to the macro definition. This commit also renames the `--haddock-lib` flag to `--haddock-resources-dir` (and `haddock-lib:` cabal.project field to `haddock-resources-dir:`), and adds this flag to the users guide since it was missing an entry. This also allows us to add this field to `cabal-install:test:integration-tests2`, since it is no longer ambiguous with the `--lib` flag. This commit also causes `documentation: true` or `--enable-documentation` to imply `-haddock` for GHC. Also, since Haddock >= 2.29 is renaming `--lib` to `--resources-dir`, this commit switches the flag provided to Haddock using a backwards compatible condition based on the Haddock version. Adds a changelog entry. --- .gitignore | 3 + Cabal/src/Distribution/Simple/Haddock.hs | 141 +++++++++++------- .../src/Distribution/Simple/Setup/Haddock.hs | 38 +++-- .../Distribution/Client/CmdHaddockProject.hs | 3 +- .../src/Distribution/Client/Config.hs | 3 +- .../src/Distribution/Client/PackageHash.hs | 6 +- .../Client/ProjectConfig/Legacy.hs | 9 +- .../Client/ProjectConfig/Types.hs | 3 +- .../Distribution/Client/ProjectPlanning.hs | 18 ++- .../Client/ProjectPlanning/Types.hs | 3 +- .../src/Distribution/Client/Setup.hs | 3 +- cabal-install/tests/IntegrationTests2.hs | 2 + .../Distribution/Client/ProjectConfig.hs | 9 +- .../PackageTests/NewHaddock/Fails/cabal.out | 3 +- changelog.d/pr-9177 | 28 ++++ doc/cabal-project-description-file.rst | 19 +++ test/IntegrationTests2/config/default-config | 7 +- .../nix-config/default-config | 7 +- tests/IntegrationTests2/config/default-config | 17 ++- .../nix-config/default-config | 7 +- 20 files changed, 235 insertions(+), 94 deletions(-) create mode 100644 changelog.d/pr-9177 diff --git a/.gitignore b/.gitignore index 97632785e28..957786d7055 100644 --- a/.gitignore +++ b/.gitignore @@ -98,6 +98,9 @@ bench.html # Emacs .projectile +# direnv +.envrc + ## Release Scripts # ignore the downloaded binary files diff --git a/Cabal/src/Distribution/Simple/Haddock.hs b/Cabal/src/Distribution/Simple/Haddock.hs index 2429362d72e..8c6fd86a691 100644 --- a/Cabal/src/Distribution/Simple/Haddock.hs +++ b/Cabal/src/Distribution/Simple/Haddock.hs @@ -153,7 +153,7 @@ data HaddockArgs = HaddockArgs -- ^ Re-exported modules , argTargets :: [FilePath] -- ^ Modules to process. - , argLib :: Flag String + , argResourcesDir :: Flag String -- ^ haddock's static \/ auxiliary files. } deriving (Generic) @@ -329,6 +329,15 @@ haddock_setupHooks [] -> allTargetsInBuildOrder' pkg_descr lbi _ -> targets + version' = + if flag haddockVersionCPP + then Just version + else Nothing + + mtmp + | version >= mkVersion [2, 28, 0] = const Nothing + | otherwise = Just + internalPackageDB <- createInternalPackageDB verbosity lbi (flag $ setupDistPref . haddockCommonFlags) @@ -367,11 +376,11 @@ haddock_setupHooks exeArgs <- fromExecutable verbosity - tmp + (mtmp tmp) lbi' clbi htmlTemplate - version + version' exe let exeArgs' = commonArgs `mappend` exeArgs runHaddock @@ -401,17 +410,17 @@ haddock_setupHooks (maybeComponentInstantiatedWith clbi) ipi <- case component of CLib lib -> do - withTempDirectoryCwdEx verbosity tmpFileOpts mbWorkDir (buildDir lbi) "tmp" $ + withTempDirectoryCwdEx verbosity tmpFileOpts mbWorkDir (buildDir lbi') "tmp" $ \tmp -> do smsg libArgs <- fromLibrary verbosity - tmp + (mtmp tmp) lbi' clbi htmlTemplate - version + version' lib let libArgs' = commonArgs `mappend` libArgs runHaddock verbosity mbWorkDir tmpFileOpts comp platform haddockProg True libArgs' @@ -448,20 +457,20 @@ haddock_setupHooks when (flag haddockForeignLibs) ( do - withTempDirectoryCwdEx verbosity tmpFileOpts mbWorkDir (buildDir lbi') "tmp" $ - \tmp -> do - smsg - flibArgs <- + smsg + flibArgs <- + withTempDirectoryCwdEx verbosity tmpFileOpts mbWorkDir (buildDir lbi') "tmp" $ + \tmp -> do fromForeignLib verbosity - tmp + (mtmp tmp) lbi' clbi htmlTemplate - version + version' flib - let libArgs' = commonArgs `mappend` flibArgs - runHaddock verbosity mbWorkDir tmpFileOpts comp platform haddockProg True libArgs' + let libArgs' = commonArgs `mappend` flibArgs + runHaddock verbosity mbWorkDir tmpFileOpts comp platform haddockProg True libArgs' ) >> return index CExe _ -> when (flag haddockExecutables) (smsg >> doExe component) >> return index @@ -525,7 +534,7 @@ fromFlags env flags = (haddockIndex flags) , argGenIndex = Flag False , argBaseUrl = haddockBaseUrl flags - , argLib = haddockLib flags + , argResourcesDir = haddockResourcesDir flags , argVerbose = maybe mempty (Any . (>= deafening)) . flagToMaybe @@ -552,7 +561,7 @@ fromHaddockProjectFlags flags = , argPrologueFile = haddockProjectPrologue flags , argInterfaces = fromFlagOrDefault [] (haddockProjectInterfaces flags) , argLinkedSource = Flag True - , argLib = haddockProjectLib flags + , argResourcesDir = haddockProjectResourcesDir flags } fromPackageDescription :: HaddockTarget -> PackageDescription -> HaddockArgs @@ -597,26 +606,34 @@ componentGhcOptions verbosity lbi bi clbi odir = mkHaddockArgs :: Verbosity - -> SymbolicPath Pkg (Path.Dir Tmp) + -> Maybe (SymbolicPath Pkg (Path.Dir Tmp)) + -- ^ 'Nothing' to prevent passing temporary directories for -hidir, -odir, and + -- -stubdir to GHC through Haddock -> LocalBuildInfo -> ComponentLocalBuildInfo -> Maybe PathTemplate -- ^ template for HTML location - -> Version + -> Maybe Version + -- ^ 'Nothing' if the user requested not to define the __HADDOCK_VERSION__ + -- macro -> [SymbolicPath Pkg File] -> BuildInfo -> IO HaddockArgs -mkHaddockArgs verbosity tmp lbi clbi htmlTemplate haddockVersion inFiles bi = do +mkHaddockArgs verbosity mtmp lbi clbi htmlTemplate haddockVersion inFiles bi = do ifaceArgs <- getInterfaces verbosity lbi clbi htmlTemplate - let vanillaOpts = - (componentGhcOptions normal lbi bi clbi (buildDir lbi)) - { -- Noooooooooo!!!!!111 - -- haddock stomps on our precious .hi - -- and .o files. Workaround by telling - -- haddock to write them elsewhere. - ghcOptObjDir = toFlag $ coerceSymbolicPath tmp - , ghcOptHiDir = toFlag $ coerceSymbolicPath tmp - , ghcOptStubDir = toFlag $ coerceSymbolicPath tmp + let vanillaOpts' = + componentGhcOptions normal lbi bi clbi (buildDir lbi) + `mappend` getGhcCppOpts haddockVersion bi + vanillaOpts = + vanillaOpts' + { -- Starting with Haddock 2.28, we no longer want to run Haddock's + -- GHC session in a temporary directory. Doing so always causes + -- recompilation during documentation generation, which can now be + -- avoided thanks to Hi Haddock. See + -- https://github.com/haskell/cabal/pull/9177 for discussion. + ghcOptObjDir = maybe (ghcOptObjDir vanillaOpts') (toFlag . coerceSymbolicPath) mtmp + , ghcOptHiDir = maybe (ghcOptHiDir vanillaOpts') (toFlag . coerceSymbolicPath) mtmp + , ghcOptStubDir = maybe (ghcOptStubDir vanillaOpts') (toFlag . coerceSymbolicPath) mtmp } `mappend` getGhcCppOpts haddockVersion bi sharedOpts = @@ -644,20 +661,24 @@ mkHaddockArgs verbosity tmp lbi clbi htmlTemplate haddockVersion inFiles bi = do fromLibrary :: Verbosity - -> SymbolicPath Pkg (Path.Dir Tmp) + -> Maybe (SymbolicPath Pkg (Path.Dir Tmp)) + -- ^ 'Nothing' to prevent passing temporary directories for -hidir, -odir, and + -- -stubdir to GHC through Haddock -> LocalBuildInfo -> ComponentLocalBuildInfo -> Maybe PathTemplate -- ^ template for HTML location - -> Version + -> Maybe Version + -- ^ 'Nothing' if the user requested not to define the __HADDOCK_VERSION__ + -- macro -> Library -> IO HaddockArgs -fromLibrary verbosity tmp lbi clbi htmlTemplate haddockVersion lib = do +fromLibrary verbosity mtmp lbi clbi htmlTemplate haddockVersion lib = do inFiles <- map snd `fmap` getLibSourceFiles verbosity lbi lib clbi args <- mkHaddockArgs verbosity - tmp + mtmp lbi clbi htmlTemplate @@ -671,20 +692,24 @@ fromLibrary verbosity tmp lbi clbi htmlTemplate haddockVersion lib = do fromExecutable :: Verbosity - -> SymbolicPath Pkg (Path.Dir Tmp) + -> Maybe (SymbolicPath Pkg (Path.Dir Tmp)) + -- ^ 'Nothing' to prevent passing temporary directories for -hidir, -odir, and + -- -stubdir to GHC through Haddock -> LocalBuildInfo -> ComponentLocalBuildInfo -> Maybe PathTemplate -- ^ template for HTML location - -> Version + -> Maybe Version + -- ^ 'Nothing' if the user requested not to define the __HADDOCK_VERSION__ + -- macro -> Executable -> IO HaddockArgs -fromExecutable verbosity tmp lbi clbi htmlTemplate haddockVersion exe = do +fromExecutable verbosity mtmp lbi clbi htmlTemplate haddockVersion exe = do inFiles <- map snd `fmap` getExeSourceFiles verbosity lbi exe clbi args <- mkHaddockArgs verbosity - tmp + mtmp lbi clbi htmlTemplate @@ -699,20 +724,24 @@ fromExecutable verbosity tmp lbi clbi htmlTemplate haddockVersion exe = do fromForeignLib :: Verbosity - -> SymbolicPath Pkg (Path.Dir Tmp) + -> Maybe (SymbolicPath Pkg (Path.Dir Tmp)) + -- ^ 'Nothing' to prevent passing temporary directories for -hidir, -odir, and + -- -stubdir to GHC through Haddock -> LocalBuildInfo -> ComponentLocalBuildInfo -> Maybe PathTemplate -- ^ template for HTML location - -> Version + -> Maybe Version + -- ^ 'Nothing' if the user requested not to define the __HADDOCK_VERSION__ + -- macro -> ForeignLib -> IO HaddockArgs -fromForeignLib verbosity tmp lbi clbi htmlTemplate haddockVersion flib = do +fromForeignLib verbosity mtmp lbi clbi htmlTemplate haddockVersion flib = do inFiles <- map snd `fmap` getFLibSourceFiles verbosity lbi flib clbi args <- mkHaddockArgs verbosity - tmp + mtmp lbi clbi htmlTemplate @@ -768,7 +797,9 @@ getReexports LibComponentLocalBuildInfo{componentExposedModules = mods} = getReexports _ = [] getGhcCppOpts - :: Version + :: Maybe Version + -- ^ 'Nothing' if the user requested not to define the __HADDOCK_VERSION__ + -- macro -> BuildInfo -> GhcOptions getGhcCppOpts haddockVersion bi = @@ -778,16 +809,21 @@ getGhcCppOpts haddockVersion bi = } where needsCpp = EnableExtension CPP `elem` usedExtensions bi - defines = [haddockVersionMacro] - haddockVersionMacro = - "-D__HADDOCK_VERSION__=" - ++ show (v1 * 1000 + v2 * 10 + v3) + defines = + [ "-D__HADDOCK_VERSION__=" ++ show vn + | Just vn <- [versionInt . versionNumbers <$> haddockVersion] + ] where - (v1, v2, v3) = case versionNumbers haddockVersion of - [] -> (0, 0, 0) - [x] -> (x, 0, 0) - [x, y] -> (x, y, 0) - (x : y : z : _) -> (x, y, z) + -- For some list xs = [x, y, z ...], versionInt xs results in + -- x * 1000 + y * 10 + z. E.g.: + -- >>> versionInt [2, 29, 0] + -- 2290 + -- >>> versionInt [3, 4] + -- 3040 + -- >>> versionInt [] + -- 0 + versionInt :: [Int] -> Int + versionInt = foldr ((+) . uncurry (*)) 0 . zip [1000, 10, 1] getGhcLibDir :: Verbosity @@ -993,7 +1029,7 @@ renderPureArgs version comp platform args = , isVersion 2 19 ] , argTargets $ args - , maybe [] ((: []) . ("--lib=" ++)) . flagToMaybe . argLib $ args + , maybe [] ((: []) . (resourcesDirFlag ++)) . flagToMaybe . argResourcesDir $ args ] where -- See Note [Symbolic paths] in Distribution.Utils.Path @@ -1037,6 +1073,9 @@ renderPureArgs version comp platform args = verbosityFlag | isVersion 2 5 = "--verbosity=1" | otherwise = "--verbose" + resourcesDirFlag + | isVersion 2 29 = "--resources-dir=" + | otherwise = "--lib=" haddockSupportsVisibility = version >= mkVersion [2, 26, 1] haddockSupportsPackageName = version > mkVersion [2, 16] haddockSupportsHyperlinkedSource = isVersion 2 17 diff --git a/Cabal/src/Distribution/Simple/Setup/Haddock.hs b/Cabal/src/Distribution/Simple/Setup/Haddock.hs index bcb2c9dbc5e..5b1a6a0999e 100644 --- a/Cabal/src/Distribution/Simple/Setup/Haddock.hs +++ b/Cabal/src/Distribution/Simple/Setup/Haddock.hs @@ -113,8 +113,9 @@ data HaddockFlags = HaddockFlags , haddockIndex :: Flag PathTemplate , haddockKeepTempFiles :: Flag Bool , haddockBaseUrl :: Flag String - , haddockLib :: Flag String + , haddockResourcesDir :: Flag String , haddockOutputDir :: Flag FilePath + , haddockVersionCPP :: Flag Bool } deriving (Show, Generic, Typeable) @@ -168,8 +169,9 @@ defaultHaddockFlags = , haddockKeepTempFiles = Flag False , haddockIndex = NoFlag , haddockBaseUrl = NoFlag - , haddockLib = NoFlag + , haddockResourcesDir = NoFlag , haddockOutputDir = NoFlag + , haddockVersionCPP = Flag False } haddockCommand :: CommandUI HaddockFlags @@ -366,10 +368,10 @@ haddockOptions showOrParseArgs = (reqArgFlag "URL") , option "" - ["lib"] + ["resources-dir"] "location of Haddocks static / auxiliary files" - haddockLib - (\v flags -> flags{haddockLib = v}) + haddockResourcesDir + (\v flags -> flags{haddockResourcesDir = v}) (reqArgFlag "DIR") , option "" @@ -378,6 +380,13 @@ haddockOptions showOrParseArgs = haddockOutputDir (\v flags -> flags{haddockOutputDir = v}) (reqArgFlag "DIR") + , option + "" + ["version-cpp"] + "Define the __HADDOCK_VERSION__ macro when invoking GHC through Haddock. This will likely trigger recompilation during documentation generation." + haddockVersionCPP + (\v flags -> flags{haddockVersionCPP = v}) + trueArg ] emptyHaddockFlags :: HaddockFlags @@ -440,8 +449,9 @@ data HaddockProjectFlags = HaddockProjectFlags haddockProjectKeepTempFiles :: Flag Bool , haddockProjectVerbosity :: Flag Verbosity , -- haddockBaseUrl is not supported, a fixed value is provided - haddockProjectLib :: Flag String + haddockProjectResourcesDir :: Flag String , haddockProjectOutputDir :: Flag FilePath + , haddockProjectVersionCPP :: Flag Bool } deriving (Show, Generic, Typeable) @@ -464,9 +474,10 @@ defaultHaddockProjectFlags = , haddockProjectHscolourCss = NoFlag , haddockProjectKeepTempFiles = Flag False , haddockProjectVerbosity = Flag normal - , haddockProjectLib = NoFlag + , haddockProjectResourcesDir = NoFlag , haddockProjectOutputDir = NoFlag , haddockProjectInterfaces = NoFlag + , haddockProjectVersionCPP = Flag False } haddockProjectCommand :: CommandUI HaddockProjectFlags @@ -608,10 +619,10 @@ haddockProjectOptions _showOrParseArgs = (\v flags -> flags{haddockProjectVerbosity = v}) , option "" - ["lib"] + ["resources-dir"] "location of Haddocks static / auxiliary files" - haddockProjectLib - (\v flags -> flags{haddockProjectLib = v}) + haddockProjectResourcesDir + (\v flags -> flags{haddockProjectResourcesDir = v}) (reqArgFlag "DIR") , option "" @@ -620,6 +631,13 @@ haddockProjectOptions _showOrParseArgs = haddockProjectOutputDir (\v flags -> flags{haddockProjectOutputDir = v}) (reqArgFlag "DIR") + , option + "" + ["version-cpp"] + "Define the __HADDOCK_VERSION__ macro when invoking GHC through Haddock. This will likely trigger recompilation during documentation generation." + haddockProjectVersionCPP + (\v flags -> flags{haddockProjectVersionCPP = v}) + trueArg ] emptyHaddockProjectFlags :: HaddockProjectFlags diff --git a/cabal-install/src/Distribution/Client/CmdHaddockProject.hs b/cabal-install/src/Distribution/Client/CmdHaddockProject.hs index bf21de2d352..c2f31c6300a 100644 --- a/cabal-install/src/Distribution/Client/CmdHaddockProject.hs +++ b/cabal-install/src/Distribution/Client/CmdHaddockProject.hs @@ -148,8 +148,9 @@ haddockProjectAction flags _extraArgs globalFlags = do then Flag (toPathTemplate "../doc-index.html") else NoFlag , haddockKeepTempFiles = haddockProjectKeepTempFiles flags - , haddockLib = haddockProjectLib flags + , haddockResourcesDir = haddockProjectResourcesDir flags , haddockOutputDir = haddockProjectOutputDir flags + , haddockVersionCPP = haddockProjectVersionCPP flags } nixFlags = (commandDefaultFlags CmdHaddock.haddockCommand) diff --git a/cabal-install/src/Distribution/Client/Config.hs b/cabal-install/src/Distribution/Client/Config.hs index fd9bd5af432..454c765b911 100644 --- a/cabal-install/src/Distribution/Client/Config.hs +++ b/cabal-install/src/Distribution/Client/Config.hs @@ -630,8 +630,9 @@ instance Semigroup SavedConfig where , haddockKeepTempFiles = combine haddockKeepTempFiles , haddockIndex = combine haddockIndex , haddockBaseUrl = combine haddockBaseUrl - , haddockLib = combine haddockLib + , haddockResourcesDir = combine haddockResourcesDir , haddockOutputDir = combine haddockOutputDir + , haddockVersionCPP = combine haddockVersionCPP } where combine = combine' savedHaddockFlags diff --git a/cabal-install/src/Distribution/Client/PackageHash.hs b/cabal-install/src/Distribution/Client/PackageHash.hs index f5387a37bd8..5ced7e1823a 100644 --- a/cabal-install/src/Distribution/Client/PackageHash.hs +++ b/cabal-install/src/Distribution/Client/PackageHash.hs @@ -238,8 +238,9 @@ data PackageHashConfigInputs = PackageHashConfigInputs , pkgHashHaddockContents :: Maybe PathTemplate , pkgHashHaddockIndex :: Maybe PathTemplate , pkgHashHaddockBaseUrl :: Maybe String - , pkgHashHaddockLib :: Maybe String + , pkgHashHaddockResourcesDir :: Maybe String , pkgHashHaddockOutputDir :: Maybe FilePath + , pkgHashHaddockVersionCPP :: Bool -- TODO: [required eventually] pkgHashToolsVersions ? -- TODO: [required eventually] pkgHashToolsExtraOptions ? } @@ -347,8 +348,9 @@ renderPackageHashInputs , opt "haddock-contents-location" Nothing (maybe "" fromPathTemplate) pkgHashHaddockContents , opt "haddock-index-location" Nothing (maybe "" fromPathTemplate) pkgHashHaddockIndex , opt "haddock-base-url" Nothing (fromMaybe "") pkgHashHaddockBaseUrl - , opt "haddock-lib" Nothing (fromMaybe "") pkgHashHaddockLib + , opt "haddock-resources-dir" Nothing (fromMaybe "") pkgHashHaddockResourcesDir , opt "haddock-output-dir" Nothing (fromMaybe "") pkgHashHaddockOutputDir + , opt "haddock-version-cpp" False prettyShow pkgHashHaddockVersionCPP ] ++ Map.foldrWithKey (\prog args acc -> opt (prog ++ "-options") [] unwords args : acc) [] pkgHashProgramArgs where diff --git a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs index fe2e86d8ccc..50e7f0feb9a 100644 --- a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs +++ b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs @@ -821,8 +821,9 @@ convertLegacyPerPackageFlags , haddockContents = packageConfigHaddockContents , haddockIndex = packageConfigHaddockIndex , haddockBaseUrl = packageConfigHaddockBaseUrl - , haddockLib = packageConfigHaddockLib + , haddockResourcesDir = packageConfigHaddockResourcesDir , haddockOutputDir = packageConfigHaddockOutputDir + , haddockVersionCPP = packageConfigHaddockVersionCPP } = haddockFlags TestFlags @@ -1218,8 +1219,9 @@ convertToLegacyPerPackageConfig PackageConfig{..} = , haddockKeepTempFiles = mempty , haddockIndex = packageConfigHaddockIndex , haddockBaseUrl = packageConfigHaddockBaseUrl - , haddockLib = packageConfigHaddockLib + , haddockResourcesDir = packageConfigHaddockResourcesDir , haddockOutputDir = packageConfigHaddockOutputDir + , haddockVersionCPP = packageConfigHaddockVersionCPP } testFlags = @@ -1619,8 +1621,9 @@ legacyPackageConfigFieldDescrs = , "index-location" , "keep-temp-files" , "base-url" - , "lib" + , "resources-dir" , "output-dir" + , "version-cpp" ] . commandOptionsToFields ) diff --git a/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs b/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs index 3e8e3ba1b07..8fc4f2b21c3 100644 --- a/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs +++ b/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs @@ -305,8 +305,9 @@ data PackageConfig = PackageConfig , packageConfigHaddockContents :: Flag PathTemplate -- TODO: [required eventually] use this , packageConfigHaddockIndex :: Flag PathTemplate -- TODO: [required eventually] use this , packageConfigHaddockBaseUrl :: Flag String -- TODO: [required eventually] use this - , packageConfigHaddockLib :: Flag String -- TODO: [required eventually] use this + , packageConfigHaddockResourcesDir :: Flag String -- TODO: [required eventually] use this , packageConfigHaddockOutputDir :: Flag FilePath -- TODO: [required eventually] use this + , packageConfigHaddockVersionCPP :: Flag Bool -- TODO: [required eventually] use this , packageConfigHaddockForHackage :: Flag HaddockTarget , -- Test options packageConfigTestHumanLog :: Flag PathTemplate diff --git a/cabal-install/src/Distribution/Client/ProjectPlanning.hs b/cabal-install/src/Distribution/Client/ProjectPlanning.hs index ea4fae8ab8c..b5f5e94567d 100644 --- a/cabal-install/src/Distribution/Client/ProjectPlanning.hs +++ b/cabal-install/src/Distribution/Client/ProjectPlanning.hs @@ -2163,6 +2163,13 @@ elaborateInstallPlan elabBuildHaddocks = perPkgOptionFlag pkgid False packageConfigDocumentation + -- `documentation: true` should imply `-haddock` for GHC + addHaddockIfDocumentationEnabled :: ConfiguredProgram -> ConfiguredProgram + addHaddockIfDocumentationEnabled cp@ConfiguredProgram{..} = + if programId == "ghc" && elabBuildHaddocks + then cp{programOverrideArgs = "-haddock" : programOverrideArgs} + else cp + elabPkgSourceLocation = srcloc elabPkgSourceHash = Map.lookup pkgid sourcePackageHashes elabLocalToProject = isLocalToProject pkg @@ -2242,7 +2249,7 @@ elaborateInstallPlan Map.fromList [ (programId prog, args) | prog <- configuredPrograms compilerprogdb - , let args = programOverrideArgs prog + , let args = programOverrideArgs $ addHaddockIfDocumentationEnabled prog , not (null args) ] <> perPkgOptionMapMappend pkgid packageConfigProgramArgs @@ -2271,8 +2278,9 @@ elaborateInstallPlan elabHaddockContents = perPkgOptionMaybe pkgid packageConfigHaddockContents elabHaddockIndex = perPkgOptionMaybe pkgid packageConfigHaddockIndex elabHaddockBaseUrl = perPkgOptionMaybe pkgid packageConfigHaddockBaseUrl - elabHaddockLib = perPkgOptionMaybe pkgid packageConfigHaddockLib + elabHaddockResourcesDir = perPkgOptionMaybe pkgid packageConfigHaddockResourcesDir elabHaddockOutputDir = perPkgOptionMaybe pkgid packageConfigHaddockOutputDir + elabHaddockVersionCPP = perPkgOptionFlag pkgid False packageConfigHaddockVersionCPP elabTestMachineLog = perPkgOptionMaybe pkgid packageConfigTestMachineLog elabTestHumanLog = perPkgOptionMaybe pkgid packageConfigTestHumanLog @@ -4138,8 +4146,9 @@ setupHsHaddockFlags , haddockKeepTempFiles = toFlag keepTmpFiles , haddockIndex = maybe mempty toFlag elabHaddockIndex , haddockBaseUrl = maybe mempty toFlag elabHaddockBaseUrl - , haddockLib = maybe mempty toFlag elabHaddockLib + , haddockResourcesDir = maybe mempty toFlag elabHaddockResourcesDir , haddockOutputDir = maybe mempty toFlag elabHaddockOutputDir + , haddockVersionCPP = maybe mempty toFlag elabHaddockVersionCPP } setupHsHaddockArgs :: ElaboratedConfiguredPackage -> [String] @@ -4296,8 +4305,9 @@ packageHashConfigInputs shared@ElaboratedSharedConfig{..} pkg = , pkgHashHaddockContents = elabHaddockContents , pkgHashHaddockIndex = elabHaddockIndex , pkgHashHaddockBaseUrl = elabHaddockBaseUrl - , pkgHashHaddockLib = elabHaddockLib + , pkgHashHaddockResourcesDir = elabHaddockResourcesDir , pkgHashHaddockOutputDir = elabHaddockOutputDir + , pkgHashHaddockVersionCPP = elabHaddockVersionCPP } where ElaboratedConfiguredPackage{..} = normaliseConfiguredPackage shared pkg diff --git a/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs b/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs index 5b4896b0568..a5a3640457d 100644 --- a/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs +++ b/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs @@ -300,8 +300,9 @@ data ElaboratedConfiguredPackage = ElaboratedConfiguredPackage , elabHaddockContents :: Maybe PathTemplate , elabHaddockIndex :: Maybe PathTemplate , elabHaddockBaseUrl :: Maybe String - , elabHaddockLib :: Maybe String + , elabHaddockResourcesDir :: Maybe String , elabHaddockOutputDir :: Maybe FilePath + , elabHaddockVersionCPP :: Bool , elabTestMachineLog :: Maybe PathTemplate , elabTestHumanLog :: Maybe PathTemplate , elabTestShowDetails :: Maybe TestShowDetails diff --git a/cabal-install/src/Distribution/Client/Setup.hs b/cabal-install/src/Distribution/Client/Setup.hs index ae21e7f3799..d2992f5ad61 100644 --- a/cabal-install/src/Distribution/Client/Setup.hs +++ b/cabal-install/src/Distribution/Client/Setup.hs @@ -2435,8 +2435,9 @@ haddockOptions showOrParseArgs = , "use-index" , "for-hackage" , "base-url" - , "lib" + , "resources-dir" , "output-dir" + , "version-cpp" ] ] diff --git a/cabal-install/tests/IntegrationTests2.hs b/cabal-install/tests/IntegrationTests2.hs index a917e48efad..4021059fd64 100644 --- a/cabal-install/tests/IntegrationTests2.hs +++ b/cabal-install/tests/IntegrationTests2.hs @@ -2099,7 +2099,9 @@ testConfigOptionComments = do " -- contents-location" @=? findLineWith True "contents-location" defaultConfigFile " -- index-location" @=? findLineWith True "index-location" defaultConfigFile " -- base-url" @=? findLineWith True "base-url" defaultConfigFile + " -- resources-dir" @=? findLineWith True "resources-dir" defaultConfigFile " -- output-dir" @=? findLineWith True "output-dir" defaultConfigFile + " -- version-cpp" @=? findLineWith True "version-cpp" defaultConfigFile " -- interactive" @=? findLineWith True "interactive" defaultConfigFile " -- quiet" @=? findLineWith True "quiet" defaultConfigFile diff --git a/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs b/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs index abdc1e79390..47b4392e0d8 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs @@ -726,6 +726,7 @@ instance Arbitrary PackageConfig where <*> arbitrary <*> arbitrary <*> arbitrary + <*> arbitrary <*> arbitraryFlag arbitraryShortToken <*> arbitrary <*> shortListOf 5 arbitrary @@ -791,8 +792,9 @@ instance Arbitrary PackageConfig where , packageConfigHaddockForHackage = x41 , packageConfigHaddockIndex = x54 , packageConfigHaddockBaseUrl = x55 - , packageConfigHaddockLib = x56 + , packageConfigHaddockResourcesDir = x56 , packageConfigHaddockOutputDir = x57 + , packageConfigHaddockVersionCPP = x58 , packageConfigTestHumanLog = x44 , packageConfigTestMachineLog = x45 , packageConfigTestShowDetails = x46 @@ -854,8 +856,9 @@ instance Arbitrary PackageConfig where , packageConfigHaddockForHackage = x41' , packageConfigHaddockIndex = x54' , packageConfigHaddockBaseUrl = x55' - , packageConfigHaddockLib = x56' + , packageConfigHaddockResourcesDir = x56' , packageConfigHaddockOutputDir = x57' + , packageConfigHaddockVersionCPP = x58' , packageConfigTestHumanLog = x44' , packageConfigTestMachineLog = x45' , packageConfigTestShowDetails = x46' @@ -878,6 +881,7 @@ instance Arbitrary PackageConfig where , (x44', x45', x46', x47', x48', x49', x51', x52', x54', x55') , x56' , x57' + , x58' ) ) <- shrink @@ -903,6 +907,7 @@ instance Arbitrary PackageConfig where , (x44, x45, x46, x47, x48, x49, x51, x52, x54, x55) , x56 , x57 + , x58 ) ) ] diff --git a/cabal-testsuite/PackageTests/NewHaddock/Fails/cabal.out b/cabal-testsuite/PackageTests/NewHaddock/Fails/cabal.out index b1bcf12d3fa..bb0ee5b906d 100644 --- a/cabal-testsuite/PackageTests/NewHaddock/Fails/cabal.out +++ b/cabal-testsuite/PackageTests/NewHaddock/Fails/cabal.out @@ -11,7 +11,8 @@ Failed to build example-1.0-inplace. # cabal v2-haddock Build profile: -w ghc- -O1 In order, the following will be built: - - example-1.0 (lib) (first run) + - example-1.0 (lib) (configuration changed) +Configuring library for example-1.0... Preprocessing library for example-1.0... Running Haddock on library for example-1.0... Error: [Cabal-7125] diff --git a/changelog.d/pr-9177 b/changelog.d/pr-9177 new file mode 100644 index 00000000000..b4f205a1f32 --- /dev/null +++ b/changelog.d/pr-9177 @@ -0,0 +1,28 @@ +synopsis: Enable recompilation avoidance during Haddock generation +packages: cabal-install +prs: #9177 +issues: #9175 + +description: { + +* Haddock no longer writes compilation files by default, so we do not need to + pass tmp dirs for `-hidir`, `-stubdir`, and `-odir` via `--optghc`. Indeed, we + do not *want* to do so, since it results in recompilation for every invocation + of Haddock via Cabal. We now stop this from happening for Haddock versions + 2.28 and greater, since that is when Hi Haddock was introduced. + +* We no longer define the `__HADDOCK_VERSION__` macro when invoking GHC through + Haddock, since doing so essentially guarantees recompilation during + documentation generation. Since a very limited set of users may still rely on + this flag, we introduce the `--haddock-version-cpp` flag and + `haddock-version-cpp:` cabal.project field, which enables the definition of + the `__HADDOCK_VERSION__` macro when invoking GHC through Haddock. + +* Rename the `--haddock-lib` flag to `--haddock-resources-dir` (and + `haddock-lib:` cabal.project field to `haddock-resources-dir:`), and add this + flag to the users guide since it was missing an entry. + +* `documentation: true` or `--enable-documentation` now implies `-haddock` for + GHC. + +} diff --git a/doc/cabal-project-description-file.rst b/doc/cabal-project-description-file.rst index b76d383dacc..16fce6b4545 100644 --- a/doc/cabal-project-description-file.rst +++ b/doc/cabal-project-description-file.rst @@ -1610,6 +1610,25 @@ running ``setup haddock``. This flag is provided as a technology preview and is subject to change in the next releases. +.. cfg-field:: haddock-resources-dir: DIR + --haddock-resources-dir=DIR + :synopsis: Location of Haddock's static/auxiliary files. + + Location of Haddock's static/auxiliary files. For Haddock distributed with + GHC (or, more precisely, built within the GHC source tree), this path should + be automatically inferred. For Haddock built from source, however, this path + should likely be explicitly set for every Haddock invocation. + +.. cfg-field:: haddock-no-version-cpp: boolean + --haddock-no-version-cpp + :synopsis: Do not define the ``__HADDOCK_VERSION__`` macro when invoking GHC + through Haddock. + + Do not define the ``__HADDOCK_VERSION__`` macro when invoking GHC through + Haddock. This is critical for avoiding recompilation during documentation + generation, since such a macro definition will trigger recompilation if the + interface files on disk were compiled without it, as they likely were. + .. cfg-field:: open: boolean --open :synopsis: Open generated documentation in-browser. diff --git a/test/IntegrationTests2/config/default-config b/test/IntegrationTests2/config/default-config index 8e3aa02742c..1e4301a14ea 100644 --- a/test/IntegrationTests2/config/default-config +++ b/test/IntegrationTests2/config/default-config @@ -33,8 +33,8 @@ remote-repo-cache: /home/colton/.cabal/packages -- cabal-file: -- with-compiler: -- with-hc-pkg: --- program-prefix: --- program-suffix: +-- program-prefix: +-- program-suffix: -- library-vanilla: True -- library-profiling: -- shared: @@ -141,8 +141,9 @@ haddock -- contents-location: -- index-location: -- base-url: - -- lib: + -- resources-dir: -- output-dir: + -- version-cpp: False init -- interactive: False diff --git a/test/IntegrationTests2/nix-config/default-config b/test/IntegrationTests2/nix-config/default-config index 8e3aa02742c..1e4301a14ea 100644 --- a/test/IntegrationTests2/nix-config/default-config +++ b/test/IntegrationTests2/nix-config/default-config @@ -33,8 +33,8 @@ remote-repo-cache: /home/colton/.cabal/packages -- cabal-file: -- with-compiler: -- with-hc-pkg: --- program-prefix: --- program-suffix: +-- program-prefix: +-- program-suffix: -- library-vanilla: True -- library-profiling: -- shared: @@ -141,8 +141,9 @@ haddock -- contents-location: -- index-location: -- base-url: - -- lib: + -- resources-dir: -- output-dir: + -- version-cpp: False init -- interactive: False diff --git a/tests/IntegrationTests2/config/default-config b/tests/IntegrationTests2/config/default-config index 8e3aa02742c..cd2dcc601e2 100644 --- a/tests/IntegrationTests2/config/default-config +++ b/tests/IntegrationTests2/config/default-config @@ -25,8 +25,8 @@ repository hackage.haskell.org -- store-dir: -- active-repositories: -- local-no-index-repo: -remote-repo-cache: /home/colton/.cabal/packages --- logs-dir: /home/colton/.cabal/logs +remote-repo-cache: /Users/finley/.cabal/packages +-- logs-dir: /Users/finley/.cabal/logs -- default-user-config: -- verbose: 1 -- compiler: ghc @@ -63,7 +63,7 @@ remote-repo-cache: /home/colton/.cabal/packages -- extra-lib-dirs: -- extra-lib-dirs-static: -- extra-framework-dirs: -extra-prog-path: /home/colton/.cabal/bin +-- extra-prog-path: -- instantiate-with: -- tests: False -- coverage: False @@ -104,12 +104,13 @@ extra-prog-path: /home/colton/.cabal/bin -- index-state: -- root-cmd: -- symlink-bindir: -build-summary: /home/colton/.cabal/logs/build.log +build-summary: /Users/finley/.cabal/logs/build.log -- build-log: remote-build-reporting: none -- report-planning-failure: False -- per-component: True -- run-tests: +-- semaphore: False jobs: $ncpus -- keep-going: False -- offline: False @@ -117,10 +118,11 @@ jobs: $ncpus -- package-env: -- overwrite-policy: -- install-method: -installdir: /home/colton/.cabal/bin +installdir: /Users/finley/.cabal/bin -- username: -- password: -- password-command: +-- multi-repl: -- builddir: haddock @@ -141,8 +143,9 @@ haddock -- contents-location: -- index-location: -- base-url: - -- lib: + -- resources-dir: -- output-dir: + -- version-cpp: False init -- interactive: False @@ -160,7 +163,7 @@ init -- source-dir: src install-dirs user - -- prefix: /home/colton/.cabal + -- prefix: /Users/finley/.cabal -- bindir: $prefix/bin -- libdir: $prefix/lib -- libsubdir: $abi/$libname diff --git a/tests/IntegrationTests2/nix-config/default-config b/tests/IntegrationTests2/nix-config/default-config index 8e3aa02742c..1e4301a14ea 100644 --- a/tests/IntegrationTests2/nix-config/default-config +++ b/tests/IntegrationTests2/nix-config/default-config @@ -33,8 +33,8 @@ remote-repo-cache: /home/colton/.cabal/packages -- cabal-file: -- with-compiler: -- with-hc-pkg: --- program-prefix: --- program-suffix: +-- program-prefix: +-- program-suffix: -- library-vanilla: True -- library-profiling: -- shared: @@ -141,8 +141,9 @@ haddock -- contents-location: -- index-location: -- base-url: - -- lib: + -- resources-dir: -- output-dir: + -- version-cpp: False init -- interactive: False From 144383e8371c499ca3a04c949d16d03829db8b18 Mon Sep 17 00:00:00 2001 From: Rodrigo Mesquita Date: Thu, 16 May 2024 14:21:35 +0100 Subject: [PATCH 2/4] Cabal: Don't pass -D__HADDOCK_VERSION__ to haddock We no longer define the `__HADDOCK_VERSION__` macro when invoking GHC through Haddock, since doing so essentially guarantees recompilation during documentation generation. We audited all uses of `__HADDOCK_VERSION__` in hackage, ensuring there was a reasonable path forward to migrate away from using `__HADDOCK_VERSION__` for each, while generating the same documentation as it did before. If you are a user of `__HADDOCK_VERSION__`, please take a look at the discussion in https://github.com/haskell/cabal/pull/9177 and reach out to us if your use case is not covered. Reverts the version-cpp flag introduced in the previous commit to avoid a workaround. Instead, we get rid of the problem (`__HADDOCK_VERSION__`) at its root. See the discussion in #9177 --- Cabal/src/Distribution/Simple/Haddock.hs | 65 ++----------------- .../src/Distribution/Simple/Setup/Haddock.hs | 18 ----- .../Distribution/Client/CmdHaddockProject.hs | 1 - .../src/Distribution/Client/Config.hs | 1 - .../src/Distribution/Client/PackageHash.hs | 2 - .../Client/ProjectConfig/Legacy.hs | 3 - .../Client/ProjectConfig/Types.hs | 1 - .../Distribution/Client/ProjectPlanning.hs | 3 - .../Client/ProjectPlanning/Types.hs | 1 - .../src/Distribution/Client/Setup.hs | 1 - cabal-install/tests/IntegrationTests2.hs | 1 - .../Distribution/Client/ProjectConfig.hs | 5 -- changelog.d/pr-9177 | 11 ++-- doc/cabal-project-description-file.rst | 10 --- release-notes/WIP-Cabal-3.12.x.0.md | 19 ++++++ test/IntegrationTests2/config/default-config | 1 - .../nix-config/default-config | 1 - tests/IntegrationTests2/config/default-config | 1 - .../nix-config/default-config | 1 - 19 files changed, 30 insertions(+), 116 deletions(-) create mode 100644 release-notes/WIP-Cabal-3.12.x.0.md diff --git a/Cabal/src/Distribution/Simple/Haddock.hs b/Cabal/src/Distribution/Simple/Haddock.hs index 8c6fd86a691..e8537e97eb3 100644 --- a/Cabal/src/Distribution/Simple/Haddock.hs +++ b/Cabal/src/Distribution/Simple/Haddock.hs @@ -83,7 +83,6 @@ import Distribution.Types.ComponentLocalBuildInfo import Distribution.Types.ExposedModule import Distribution.Types.LocalBuildInfo import Distribution.Types.TargetInfo -import Distribution.Utils.NubList import Distribution.Utils.Path hiding ( Dir ) @@ -92,8 +91,6 @@ import qualified Distribution.Utils.ShortText as ShortText import Distribution.Verbosity import Distribution.Version -import Language.Haskell.Extension - import Control.Monad import Data.Either (rights) import System.Directory (doesDirectoryExist, doesFileExist) @@ -329,11 +326,6 @@ haddock_setupHooks [] -> allTargetsInBuildOrder' pkg_descr lbi _ -> targets - version' = - if flag haddockVersionCPP - then Just version - else Nothing - mtmp | version >= mkVersion [2, 28, 0] = const Nothing | otherwise = Just @@ -380,7 +372,6 @@ haddock_setupHooks lbi' clbi htmlTemplate - version' exe let exeArgs' = commonArgs `mappend` exeArgs runHaddock @@ -420,7 +411,6 @@ haddock_setupHooks lbi' clbi htmlTemplate - version' lib let libArgs' = commonArgs `mappend` libArgs runHaddock verbosity mbWorkDir tmpFileOpts comp platform haddockProg True libArgs' @@ -467,7 +457,6 @@ haddock_setupHooks lbi' clbi htmlTemplate - version' flib let libArgs' = commonArgs `mappend` flibArgs runHaddock verbosity mbWorkDir tmpFileOpts comp platform haddockProg True libArgs' @@ -613,17 +602,13 @@ mkHaddockArgs -> ComponentLocalBuildInfo -> Maybe PathTemplate -- ^ template for HTML location - -> Maybe Version - -- ^ 'Nothing' if the user requested not to define the __HADDOCK_VERSION__ - -- macro -> [SymbolicPath Pkg File] -> BuildInfo -> IO HaddockArgs -mkHaddockArgs verbosity mtmp lbi clbi htmlTemplate haddockVersion inFiles bi = do +mkHaddockArgs verbosity mtmp lbi clbi htmlTemplate inFiles bi = do ifaceArgs <- getInterfaces verbosity lbi clbi htmlTemplate let vanillaOpts' = componentGhcOptions normal lbi bi clbi (buildDir lbi) - `mappend` getGhcCppOpts haddockVersion bi vanillaOpts = vanillaOpts' { -- Starting with Haddock 2.28, we no longer want to run Haddock's @@ -635,7 +620,6 @@ mkHaddockArgs verbosity mtmp lbi clbi htmlTemplate haddockVersion inFiles bi = d , ghcOptHiDir = maybe (ghcOptHiDir vanillaOpts') (toFlag . coerceSymbolicPath) mtmp , ghcOptStubDir = maybe (ghcOptStubDir vanillaOpts') (toFlag . coerceSymbolicPath) mtmp } - `mappend` getGhcCppOpts haddockVersion bi sharedOpts = vanillaOpts { ghcOptDynLinkMode = toFlag GhcDynamicOnly @@ -668,12 +652,9 @@ fromLibrary -> ComponentLocalBuildInfo -> Maybe PathTemplate -- ^ template for HTML location - -> Maybe Version - -- ^ 'Nothing' if the user requested not to define the __HADDOCK_VERSION__ - -- macro -> Library -> IO HaddockArgs -fromLibrary verbosity mtmp lbi clbi htmlTemplate haddockVersion lib = do +fromLibrary verbosity mtmp lbi clbi htmlTemplate lib = do inFiles <- map snd `fmap` getLibSourceFiles verbosity lbi lib clbi args <- mkHaddockArgs @@ -682,7 +663,6 @@ fromLibrary verbosity mtmp lbi clbi htmlTemplate haddockVersion lib = do lbi clbi htmlTemplate - haddockVersion inFiles (libBuildInfo lib) return @@ -699,12 +679,9 @@ fromExecutable -> ComponentLocalBuildInfo -> Maybe PathTemplate -- ^ template for HTML location - -> Maybe Version - -- ^ 'Nothing' if the user requested not to define the __HADDOCK_VERSION__ - -- macro -> Executable -> IO HaddockArgs -fromExecutable verbosity mtmp lbi clbi htmlTemplate haddockVersion exe = do +fromExecutable verbosity mtmp lbi clbi htmlTemplate exe = do inFiles <- map snd `fmap` getExeSourceFiles verbosity lbi exe clbi args <- mkHaddockArgs @@ -713,7 +690,6 @@ fromExecutable verbosity mtmp lbi clbi htmlTemplate haddockVersion exe = do lbi clbi htmlTemplate - haddockVersion inFiles (buildInfo exe) return @@ -731,12 +707,9 @@ fromForeignLib -> ComponentLocalBuildInfo -> Maybe PathTemplate -- ^ template for HTML location - -> Maybe Version - -- ^ 'Nothing' if the user requested not to define the __HADDOCK_VERSION__ - -- macro -> ForeignLib -> IO HaddockArgs -fromForeignLib verbosity mtmp lbi clbi htmlTemplate haddockVersion flib = do +fromForeignLib verbosity mtmp lbi clbi htmlTemplate flib = do inFiles <- map snd `fmap` getFLibSourceFiles verbosity lbi flib clbi args <- mkHaddockArgs @@ -745,7 +718,6 @@ fromForeignLib verbosity mtmp lbi clbi htmlTemplate haddockVersion flib = do lbi clbi htmlTemplate - haddockVersion inFiles (foreignLibBuildInfo flib) return @@ -796,35 +768,6 @@ getReexports LibComponentLocalBuildInfo{componentExposedModules = mods} = mapMaybe exposedReexport mods getReexports _ = [] -getGhcCppOpts - :: Maybe Version - -- ^ 'Nothing' if the user requested not to define the __HADDOCK_VERSION__ - -- macro - -> BuildInfo - -> GhcOptions -getGhcCppOpts haddockVersion bi = - mempty - { ghcOptExtensions = toNubListR [EnableExtension CPP | needsCpp] - , ghcOptCppOptions = defines - } - where - needsCpp = EnableExtension CPP `elem` usedExtensions bi - defines = - [ "-D__HADDOCK_VERSION__=" ++ show vn - | Just vn <- [versionInt . versionNumbers <$> haddockVersion] - ] - where - -- For some list xs = [x, y, z ...], versionInt xs results in - -- x * 1000 + y * 10 + z. E.g.: - -- >>> versionInt [2, 29, 0] - -- 2290 - -- >>> versionInt [3, 4] - -- 3040 - -- >>> versionInt [] - -- 0 - versionInt :: [Int] -> Int - versionInt = foldr ((+) . uncurry (*)) 0 . zip [1000, 10, 1] - getGhcLibDir :: Verbosity -> LocalBuildInfo diff --git a/Cabal/src/Distribution/Simple/Setup/Haddock.hs b/Cabal/src/Distribution/Simple/Setup/Haddock.hs index 5b1a6a0999e..402544ce511 100644 --- a/Cabal/src/Distribution/Simple/Setup/Haddock.hs +++ b/Cabal/src/Distribution/Simple/Setup/Haddock.hs @@ -115,7 +115,6 @@ data HaddockFlags = HaddockFlags , haddockBaseUrl :: Flag String , haddockResourcesDir :: Flag String , haddockOutputDir :: Flag FilePath - , haddockVersionCPP :: Flag Bool } deriving (Show, Generic, Typeable) @@ -171,7 +170,6 @@ defaultHaddockFlags = , haddockBaseUrl = NoFlag , haddockResourcesDir = NoFlag , haddockOutputDir = NoFlag - , haddockVersionCPP = Flag False } haddockCommand :: CommandUI HaddockFlags @@ -380,13 +378,6 @@ haddockOptions showOrParseArgs = haddockOutputDir (\v flags -> flags{haddockOutputDir = v}) (reqArgFlag "DIR") - , option - "" - ["version-cpp"] - "Define the __HADDOCK_VERSION__ macro when invoking GHC through Haddock. This will likely trigger recompilation during documentation generation." - haddockVersionCPP - (\v flags -> flags{haddockVersionCPP = v}) - trueArg ] emptyHaddockFlags :: HaddockFlags @@ -451,7 +442,6 @@ data HaddockProjectFlags = HaddockProjectFlags , -- haddockBaseUrl is not supported, a fixed value is provided haddockProjectResourcesDir :: Flag String , haddockProjectOutputDir :: Flag FilePath - , haddockProjectVersionCPP :: Flag Bool } deriving (Show, Generic, Typeable) @@ -477,7 +467,6 @@ defaultHaddockProjectFlags = , haddockProjectResourcesDir = NoFlag , haddockProjectOutputDir = NoFlag , haddockProjectInterfaces = NoFlag - , haddockProjectVersionCPP = Flag False } haddockProjectCommand :: CommandUI HaddockProjectFlags @@ -631,13 +620,6 @@ haddockProjectOptions _showOrParseArgs = haddockProjectOutputDir (\v flags -> flags{haddockProjectOutputDir = v}) (reqArgFlag "DIR") - , option - "" - ["version-cpp"] - "Define the __HADDOCK_VERSION__ macro when invoking GHC through Haddock. This will likely trigger recompilation during documentation generation." - haddockProjectVersionCPP - (\v flags -> flags{haddockProjectVersionCPP = v}) - trueArg ] emptyHaddockProjectFlags :: HaddockProjectFlags diff --git a/cabal-install/src/Distribution/Client/CmdHaddockProject.hs b/cabal-install/src/Distribution/Client/CmdHaddockProject.hs index c2f31c6300a..8c0c21a5427 100644 --- a/cabal-install/src/Distribution/Client/CmdHaddockProject.hs +++ b/cabal-install/src/Distribution/Client/CmdHaddockProject.hs @@ -150,7 +150,6 @@ haddockProjectAction flags _extraArgs globalFlags = do , haddockKeepTempFiles = haddockProjectKeepTempFiles flags , haddockResourcesDir = haddockProjectResourcesDir flags , haddockOutputDir = haddockProjectOutputDir flags - , haddockVersionCPP = haddockProjectVersionCPP flags } nixFlags = (commandDefaultFlags CmdHaddock.haddockCommand) diff --git a/cabal-install/src/Distribution/Client/Config.hs b/cabal-install/src/Distribution/Client/Config.hs index 454c765b911..d9b91c959d0 100644 --- a/cabal-install/src/Distribution/Client/Config.hs +++ b/cabal-install/src/Distribution/Client/Config.hs @@ -632,7 +632,6 @@ instance Semigroup SavedConfig where , haddockBaseUrl = combine haddockBaseUrl , haddockResourcesDir = combine haddockResourcesDir , haddockOutputDir = combine haddockOutputDir - , haddockVersionCPP = combine haddockVersionCPP } where combine = combine' savedHaddockFlags diff --git a/cabal-install/src/Distribution/Client/PackageHash.hs b/cabal-install/src/Distribution/Client/PackageHash.hs index 5ced7e1823a..2e7b9320e3d 100644 --- a/cabal-install/src/Distribution/Client/PackageHash.hs +++ b/cabal-install/src/Distribution/Client/PackageHash.hs @@ -240,7 +240,6 @@ data PackageHashConfigInputs = PackageHashConfigInputs , pkgHashHaddockBaseUrl :: Maybe String , pkgHashHaddockResourcesDir :: Maybe String , pkgHashHaddockOutputDir :: Maybe FilePath - , pkgHashHaddockVersionCPP :: Bool -- TODO: [required eventually] pkgHashToolsVersions ? -- TODO: [required eventually] pkgHashToolsExtraOptions ? } @@ -350,7 +349,6 @@ renderPackageHashInputs , opt "haddock-base-url" Nothing (fromMaybe "") pkgHashHaddockBaseUrl , opt "haddock-resources-dir" Nothing (fromMaybe "") pkgHashHaddockResourcesDir , opt "haddock-output-dir" Nothing (fromMaybe "") pkgHashHaddockOutputDir - , opt "haddock-version-cpp" False prettyShow pkgHashHaddockVersionCPP ] ++ Map.foldrWithKey (\prog args acc -> opt (prog ++ "-options") [] unwords args : acc) [] pkgHashProgramArgs where diff --git a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs index 50e7f0feb9a..ddb6f615264 100644 --- a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs +++ b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs @@ -823,7 +823,6 @@ convertLegacyPerPackageFlags , haddockBaseUrl = packageConfigHaddockBaseUrl , haddockResourcesDir = packageConfigHaddockResourcesDir , haddockOutputDir = packageConfigHaddockOutputDir - , haddockVersionCPP = packageConfigHaddockVersionCPP } = haddockFlags TestFlags @@ -1221,7 +1220,6 @@ convertToLegacyPerPackageConfig PackageConfig{..} = , haddockBaseUrl = packageConfigHaddockBaseUrl , haddockResourcesDir = packageConfigHaddockResourcesDir , haddockOutputDir = packageConfigHaddockOutputDir - , haddockVersionCPP = packageConfigHaddockVersionCPP } testFlags = @@ -1623,7 +1621,6 @@ legacyPackageConfigFieldDescrs = , "base-url" , "resources-dir" , "output-dir" - , "version-cpp" ] . commandOptionsToFields ) diff --git a/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs b/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs index 8fc4f2b21c3..2a6f9589cbb 100644 --- a/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs +++ b/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs @@ -307,7 +307,6 @@ data PackageConfig = PackageConfig , packageConfigHaddockBaseUrl :: Flag String -- TODO: [required eventually] use this , packageConfigHaddockResourcesDir :: Flag String -- TODO: [required eventually] use this , packageConfigHaddockOutputDir :: Flag FilePath -- TODO: [required eventually] use this - , packageConfigHaddockVersionCPP :: Flag Bool -- TODO: [required eventually] use this , packageConfigHaddockForHackage :: Flag HaddockTarget , -- Test options packageConfigTestHumanLog :: Flag PathTemplate diff --git a/cabal-install/src/Distribution/Client/ProjectPlanning.hs b/cabal-install/src/Distribution/Client/ProjectPlanning.hs index b5f5e94567d..43c835f7a0d 100644 --- a/cabal-install/src/Distribution/Client/ProjectPlanning.hs +++ b/cabal-install/src/Distribution/Client/ProjectPlanning.hs @@ -2280,7 +2280,6 @@ elaborateInstallPlan elabHaddockBaseUrl = perPkgOptionMaybe pkgid packageConfigHaddockBaseUrl elabHaddockResourcesDir = perPkgOptionMaybe pkgid packageConfigHaddockResourcesDir elabHaddockOutputDir = perPkgOptionMaybe pkgid packageConfigHaddockOutputDir - elabHaddockVersionCPP = perPkgOptionFlag pkgid False packageConfigHaddockVersionCPP elabTestMachineLog = perPkgOptionMaybe pkgid packageConfigTestMachineLog elabTestHumanLog = perPkgOptionMaybe pkgid packageConfigTestHumanLog @@ -4148,7 +4147,6 @@ setupHsHaddockFlags , haddockBaseUrl = maybe mempty toFlag elabHaddockBaseUrl , haddockResourcesDir = maybe mempty toFlag elabHaddockResourcesDir , haddockOutputDir = maybe mempty toFlag elabHaddockOutputDir - , haddockVersionCPP = maybe mempty toFlag elabHaddockVersionCPP } setupHsHaddockArgs :: ElaboratedConfiguredPackage -> [String] @@ -4307,7 +4305,6 @@ packageHashConfigInputs shared@ElaboratedSharedConfig{..} pkg = , pkgHashHaddockBaseUrl = elabHaddockBaseUrl , pkgHashHaddockResourcesDir = elabHaddockResourcesDir , pkgHashHaddockOutputDir = elabHaddockOutputDir - , pkgHashHaddockVersionCPP = elabHaddockVersionCPP } where ElaboratedConfiguredPackage{..} = normaliseConfiguredPackage shared pkg diff --git a/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs b/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs index a5a3640457d..352e35d4150 100644 --- a/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs +++ b/cabal-install/src/Distribution/Client/ProjectPlanning/Types.hs @@ -302,7 +302,6 @@ data ElaboratedConfiguredPackage = ElaboratedConfiguredPackage , elabHaddockBaseUrl :: Maybe String , elabHaddockResourcesDir :: Maybe String , elabHaddockOutputDir :: Maybe FilePath - , elabHaddockVersionCPP :: Bool , elabTestMachineLog :: Maybe PathTemplate , elabTestHumanLog :: Maybe PathTemplate , elabTestShowDetails :: Maybe TestShowDetails diff --git a/cabal-install/src/Distribution/Client/Setup.hs b/cabal-install/src/Distribution/Client/Setup.hs index d2992f5ad61..8fea76bae3b 100644 --- a/cabal-install/src/Distribution/Client/Setup.hs +++ b/cabal-install/src/Distribution/Client/Setup.hs @@ -2437,7 +2437,6 @@ haddockOptions showOrParseArgs = , "base-url" , "resources-dir" , "output-dir" - , "version-cpp" ] ] diff --git a/cabal-install/tests/IntegrationTests2.hs b/cabal-install/tests/IntegrationTests2.hs index 4021059fd64..b5b49053b6d 100644 --- a/cabal-install/tests/IntegrationTests2.hs +++ b/cabal-install/tests/IntegrationTests2.hs @@ -2101,7 +2101,6 @@ testConfigOptionComments = do " -- base-url" @=? findLineWith True "base-url" defaultConfigFile " -- resources-dir" @=? findLineWith True "resources-dir" defaultConfigFile " -- output-dir" @=? findLineWith True "output-dir" defaultConfigFile - " -- version-cpp" @=? findLineWith True "version-cpp" defaultConfigFile " -- interactive" @=? findLineWith True "interactive" defaultConfigFile " -- quiet" @=? findLineWith True "quiet" defaultConfigFile diff --git a/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs b/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs index 47b4392e0d8..946e0bf48fd 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs @@ -726,7 +726,6 @@ instance Arbitrary PackageConfig where <*> arbitrary <*> arbitrary <*> arbitrary - <*> arbitrary <*> arbitraryFlag arbitraryShortToken <*> arbitrary <*> shortListOf 5 arbitrary @@ -794,7 +793,6 @@ instance Arbitrary PackageConfig where , packageConfigHaddockBaseUrl = x55 , packageConfigHaddockResourcesDir = x56 , packageConfigHaddockOutputDir = x57 - , packageConfigHaddockVersionCPP = x58 , packageConfigTestHumanLog = x44 , packageConfigTestMachineLog = x45 , packageConfigTestShowDetails = x46 @@ -858,7 +856,6 @@ instance Arbitrary PackageConfig where , packageConfigHaddockBaseUrl = x55' , packageConfigHaddockResourcesDir = x56' , packageConfigHaddockOutputDir = x57' - , packageConfigHaddockVersionCPP = x58' , packageConfigTestHumanLog = x44' , packageConfigTestMachineLog = x45' , packageConfigTestShowDetails = x46' @@ -881,7 +878,6 @@ instance Arbitrary PackageConfig where , (x44', x45', x46', x47', x48', x49', x51', x52', x54', x55') , x56' , x57' - , x58' ) ) <- shrink @@ -907,7 +903,6 @@ instance Arbitrary PackageConfig where , (x44, x45, x46, x47, x48, x49, x51, x52, x54, x55) , x56 , x57 - , x58 ) ) ] diff --git a/changelog.d/pr-9177 b/changelog.d/pr-9177 index b4f205a1f32..6b1eb227350 100644 --- a/changelog.d/pr-9177 +++ b/changelog.d/pr-9177 @@ -13,10 +13,13 @@ description: { * We no longer define the `__HADDOCK_VERSION__` macro when invoking GHC through Haddock, since doing so essentially guarantees recompilation during - documentation generation. Since a very limited set of users may still rely on - this flag, we introduce the `--haddock-version-cpp` flag and - `haddock-version-cpp:` cabal.project field, which enables the definition of - the `__HADDOCK_VERSION__` macro when invoking GHC through Haddock. + documentation generation. We audited all uses of `__HADDOCK_VERSION__` in + hackage, ensuring there was a reasonable path forward to migrate away from + using `__HADDOCK_VERSION__` for each, while generating the same documentation + as it did before. + If you are a user of `__HADDOCK_VERSION__`, please take a look at the + discussion in https://github.com/haskell/cabal/pull/9177 and reach out to us + if your use case is not covered. * Rename the `--haddock-lib` flag to `--haddock-resources-dir` (and `haddock-lib:` cabal.project field to `haddock-resources-dir:`), and add this diff --git a/doc/cabal-project-description-file.rst b/doc/cabal-project-description-file.rst index 16fce6b4545..c1f29bfc052 100644 --- a/doc/cabal-project-description-file.rst +++ b/doc/cabal-project-description-file.rst @@ -1619,16 +1619,6 @@ running ``setup haddock``. be automatically inferred. For Haddock built from source, however, this path should likely be explicitly set for every Haddock invocation. -.. cfg-field:: haddock-no-version-cpp: boolean - --haddock-no-version-cpp - :synopsis: Do not define the ``__HADDOCK_VERSION__`` macro when invoking GHC - through Haddock. - - Do not define the ``__HADDOCK_VERSION__`` macro when invoking GHC through - Haddock. This is critical for avoiding recompilation during documentation - generation, since such a macro definition will trigger recompilation if the - interface files on disk were compiled without it, as they likely were. - .. cfg-field:: open: boolean --open :synopsis: Open generated documentation in-browser. diff --git a/release-notes/WIP-Cabal-3.12.x.0.md b/release-notes/WIP-Cabal-3.12.x.0.md new file mode 100644 index 00000000000..d1f2d17f04f --- /dev/null +++ b/release-notes/WIP-Cabal-3.12.x.0.md @@ -0,0 +1,19 @@ +Cabal 3.12.1.0 changelog and release notes. + +This file will be edited and the changes incorprated into the official +3.12.1.0 Cabal and Cabal-syntax release notes. + +--- + +### Significant changes + +- Deprecation of the `__HADDOCK_VERSION__` macro: + In the next major version of Cabal, we no longer define the + `__HADDOCK_VERSION__` macro when invoking GHC through Haddock, since doing + so essentially guarantees recompilation during documentation generation. We + audited all uses of `__HADDOCK_VERSION__` in hackage, ensuring there was a + reasonable path forward to migrate away from using `__HADDOCK_VERSION__` for + each, while generating the same documentation as it did before. If you are + a user of `__HADDOCK_VERSION__`, please take a look at the discussion in + https://github.com/haskell/cabal/pull/9177 and reach out to us if your use + case is not covered. diff --git a/test/IntegrationTests2/config/default-config b/test/IntegrationTests2/config/default-config index 1e4301a14ea..e74a2c97764 100644 --- a/test/IntegrationTests2/config/default-config +++ b/test/IntegrationTests2/config/default-config @@ -143,7 +143,6 @@ haddock -- base-url: -- resources-dir: -- output-dir: - -- version-cpp: False init -- interactive: False diff --git a/test/IntegrationTests2/nix-config/default-config b/test/IntegrationTests2/nix-config/default-config index 1e4301a14ea..e74a2c97764 100644 --- a/test/IntegrationTests2/nix-config/default-config +++ b/test/IntegrationTests2/nix-config/default-config @@ -143,7 +143,6 @@ haddock -- base-url: -- resources-dir: -- output-dir: - -- version-cpp: False init -- interactive: False diff --git a/tests/IntegrationTests2/config/default-config b/tests/IntegrationTests2/config/default-config index cd2dcc601e2..8d5b2ea1df6 100644 --- a/tests/IntegrationTests2/config/default-config +++ b/tests/IntegrationTests2/config/default-config @@ -145,7 +145,6 @@ haddock -- base-url: -- resources-dir: -- output-dir: - -- version-cpp: False init -- interactive: False diff --git a/tests/IntegrationTests2/nix-config/default-config b/tests/IntegrationTests2/nix-config/default-config index 1e4301a14ea..e74a2c97764 100644 --- a/tests/IntegrationTests2/nix-config/default-config +++ b/tests/IntegrationTests2/nix-config/default-config @@ -143,7 +143,6 @@ haddock -- base-url: -- resources-dir: -- output-dir: - -- version-cpp: False init -- interactive: False From 68fcd33d73af7e345e6ebd2af074cb77cd62c715 Mon Sep 17 00:00:00 2001 From: Rodrigo Mesquita Date: Thu, 16 May 2024 16:06:29 +0100 Subject: [PATCH 3/4] haddock: Pass --no-tmp-comp-dir by default With "Hi Haddock", we want to re-use GHC's compilation output (in particular, the generated interface files) to generate documentation from. However, haddock by default will use a temporary location to build sources, and will therefore fail to find the interface files produced by GHC. To avoid recompilation, we need to instruct Cabal to pass --no-tmp-comp-dir to Haddock so as to not use a temporary directory and thus re-use existing interface files. --- Cabal/src/Distribution/Simple/Haddock.hs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Cabal/src/Distribution/Simple/Haddock.hs b/Cabal/src/Distribution/Simple/Haddock.hs index e8537e97eb3..6776ef7e78e 100644 --- a/Cabal/src/Distribution/Simple/Haddock.hs +++ b/Cabal/src/Distribution/Simple/Haddock.hs @@ -326,6 +326,7 @@ haddock_setupHooks [] -> allTargetsInBuildOrder' pkg_descr lbi _ -> targets + -- See Note [Hi Haddock Recompilation Avoidance] mtmp | version >= mkVersion [2, 28, 0] = const Nothing | otherwise = Just @@ -593,6 +594,17 @@ componentGhcOptions verbosity lbi bi clbi odir = ++ "haddock only supports GHC and GHCJS" in f verbosity lbi bi clbi odir +{- +Note [Hi Haddock Recompilation Avoidance] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Starting with Haddock 2.28, we no longer want to run Haddock's +GHC session in a temporary directory. Doing so always causes +recompilation during documentation generation, which can now be +avoided thanks to Hi Haddock. + +See https://github.com/haskell/cabal/pull/9177 for discussion. +-} + mkHaddockArgs :: Verbosity -> Maybe (SymbolicPath Pkg (Path.Dir Tmp)) @@ -611,11 +623,7 @@ mkHaddockArgs verbosity mtmp lbi clbi htmlTemplate inFiles bi = do componentGhcOptions normal lbi bi clbi (buildDir lbi) vanillaOpts = vanillaOpts' - { -- Starting with Haddock 2.28, we no longer want to run Haddock's - -- GHC session in a temporary directory. Doing so always causes - -- recompilation during documentation generation, which can now be - -- avoided thanks to Hi Haddock. See - -- https://github.com/haskell/cabal/pull/9177 for discussion. + { -- See Note [Hi Haddock Recompilation Avoidance] ghcOptObjDir = maybe (ghcOptObjDir vanillaOpts') (toFlag . coerceSymbolicPath) mtmp , ghcOptHiDir = maybe (ghcOptHiDir vanillaOpts') (toFlag . coerceSymbolicPath) mtmp , ghcOptStubDir = maybe (ghcOptStubDir vanillaOpts') (toFlag . coerceSymbolicPath) mtmp @@ -973,6 +981,10 @@ renderPureArgs version comp platform args = ] , argTargets $ args , maybe [] ((: []) . (resourcesDirFlag ++)) . flagToMaybe . argResourcesDir $ args + -- Do not re-direct compilation output to a temporary directory (--no-tmp-comp-dir) + -- We pass this option by default to haddock to avoid recompilation + -- See Note [Hi Haddock Recompilation Avoidance] + , [ "--no-tmp-comp-dir" | version >= mkVersion [2, 28, 0] ] ] where -- See Note [Symbolic paths] in Distribution.Utils.Path From a1e14a7d3a93fa8915a39c9474c2197920bc2b5c Mon Sep 17 00:00:00 2001 From: Rodrigo Mesquita Date: Fri, 17 May 2024 14:01:02 +0100 Subject: [PATCH 4/4] haddock: Copy interface files to tmp dir In the last commits we started re-using GHC's interface files and objects in haddock in order to avoid recompilation. However, if haddock is run with different flags than GHC (say, for example, `haddock-options: -DSomethingCustom`), it will recompile the interfaces and objects. This commit introduces a guardrail to the process of re-using GHC's compilation files: instead of running haddock directly on the directories where GHC placed its output, copy the directory contents to a temporary directory and point haddock to the objects and interfaces there. Even if recompilation is triggered by haddock, the objects produced by GHC will be left untouched. --- Cabal/src/Distribution/Simple/Haddock.hs | 358 ++++++++++-------- .../src/Distribution/Types/LocalBuildInfo.hs | 4 + 2 files changed, 211 insertions(+), 151 deletions(-) diff --git a/Cabal/src/Distribution/Simple/Haddock.hs b/Cabal/src/Distribution/Simple/Haddock.hs index 6776ef7e78e..657991e16b1 100644 --- a/Cabal/src/Distribution/Simple/Haddock.hs +++ b/Cabal/src/Distribution/Simple/Haddock.hs @@ -326,11 +326,6 @@ haddock_setupHooks [] -> allTargetsInBuildOrder' pkg_descr lbi _ -> targets - -- See Note [Hi Haddock Recompilation Avoidance] - mtmp - | version >= mkVersion [2, 28, 0] = const Nothing - | otherwise = Just - internalPackageDB <- createInternalPackageDB verbosity lbi (flag $ setupDistPref . haddockCommonFlags) @@ -359,115 +354,112 @@ haddock_setupHooks in for_ mbPbcRules $ \pbcRules -> do (ruleFromId, _mons) <- SetupHooks.computeRules verbosity inputs pbcRules SetupHooks.executeRules verbosity lbi2 tgt ruleFromId - preBuildComponent runPreBuildHooks verbosity lbi' target - preprocessComponent pkg_descr component lbi' clbi False verbosity suffixes - let - doExe com = case (compToExe com) of - Just exe -> do - withTempDirectoryCwdEx verbosity tmpFileOpts mbWorkDir (buildDir lbi') "tmp" $ - \tmp -> do - exeArgs <- - fromExecutable - verbosity - (mtmp tmp) - lbi' - clbi - htmlTemplate - exe - let exeArgs' = commonArgs `mappend` exeArgs - runHaddock - verbosity - mbWorkDir - tmpFileOpts - comp - platform - haddockProg - True - exeArgs' - Nothing -> do - warn - verbosity - "Unsupported component, skipping..." - return () - -- We define 'smsg' once and then reuse it inside the case, so that - -- we don't say we are running Haddock when we actually aren't - -- (e.g., Haddock is not run on non-libraries) - smsg :: IO () - smsg = - setupMessage' - verbosity - "Running Haddock on" - (packageId pkg_descr) - (componentLocalName clbi) - (maybeComponentInstantiatedWith clbi) - ipi <- case component of - CLib lib -> do - withTempDirectoryCwdEx verbosity tmpFileOpts mbWorkDir (buildDir lbi') "tmp" $ - \tmp -> do - smsg - libArgs <- - fromLibrary + + -- See Note [Hi Haddock Recompilation Avoidance] + reusingGHCCompilationArtifacts verbosity tmpFileOpts mbWorkDir lbi bi clbi version $ \haddockArtifactsDirs -> do + preBuildComponent runPreBuildHooks verbosity lbi' target + preprocessComponent pkg_descr component lbi' clbi False verbosity suffixes + let + doExe com = case (compToExe com) of + Just exe -> do + exeArgs <- + fromExecutable verbosity - (mtmp tmp) + haddockArtifactsDirs lbi' clbi htmlTemplate - lib - let libArgs' = commonArgs `mappend` libArgs - runHaddock verbosity mbWorkDir tmpFileOpts comp platform haddockProg True libArgs' - inplaceDir <- absoluteWorkingDirLBI lbi - - let - ipi = - inplaceInstalledPackageInfo - inplaceDir - (flag $ setupDistPref . haddockCommonFlags) - pkg_descr - (mkAbiHash "inplace") - lib - lbi' - clbi - - debug verbosity $ - "Registering inplace:\n" - ++ (InstalledPackageInfo.showInstalledPackageInfo ipi) - - registerPackage + exe + let exeArgs' = commonArgs `mappend` exeArgs + runHaddock verbosity - (compiler lbi') - (withPrograms lbi') mbWorkDir - (withPackageDB lbi') - ipi - HcPkg.defaultRegisterOptions - { HcPkg.registerMultiInstance = True - } + tmpFileOpts + comp + platform + haddockProg + True + exeArgs' + Nothing -> do + warn + verbosity + "Unsupported component, skipping..." + return () + -- We define 'smsg' once and then reuse it inside the case, so that + -- we don't say we are running Haddock when we actually aren't + -- (e.g., Haddock is not run on non-libraries) + smsg :: IO () + smsg = + setupMessage' + verbosity + "Running Haddock on" + (packageId pkg_descr) + (componentLocalName clbi) + (maybeComponentInstantiatedWith clbi) + ipi <- case component of + CLib lib -> do + smsg + libArgs <- + fromLibrary + verbosity + haddockArtifactsDirs + lbi' + clbi + htmlTemplate + lib + let libArgs' = commonArgs `mappend` libArgs + runHaddock verbosity mbWorkDir tmpFileOpts comp platform haddockProg True libArgs' + inplaceDir <- absoluteWorkingDirLBI lbi + + let + ipi = + inplaceInstalledPackageInfo + inplaceDir + (flag $ setupDistPref . haddockCommonFlags) + pkg_descr + (mkAbiHash "inplace") + lib + lbi' + clbi - return $ PackageIndex.insert ipi index - CFLib flib -> - when - (flag haddockForeignLibs) - ( do - smsg - flibArgs <- - withTempDirectoryCwdEx verbosity tmpFileOpts mbWorkDir (buildDir lbi') "tmp" $ - \tmp -> do - fromForeignLib - verbosity - (mtmp tmp) - lbi' - clbi - htmlTemplate - flib - let libArgs' = commonArgs `mappend` flibArgs - runHaddock verbosity mbWorkDir tmpFileOpts comp platform haddockProg True libArgs' - ) - >> return index - CExe _ -> when (flag haddockExecutables) (smsg >> doExe component) >> return index - CTest _ -> when (flag haddockTestSuites) (smsg >> doExe component) >> return index - CBench _ -> when (flag haddockBenchmarks) (smsg >> doExe component) >> return index + debug verbosity $ + "Registering inplace:\n" + ++ (InstalledPackageInfo.showInstalledPackageInfo ipi) + + registerPackage + verbosity + (compiler lbi') + (withPrograms lbi') + mbWorkDir + (withPackageDB lbi') + ipi + HcPkg.defaultRegisterOptions + { HcPkg.registerMultiInstance = True + } + + return $ PackageIndex.insert ipi index + CFLib flib -> + when + (flag haddockForeignLibs) + ( do + smsg + flibArgs <- + fromForeignLib + verbosity + haddockArtifactsDirs + lbi' + clbi + htmlTemplate + flib + let libArgs' = commonArgs `mappend` flibArgs + runHaddock verbosity mbWorkDir tmpFileOpts comp platform haddockProg True libArgs' + ) + >> return index + CExe _ -> when (flag haddockExecutables) (smsg >> doExe component) >> return index + CTest _ -> when (flag haddockTestSuites) (smsg >> doExe component) >> return index + CBench _ -> when (flag haddockBenchmarks) (smsg >> doExe component) >> return index - return ipi + return ipi for_ (extraDocFiles pkg_descr) $ \fpath -> do files <- matchDirFileGlob verbosity (specVersion pkg_descr) mbWorkDir fpath @@ -597,19 +589,40 @@ componentGhcOptions verbosity lbi bi clbi odir = {- Note [Hi Haddock Recompilation Avoidance] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Starting with Haddock 2.28, we no longer want to run Haddock's -GHC session in a temporary directory. Doing so always causes -recompilation during documentation generation, which can now be -avoided thanks to Hi Haddock. +Starting with Haddock 2.28, we no longer want to run Haddock's GHC session in +an arbitrary temporary directory. Doing so always causes recompilation during +documentation generation, which can now be avoided thanks to Hi Haddock. + +Instead, we want to re-use the interface and object files produced by GHC. +We copy these intermediate files produced by GHC to temporary directories and +point haddock to them. + +The reason why we can't use the GHC files /inplace/ is that haddock may have to +recompile (e.g. because of `haddock-options`). In that case, we want to be sure +the files produced by GHC do not get overwritten. See https://github.com/haskell/cabal/pull/9177 for discussion. + +(W.1) As it turns out, -stubdir is included in GHC's recompilation fingerprint. +This means that if we use a temporary directory for stubfiles produced by GHC +for the haddock invocation, haddock will trigger full recompilation since the +stubdir would be different. + +So we don't use a temporary stubdir, despite the tmp o-dir and hi-dir: + +We want to avoid at all costs haddock accidentally overwriting o-files and +hi-files (e.g. if a user specified haddock-option triggers recompilation), and +thus copy them to a temporary directory to pass them on to haddock. However, +stub files are much less problematic since ABI-incompatibility isn't at play +here, that is, there doesn't seem to be a GHC flag that could accidentally make +a stub file incompatible with the one produced by GHC from the same module. -} mkHaddockArgs :: Verbosity - -> Maybe (SymbolicPath Pkg (Path.Dir Tmp)) - -- ^ 'Nothing' to prevent passing temporary directories for -hidir, -odir, and - -- -stubdir to GHC through Haddock + -> (SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts)) + -- ^ Directories for -hidir, -odir, and -stubdir to GHC through Haddock. + -- See Note [Hi Haddock Recompilation Avoidance] -> LocalBuildInfo -> ComponentLocalBuildInfo -> Maybe PathTemplate @@ -617,25 +630,26 @@ mkHaddockArgs -> [SymbolicPath Pkg File] -> BuildInfo -> IO HaddockArgs -mkHaddockArgs verbosity mtmp lbi clbi htmlTemplate inFiles bi = do +mkHaddockArgs verbosity (tmpObjDir, tmpHiDir, tmpStubDir) lbi clbi htmlTemplate inFiles bi = do + let + vanillaOpts' = + componentGhcOptions normal lbi bi clbi (buildDir lbi) + vanillaOpts = + vanillaOpts' + { -- See Note [Hi Haddock Recompilation Avoidance] + ghcOptObjDir = toFlag tmpObjDir + , ghcOptHiDir = toFlag tmpHiDir + , ghcOptStubDir = toFlag tmpStubDir + } + sharedOpts = + vanillaOpts + { ghcOptDynLinkMode = toFlag GhcDynamicOnly + , ghcOptFPic = toFlag True + , ghcOptHiSuffix = toFlag "dyn_hi" + , ghcOptObjSuffix = toFlag "dyn_o" + , ghcOptExtra = hcSharedOptions GHC bi + } ifaceArgs <- getInterfaces verbosity lbi clbi htmlTemplate - let vanillaOpts' = - componentGhcOptions normal lbi bi clbi (buildDir lbi) - vanillaOpts = - vanillaOpts' - { -- See Note [Hi Haddock Recompilation Avoidance] - ghcOptObjDir = maybe (ghcOptObjDir vanillaOpts') (toFlag . coerceSymbolicPath) mtmp - , ghcOptHiDir = maybe (ghcOptHiDir vanillaOpts') (toFlag . coerceSymbolicPath) mtmp - , ghcOptStubDir = maybe (ghcOptStubDir vanillaOpts') (toFlag . coerceSymbolicPath) mtmp - } - sharedOpts = - vanillaOpts - { ghcOptDynLinkMode = toFlag GhcDynamicOnly - , ghcOptFPic = toFlag True - , ghcOptHiSuffix = toFlag "dyn_hi" - , ghcOptObjSuffix = toFlag "dyn_o" - , ghcOptExtra = hcSharedOptions GHC bi - } opts <- if withVanillaLib lbi then return vanillaOpts @@ -653,21 +667,21 @@ mkHaddockArgs verbosity mtmp lbi clbi htmlTemplate inFiles bi = do fromLibrary :: Verbosity - -> Maybe (SymbolicPath Pkg (Path.Dir Tmp)) - -- ^ 'Nothing' to prevent passing temporary directories for -hidir, -odir, and - -- -stubdir to GHC through Haddock + -> (SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts)) + -- ^ Directories for -hidir, -odir, and -stubdir to GHC through Haddock. + -- See Note [Hi Haddock Recompilation Avoidance] -> LocalBuildInfo -> ComponentLocalBuildInfo -> Maybe PathTemplate -- ^ template for HTML location -> Library -> IO HaddockArgs -fromLibrary verbosity mtmp lbi clbi htmlTemplate lib = do +fromLibrary verbosity haddockArtifactsDirs lbi clbi htmlTemplate lib = do inFiles <- map snd `fmap` getLibSourceFiles verbosity lbi lib clbi args <- mkHaddockArgs verbosity - mtmp + haddockArtifactsDirs lbi clbi htmlTemplate @@ -680,21 +694,21 @@ fromLibrary verbosity mtmp lbi clbi htmlTemplate lib = do fromExecutable :: Verbosity - -> Maybe (SymbolicPath Pkg (Path.Dir Tmp)) - -- ^ 'Nothing' to prevent passing temporary directories for -hidir, -odir, and - -- -stubdir to GHC through Haddock + -> (SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts)) + -- ^ Directories for -hidir, -odir, and -stubdir to GHC through Haddock. + -- See Note [Hi Haddock Recompilation Avoidance] -> LocalBuildInfo -> ComponentLocalBuildInfo -> Maybe PathTemplate -- ^ template for HTML location -> Executable -> IO HaddockArgs -fromExecutable verbosity mtmp lbi clbi htmlTemplate exe = do +fromExecutable verbosity haddockArtifactsDirs lbi clbi htmlTemplate exe = do inFiles <- map snd `fmap` getExeSourceFiles verbosity lbi exe clbi args <- mkHaddockArgs verbosity - mtmp + haddockArtifactsDirs lbi clbi htmlTemplate @@ -708,21 +722,21 @@ fromExecutable verbosity mtmp lbi clbi htmlTemplate exe = do fromForeignLib :: Verbosity - -> Maybe (SymbolicPath Pkg (Path.Dir Tmp)) - -- ^ 'Nothing' to prevent passing temporary directories for -hidir, -odir, and - -- -stubdir to GHC through Haddock + -> (SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts)) + -- ^ Directories for -hidir, -odir, and -stubdir to GHC through Haddock. + -- See Note [Hi Haddock Recompilation Avoidance] -> LocalBuildInfo -> ComponentLocalBuildInfo -> Maybe PathTemplate -- ^ template for HTML location -> ForeignLib -> IO HaddockArgs -fromForeignLib verbosity mtmp lbi clbi htmlTemplate flib = do +fromForeignLib verbosity haddockArtifactsDirs lbi clbi htmlTemplate flib = do inFiles <- map snd `fmap` getFLibSourceFiles verbosity lbi flib clbi args <- mkHaddockArgs verbosity - mtmp + haddockArtifactsDirs lbi clbi htmlTemplate @@ -787,6 +801,47 @@ getGhcLibDir verbosity lbi = do _ -> error "haddock only supports GHC and GHCJS" return $ mempty{argGhcLibDir = Flag l} +-- | If Hi Haddock is supported, this function creates temporary directories +-- and copies existing interface and object files produced by GHC into them, +-- then passes them off to the given continuation. +-- +-- If Hi Haddock is _not_ supported, we can't re-use GHC's compilation files. +-- Instead, we use a clean temporary directory to the continuation, +-- with no hope for recompilation avoidance. +-- +-- See Note [Hi Haddock Recompilation Avoidance] +reusingGHCCompilationArtifacts + :: Verbosity + -> TempFileOptions + -> Maybe (SymbolicPath CWD (Path.Dir Pkg)) + -- ^ Working directory + -> LocalBuildInfo + -> BuildInfo + -> ComponentLocalBuildInfo + -> Version + -- ^ Haddock's version + -> ((SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts)) -> IO r) + -- ^ Continuation + -> IO r +reusingGHCCompilationArtifacts verbosity tmpFileOpts mbWorkDir lbi bi clbi version act + | version >= mkVersion [2, 28, 0] = do + withTempDirectoryCwdEx verbosity tmpFileOpts mbWorkDir (distPrefLBI lbi) "haddock-objs" $ \tmpObjDir -> + withTempDirectoryCwdEx verbosity tmpFileOpts mbWorkDir (distPrefLBI lbi) "haddock-his" $ \tmpHiDir -> do + -- Re-use ghc's interface and obj files, but first copy them to + -- somewhere where it is safe if haddock overwrites them + let + vanillaOpts = componentGhcOptions normal lbi bi clbi (buildDir lbi) + i = interpretSymbolicPath mbWorkDir + copyDir ghcDir tmpDir = copyDirectoryRecursive verbosity (i $ fromFlag $ ghcDir vanillaOpts) (i tmpDir) + copyDir ghcOptObjDir tmpObjDir + copyDir ghcOptHiDir tmpHiDir + -- copyDir ghcOptStubDir tmpStubDir -- (see W.1 in Note [Hi Haddock Recompilation Avoidance]) + + act (tmpObjDir, tmpHiDir, fromFlag $ ghcOptHiDir vanillaOpts) + | otherwise = do + withTempDirectoryCwdEx verbosity tmpFileOpts mbWorkDir (distPrefLBI lbi) "tmp" $ + \tmpFallback -> act (tmpFallback, tmpFallback, tmpFallback) + -- ------------------------------------------------------------------------------ -- | Call haddock with the specified arguments. @@ -981,10 +1036,10 @@ renderPureArgs version comp platform args = ] , argTargets $ args , maybe [] ((: []) . (resourcesDirFlag ++)) . flagToMaybe . argResourcesDir $ args - -- Do not re-direct compilation output to a temporary directory (--no-tmp-comp-dir) - -- We pass this option by default to haddock to avoid recompilation - -- See Note [Hi Haddock Recompilation Avoidance] - , [ "--no-tmp-comp-dir" | version >= mkVersion [2, 28, 0] ] + , -- Do not re-direct compilation output to a temporary directory (--no-tmp-comp-dir) + -- We pass this option by default to haddock to avoid recompilation + -- See Note [Hi Haddock Recompilation Avoidance] + ["--no-tmp-comp-dir" | version >= mkVersion [2, 28, 0]] ] where -- See Note [Symbolic paths] in Distribution.Utils.Path @@ -1303,7 +1358,8 @@ hscolour' where outFile m = i outputDir - intercalate "-" (ModuleName.components m) <.> "html" + intercalate "-" (ModuleName.components m) + <.> "html" haddockToHscolour :: HaddockFlags -> HscolourFlags haddockToHscolour flags = diff --git a/Cabal/src/Distribution/Types/LocalBuildInfo.hs b/Cabal/src/Distribution/Types/LocalBuildInfo.hs index a5706fff09a..3f9d8d74268 100644 --- a/Cabal/src/Distribution/Types/LocalBuildInfo.hs +++ b/Cabal/src/Distribution/Types/LocalBuildInfo.hs @@ -57,6 +57,7 @@ module Distribution.Types.LocalBuildInfo , buildDir , buildDirPBD , setupFlagsBuildDir + , distPrefLBI , packageRoot , progPrefix , progSuffix @@ -289,6 +290,9 @@ buildDirPBD (LBC.PackageBuildDescr{configFlags = cfg}) = setupFlagsBuildDir :: CommonSetupFlags -> SymbolicPath Pkg (Dir Build) setupFlagsBuildDir cfg = fromFlag (setupDistPref cfg) makeRelativePathEx "build" +distPrefLBI :: LocalBuildInfo -> SymbolicPath Pkg (Dir Dist) +distPrefLBI = fromFlag . setupDistPref . configCommonFlags . LBC.configFlags . LBC.packageBuildDescr . localBuildDescr + -- | The (relative or absolute) path to the package root, based on -- -- - the working directory flag