From 68a73d0f2e746e3ba057563e69613bd8672ac8b1 Mon Sep 17 00:00:00 2001 From: sheaf Date: Mon, 4 May 2026 11:18:56 +0200 Subject: [PATCH 1/2] cabal-install: add --build-timings flag This new flag makes cabal-install dump timing information for the various stages of building a package. This allows us to better see how much time is spending in configure/build stages. --- .../parser-tests/Tests/ParserTests.hs | 1 + .../src/Distribution/Client/Config.hs | 1 + .../Client/ProjectBuilding/UnpackedPackage.hs | 59 ++++++++++++++++--- .../src/Distribution/Client/ProjectConfig.hs | 1 + .../Client/ProjectConfig/FieldGrammar.hs | 1 + .../Client/ProjectConfig/Legacy.hs | 3 + .../Distribution/Client/ProjectConfig/Lens.hs | 4 ++ .../Client/ProjectConfig/Types.hs | 2 + .../src/Distribution/Client/Setup.hs | 9 +++ .../Distribution/Client/ProjectConfig.hs | 7 ++- changelog.d/build-timings.md | 13 ++++ doc/cabal-project-description-file.rst | 8 +++ 12 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 changelog.d/build-timings.md diff --git a/cabal-install/parser-tests/Tests/ParserTests.hs b/cabal-install/parser-tests/Tests/ParserTests.hs index 674e09c18e9..25ada09ce64 100644 --- a/cabal-install/parser-tests/Tests/ParserTests.hs +++ b/cabal-install/parser-tests/Tests/ParserTests.hs @@ -173,6 +173,7 @@ testProjectConfigBuildOnly = do , cinstInstallMethod = Flag InstallMethodSymlink , cinstInstalldir = Flag "path/to/installdir" } + projectConfigBuildTimings = mempty testProjectConfigShared :: Assertion testProjectConfigShared = do diff --git a/cabal-install/src/Distribution/Client/Config.hs b/cabal-install/src/Distribution/Client/Config.hs index 16205e8d14f..506eb74d1c8 100644 --- a/cabal-install/src/Distribution/Client/Config.hs +++ b/cabal-install/src/Distribution/Client/Config.hs @@ -447,6 +447,7 @@ instance Semigroup SavedConfig where , installKeepGoing = combine installKeepGoing , installRunTests = combine installRunTests , installOfflineMode = combine installOfflineMode + , installBuildTimings = combine installBuildTimings } where combine = combine' savedInstallFlags diff --git a/cabal-install/src/Distribution/Client/ProjectBuilding/UnpackedPackage.hs b/cabal-install/src/Distribution/Client/ProjectBuilding/UnpackedPackage.hs index 42a19a03d43..ef069fc50ec 100644 --- a/cabal-install/src/Distribution/Client/ProjectBuilding/UnpackedPackage.hs +++ b/cabal-install/src/Distribution/Client/ProjectBuilding/UnpackedPackage.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-} @@ -118,10 +119,12 @@ import qualified Data.List.NonEmpty as NE import Control.Concurrent.STM (TVar, atomically, modifyTVar) import Control.Exception (ErrorCall, Handler (..), SomeAsyncException, assert, catches, onException) import Data.IORef (newIORef, readIORef, writeIORef) +import GHC.Clock (getMonotonicTime) import System.Directory (canonicalizePath, createDirectoryIfMissing, doesDirectoryExist, listDirectory) import System.FilePath (dropDrive, normalise, takeDirectory, (<.>), ()) import System.IO (Handle, IOMode (AppendMode), withFile) import System.Semaphore (SemaphoreIdentifier) +import Text.Printf (printf) import GHC.Stack import Web.Browser (openBrowser) @@ -189,7 +192,10 @@ buildAndRegisterUnpackedPackage verbosity distDirLayout@DistDirLayout{distTempDirectory} maybe_semaphore - buildTimeSettings@BuildTimeSettings{buildSettingKeepTempFiles} + buildTimeSettings@BuildTimeSettings + { buildSettingKeepTempFiles + , buildSettingBuildTimings + } registerLock cacheLock pkgshared@ElaboratedSharedConfig @@ -205,7 +211,7 @@ buildAndRegisterUnpackedPackage delegate = do -- Configure phase mbLBI <- - delegate $ + timedDelegate $ PBConfigurePhase $ annotateFailure mlogFile ConfigureFailed $ setup @@ -216,7 +222,7 @@ buildAndRegisterUnpackedPackage (InLibraryArgs $ InLibraryConfigureArgs pkgshared rpkg ipiTVar) -- Build phase - delegate $ + timedDelegate $ PBBuildPhase $ annotateFailure mlogFile BuildFailed $ do setup @@ -228,7 +234,7 @@ buildAndRegisterUnpackedPackage -- Haddock phase whenHaddock $ - delegate $ + timedDelegate $ PBHaddockPhase $ annotateFailure mlogFile HaddocksFailed $ do setup @@ -244,7 +250,7 @@ buildAndRegisterUnpackedPackage -- the installed package id is, not the build system. ipkg0 <- generateInstalledPackageInfo mbLBI return ipkg0{Installed.installedUnitId = uid} - delegate $ + timedDelegate $ PBInstallPhase { runCopy = \destdir -> annotateFailure mlogFile InstallFailed $ @@ -273,7 +279,7 @@ buildAndRegisterUnpackedPackage -- Test phase whenTest $ - delegate $ + timedDelegate $ PBTestPhase $ annotateFailure mlogFile TestsFailed $ setup @@ -285,7 +291,7 @@ buildAndRegisterUnpackedPackage -- Bench phase whenBench $ - delegate $ + timedDelegate $ PBBenchPhase $ annotateFailure mlogFile BenchFailed $ setup @@ -297,7 +303,7 @@ buildAndRegisterUnpackedPackage -- Repl phase whenRepl $ - delegate $ + timedDelegate $ PBReplPhase $ annotateFailure mlogFile ReplFailed $ setupInteractive @@ -311,6 +317,33 @@ buildAndRegisterUnpackedPackage where uid = installedUnitId rpkg + timedDelegate :: forall r. PackageBuildingPhase r -> IO r + timedDelegate phase + | buildSettingBuildTimings = do + t0 <- getMonotonicTime + let + printTiming :: String -> IO () + printTiming suffix = do + t1 <- getMonotonicTime + let + elapsed = t1 - t0 + pkgstr = prettyShow (packageId rpkg) + msg = + unwords + [ "[build-timings]" + , buildPhaseName phase + , pkgstr + , -- Print milliseconds (3 decimal places) + printf "%.3fs" elapsed + , suffix + ] + notice verbosity msg + r <- delegate phase `onException` printTiming "(failed)" + !_ <- evaluate r + printTiming "" + return r + | otherwise = delegate phase + comp_par_strat = case maybe_semaphore of Just sem_ident -> Cabal.toFlag sem_ident _ -> Cabal.NoFlag @@ -1014,6 +1047,16 @@ annotateFailure mlogFile annotate action = -- * Other Utils -------------------------------------------------------------------------------- +-- | Display name for each build phase, used in timing output. +buildPhaseName :: PackageBuildingPhase r -> String +buildPhaseName PBConfigurePhase{} = "configure" +buildPhaseName PBBuildPhase{} = "build" +buildPhaseName PBHaddockPhase{} = "haddock" +buildPhaseName PBReplPhase{} = "repl" +buildPhaseName PBInstallPhase{} = "install" +buildPhaseName PBTestPhase{} = "test" +buildPhaseName PBBenchPhase{} = "bench" + hasValidHaddockTargets :: ElaboratedConfiguredPackage -> Bool hasValidHaddockTargets ElaboratedConfiguredPackage{..} | not elabBuildHaddocks = False diff --git a/cabal-install/src/Distribution/Client/ProjectConfig.hs b/cabal-install/src/Distribution/Client/ProjectConfig.hs index 2249c4c7147..603c1e00839 100644 --- a/cabal-install/src/Distribution/Client/ProjectConfig.hs +++ b/cabal-install/src/Distribution/Client/ProjectConfig.hs @@ -470,6 +470,7 @@ resolveBuildTimeSettings fromFlag projectConfigReportPlanningFailure buildSettingProgPathExtra = fromNubList projectConfigProgPathExtra buildSettingHaddockOpen = False + buildSettingBuildTimings = fromFlagOrDefault False projectConfigBuildTimings ProjectConfigBuildOnly{..} = defaults diff --git a/cabal-install/src/Distribution/Client/ProjectConfig/FieldGrammar.hs b/cabal-install/src/Distribution/Client/ProjectConfig/FieldGrammar.hs index f49279f7781..f5672a3ccf8 100644 --- a/cabal-install/src/Distribution/Client/ProjectConfig/FieldGrammar.hs +++ b/cabal-install/src/Distribution/Client/ProjectConfig/FieldGrammar.hs @@ -66,6 +66,7 @@ projectConfigBuildOnlyFieldGrammar = <*> optionalFieldDefAla "remote-repo-cache" (alaFlag FilePathNT) L.projectConfigCacheDir mempty <*> optionalFieldDefAla "logs-dir" (alaFlag FilePathNT) L.projectConfigLogsDir mempty <*> blurFieldGrammar L.projectConfigClientInstallFlags clientInstallFlagsGrammar + <*> optionalFieldDef "build-timings" L.projectConfigBuildTimings mempty projectConfigSharedFieldGrammar :: ProjectConfigPath -> ParsecFieldGrammar' ProjectConfigShared projectConfigSharedFieldGrammar source = diff --git a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs index c0e4962cd6f..eb243ae4e07 100644 --- a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs +++ b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs @@ -887,6 +887,7 @@ convertLegacyBuildOnlyFlags , installUseSemaphore = projectConfigUseSemaphore , installKeepGoing = projectConfigKeepGoing , installOfflineMode = projectConfigOfflineMode + , installBuildTimings = projectConfigBuildTimings } = installFlags convertToLegacyProjectConfig :: ProjectConfig -> LegacyProjectConfig @@ -1022,6 +1023,7 @@ convertToLegacySharedConfig , installKeepGoing = projectConfigKeepGoing , installRunTests = mempty , installOfflineMode = projectConfigOfflineMode + , installBuildTimings = projectConfigBuildTimings } projectFlags = @@ -1458,6 +1460,7 @@ legacySharedConfigFieldDescrs constraintSrc = , "keep-going" , "offline" , "per-component" + , "build-timings" , -- solver flags: "max-backjumps" , "reorder-goals" diff --git a/cabal-install/src/Distribution/Client/ProjectConfig/Lens.hs b/cabal-install/src/Distribution/Client/ProjectConfig/Lens.hs index d262526e2ee..69d4e5e3aed 100644 --- a/cabal-install/src/Distribution/Client/ProjectConfig/Lens.hs +++ b/cabal-install/src/Distribution/Client/ProjectConfig/Lens.hs @@ -164,6 +164,10 @@ projectConfigClientInstallFlags :: Lens' ProjectConfigBuildOnly ClientInstallFla projectConfigClientInstallFlags f s = fmap (\x -> s{T.projectConfigClientInstallFlags = x}) (f (T.projectConfigClientInstallFlags s)) {-# INLINEABLE projectConfigClientInstallFlags #-} +projectConfigBuildTimings :: Lens' ProjectConfigBuildOnly (Flag Bool) +projectConfigBuildTimings f s = fmap (\x -> s{T.projectConfigBuildTimings = x}) (f (T.projectConfigBuildTimings s)) +{-# INLINEABLE projectConfigBuildTimings #-} + projectConfigDistDir :: Lens' ProjectConfigShared (Flag FilePath) projectConfigDistDir f s = fmap (\x -> s{T.projectConfigDistDir = x}) (f (T.projectConfigDistDir s)) {-# INLINEABLE projectConfigDistDir #-} diff --git a/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs b/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs index c7fefd34d99..99bee5cf1d6 100644 --- a/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs +++ b/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs @@ -184,6 +184,7 @@ data ProjectConfigBuildOnly = ProjectConfigBuildOnly , projectConfigCacheDir :: Flag FilePath , projectConfigLogsDir :: Flag FilePath , projectConfigClientInstallFlags :: ClientInstallFlags + , projectConfigBuildTimings :: Flag Bool } deriving (Eq, Show, Generic) deriving (Semigroup, Monoid) via Generically ProjectConfigBuildOnly @@ -497,6 +498,7 @@ data BuildTimeSettings = BuildTimeSettings , buildSettingIgnoreExpiry :: Bool , buildSettingProgPathExtra :: [FilePath] , buildSettingHaddockOpen :: Bool + , buildSettingBuildTimings :: Bool } deriving (Generic) diff --git a/cabal-install/src/Distribution/Client/Setup.hs b/cabal-install/src/Distribution/Client/Setup.hs index f7a680e0c6f..a2a693c184e 100644 --- a/cabal-install/src/Distribution/Client/Setup.hs +++ b/cabal-install/src/Distribution/Client/Setup.hs @@ -2243,6 +2243,7 @@ data InstallFlags = InstallFlags , installKeepGoing :: Flag Bool , installRunTests :: Flag Bool , installOfflineMode :: Flag Bool + , installBuildTimings :: Flag Bool } deriving (Eq, Show, Generic) deriving (Semigroup, Monoid) via Generically InstallFlags @@ -2287,6 +2288,7 @@ defaultInstallFlags = , installKeepGoing = Flag False , installRunTests = mempty , installOfflineMode = Flag False + , installBuildTimings = Flag False } where docIndexFile = @@ -2790,6 +2792,13 @@ installOptions showOrParseArgs = installOfflineMode (\v flags -> flags{installOfflineMode = v}) (yesNoOpt showOrParseArgs) + , option + [] + ["build-timings"] + "Print elapsed time for each build phase." + installBuildTimings + (\v flags -> flags{installBuildTimings = v}) + (yesNoOpt showOrParseArgs) ] ++ case showOrParseArgs of -- TODO: remove when "cabal install" -- avoids diff --git a/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs b/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs index 68c985fe1bb..39e38f4f08f 100644 --- a/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs +++ b/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs @@ -524,6 +524,7 @@ instance Arbitrary ProjectConfigBuildOnly where <*> (fmap getShortToken <$> arbitrary) <*> (fmap getShortToken <$> arbitrary) <*> arbitrary + <*> arbitrary where arbitraryNumJobs = fmap (fmap getPositive) <$> arbitrary @@ -548,6 +549,7 @@ instance Arbitrary ProjectConfigBuildOnly where , projectConfigCacheDir = x15 , projectConfigLogsDir = x16 , projectConfigClientInstallFlags = x17 + , projectConfigBuildTimings = x20 } = [ ProjectConfigBuildOnly { projectConfigVerbosity = x00' @@ -569,17 +571,18 @@ instance Arbitrary ProjectConfigBuildOnly where , projectConfigCacheDir = x15 , projectConfigLogsDir = x16 , projectConfigClientInstallFlags = x17' + , projectConfigBuildTimings = x20' } | ( (x00', x01', x02', x03', x04') , (x05', x06', x07', x09') , (x10', x11', x12', x14') - , (x17', x18', x19') + , (x17', x18', x19', x20') ) <- shrink ( (x00, x01, x02, x03, x04) , (x05, x06, x07, preShrink_NumJobs x09) , (x10, x11, x12, x14) - , (x17, x18, x19) + , (x17, x18, x19, x20) ) ] where diff --git a/changelog.d/build-timings.md b/changelog.d/build-timings.md new file mode 100644 index 00000000000..b6ef65593dd --- /dev/null +++ b/changelog.d/build-timings.md @@ -0,0 +1,13 @@ +synopsis: Add flag for build timings +packages: cabal-install +prs: #11769 +description:{ +Introduce `--build-timings` flag to `cabal-install`. This flag makes `cabal-install` +log timing information to stdout, in a format like: + +``` +[build-timings] configure aeson-2.2.3.0 0.042s +[build-timings] build aeson-2.2.3.0 3.284s +[build-timings] install aeson-2.2.3.0 0.123s +``` +} diff --git a/doc/cabal-project-description-file.rst b/doc/cabal-project-description-file.rst index e4bd6264480..8f7639ee1b8 100644 --- a/doc/cabal-project-description-file.rst +++ b/doc/cabal-project-description-file.rst @@ -511,6 +511,14 @@ package, and thus apply globally: The command line variant of this flag is ``--package-db=DB`` which can be specified multiple times. +.. option:: --build-timings + + Log timing information to stdout, in the following format:: + + [build-timings] configure aeson-2.2.3.0 0.042s + [build-timings] build aeson-2.2.3.0 3.284s + [build-timings] install aeson-2.2.3.0 0.123s + Phase control ------------- From 75389a947398aad66753b81881ae43dabc9efbb7 Mon Sep 17 00:00:00 2001 From: sheaf Date: Thu, 28 May 2026 13:46:59 +0200 Subject: [PATCH 2/2] Add program prefix and suffix to `BuildOptions` This commits adds two new fields of `BuildOptions`, namely `programPrefix` and `programSuffix`. This allows the installed executable program prefix and suffix to be set by `SetupHooks` for packages with `build-type: Hooks`. Fixes #11168 --- .../Distribution/Utils/Structured.hs | 6 +++++- Cabal/src/Distribution/Simple/Configure.hs | 2 ++ .../Distribution/Types/LocalBuildConfig.hs | 6 ++++++ .../src/Distribution/Types/LocalBuildInfo.hs | 19 +++++++++++++++---- .../Distribution/Client/ProjectPlanning.hs | 2 ++ .../SetupHooksProgramPrefix/Main.hs | 4 ++++ .../SetupHooksProgramPrefix/Setup.hs | 7 +++++++ .../SetupHooksProgramPrefix/SetupHooks.hs | 18 ++++++++++++++++++ .../SetupHooksProgramPrefix/cabal.project | 1 + .../setup-hooks-prog-prefix.cabal | 13 +++++++++++++ .../SetupHooksProgramPrefix/setup.test.hs | 15 +++++++++++++++ changelog.d/hooks-prefix.md | 10 ++++++++++ 12 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/Main.hs create mode 100644 cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/Setup.hs create mode 100644 cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/SetupHooks.hs create mode 100644 cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/cabal.project create mode 100644 cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/setup-hooks-prog-prefix.cabal create mode 100644 cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/setup.test.hs create mode 100644 changelog.d/hooks-prefix.md diff --git a/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs b/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs index b1c416cf44f..a6b482038cf 100644 --- a/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs +++ b/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs @@ -27,10 +27,14 @@ tests = testGroup "Distribution.Utils.Structured" md5Check :: Structured a => Proxy a -> Integer -> Assertion md5Check proxy md5Int = structureHash proxy @?= md5FromInteger md5Int +-- NB: if you need to update these values locally, you can run: +-- +-- > cabal run Cabal-tests:unit-tests -- -p "/Structured/" + md5CheckGenericPackageDescription :: Proxy GenericPackageDescription -> Assertion md5CheckGenericPackageDescription proxy = md5Check proxy 0xfbca1c1f2a700fb3a174ec5346e86cbb md5CheckLocalBuildInfo :: Proxy LocalBuildInfo -> Assertion md5CheckLocalBuildInfo proxy = md5Check proxy - 0x3bf7bf1420847ce5fdaf6e36e33aecb2 + 0xd9542841ab7584d348aa142053fe934f diff --git a/Cabal/src/Distribution/Simple/Configure.hs b/Cabal/src/Distribution/Simple/Configure.hs index 98a618b7dc8..5200dd83d36 100644 --- a/Cabal/src/Distribution/Simple/Configure.hs +++ b/Cabal/src/Distribution/Simple/Configure.hs @@ -914,6 +914,8 @@ buildOptionsFromConfigFlags verbosity cfg comp = do , exeCoverage = False , libCoverage = False , relocatable = fromFlagOrDefault False $ configRelocatable cfg + , programPrefix = flagToMaybe $ configProgPrefix cfg + , programSuffix = flagToMaybe $ configProgSuffix cfg } -- | Adjust 'LBC.BuildOptions' to be compatible with the given 'Compiler' and diff --git a/Cabal/src/Distribution/Types/LocalBuildConfig.hs b/Cabal/src/Distribution/Types/LocalBuildConfig.hs index f79d470dcf3..7a7ae976982 100644 --- a/Cabal/src/Distribution/Types/LocalBuildConfig.hs +++ b/Cabal/src/Distribution/Types/LocalBuildConfig.hs @@ -188,6 +188,10 @@ data BuildOptions = BuildOptions -- ^ Whether to enable library program coverage , relocatable :: Bool -- ^ Whether to build a relocatable package + , programPrefix :: Maybe PathTemplate + -- ^ Installed executable prefix + , programSuffix :: Maybe PathTemplate + -- ^ Installed executable suffix } deriving (Eq, Generic, Read, Show) @@ -229,4 +233,6 @@ buildOptionsConfigFlags (BuildOptions{..}) = , configStripExes = toFlag stripExes , configStripLibs = toFlag stripLibs , configDebugInfo = toFlag withDebugInfo + , configProgPrefix = maybeToFlag programPrefix + , configProgSuffix = maybeToFlag programSuffix } diff --git a/Cabal/src/Distribution/Types/LocalBuildInfo.hs b/Cabal/src/Distribution/Types/LocalBuildInfo.hs index f525d397aba..626085fb468 100644 --- a/Cabal/src/Distribution/Types/LocalBuildInfo.hs +++ b/Cabal/src/Distribution/Types/LocalBuildInfo.hs @@ -47,6 +47,8 @@ module Distribution.Types.LocalBuildInfo , libCoverage , extraCoverageFor , relocatable + , programPrefix + , programSuffix , .. ) @@ -188,6 +190,8 @@ pattern LocalBuildInfo -> Bool -> [UnitId] -> Bool + -> Maybe PathTemplate + -> Maybe PathTemplate -> LocalBuildInfo pattern LocalBuildInfo { configFlags @@ -227,6 +231,8 @@ pattern LocalBuildInfo , libCoverage , extraCoverageFor , relocatable + , programPrefix + , programSuffix } = NewLocalBuildInfo { localBuildDescr = @@ -279,6 +285,8 @@ pattern LocalBuildInfo , exeCoverage , libCoverage , relocatable + , programPrefix + , programSuffix } } } @@ -316,10 +324,13 @@ packageRoot cfg = mbWorkDir = flagToMaybe $ setupWorkingDir cfg progPrefix, progSuffix :: LocalBuildInfo -> PathTemplate -progPrefix (LocalBuildInfo{configFlags = cfg}) = - fromFlag $ configProgPrefix cfg -progSuffix (LocalBuildInfo{configFlags = cfg}) = - fromFlag $ configProgSuffix cfg +-- NB: make sure to read from 'BuildOptions' rather than the 'ConfigFlags' +-- stored in 'PackageBuildDescr', as the latter are the original command-line +-- input and are not updated by 'SetupHooks' configure hooks. +progPrefix (LocalBuildInfo{programPrefix = pfix}) = + fromMaybe (toPathTemplate "") pfix +progSuffix (LocalBuildInfo{programSuffix = sfix}) = + fromMaybe (toPathTemplate "") sfix -- TODO: Get rid of these functions, as much as possible. They are -- a bit useful in some cases, but you should be very careful! diff --git a/cabal-install/src/Distribution/Client/ProjectPlanning.hs b/cabal-install/src/Distribution/Client/ProjectPlanning.hs index f3054b98099..3021e5dfdef 100644 --- a/cabal-install/src/Distribution/Client/ProjectPlanning.hs +++ b/cabal-install/src/Distribution/Client/ProjectPlanning.hs @@ -2405,6 +2405,8 @@ elaborateInstallPlan , relocatable = perPkgOptionFlag pkgid False packageConfigRelocatable , withProfLibDetail = elabProfExeDetail , withProfExeDetail = elabProfLibDetail + , programPrefix = elabProgPrefix + , programSuffix = elabProgSuffix } okProfDyn = profilingDynamicSupportedOrUnknown compiler profExe = perPkgOptionFlag pkgid False packageConfigProf diff --git a/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/Main.hs b/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/Main.hs new file mode 100644 index 00000000000..d82a4bd93b7 --- /dev/null +++ b/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/Main.hs @@ -0,0 +1,4 @@ +module Main where + +main :: IO () +main = return () diff --git a/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/Setup.hs b/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/Setup.hs new file mode 100644 index 00000000000..bfa0675fc95 --- /dev/null +++ b/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/Setup.hs @@ -0,0 +1,7 @@ +module Main where + +import Distribution.Simple ( defaultMainWithSetupHooks ) +import SetupHooks ( setupHooks ) + +main :: IO () +main = defaultMainWithSetupHooks setupHooks diff --git a/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/SetupHooks.hs b/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/SetupHooks.hs new file mode 100644 index 00000000000..b6e8cae0e73 --- /dev/null +++ b/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/SetupHooks.hs @@ -0,0 +1,18 @@ +module SetupHooks where + +import Distribution.Simple.SetupHooks +import Distribution.Simple.InstallDirs ( toPathTemplate ) +import Distribution.Types.LocalBuildConfig ( BuildOptions (..) ) + +setupHooks :: SetupHooks +setupHooks = + noSetupHooks + { configureHooks = + noConfigureHooks + { preConfPackageHook = Just preConfPkg } + } + +preConfPkg :: PreConfPackageHook +preConfPkg inputs = + let outputs@PreConfPackageOutputs{buildOptions = opts} = noPreConfPackageOutputs inputs + in return outputs{buildOptions = opts{programPrefix = Just (toPathTemplate "pre-")}} diff --git a/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/cabal.project b/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/cabal.project new file mode 100644 index 00000000000..e6fdbadb439 --- /dev/null +++ b/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/cabal.project @@ -0,0 +1 @@ +packages: . diff --git a/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/setup-hooks-prog-prefix.cabal b/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/setup-hooks-prog-prefix.cabal new file mode 100644 index 00000000000..7e0d0707098 --- /dev/null +++ b/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/setup-hooks-prog-prefix.cabal @@ -0,0 +1,13 @@ +cabal-version: 3.14 +name: setup-hooks-prog-prefix +version: 0.1.0.0 +license: BSD-3-Clause +build-type: Hooks + +custom-setup + setup-depends: Cabal, Cabal-hooks, base + +executable myexe + main-is: Main.hs + build-depends: base + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/setup.test.hs b/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/setup.test.hs new file mode 100644 index 00000000000..f5339c17f41 --- /dev/null +++ b/cabal-testsuite/PackageTests/SetupHooks/SetupHooksProgramPrefix/setup.test.hs @@ -0,0 +1,15 @@ +import Test.Cabal.Prelude +import Distribution.System ( buildPlatform ) +import Distribution.Simple.BuildPaths ( exeExtension ) + +-- Test that SetupHooks can set the programPrefix (#11168). +main = setupTest $ do + env <- getTestEnv + withPackageDb $ recordMode DoNotRecord $ do + setup "configure" [] + setup "build" [] + setup "copy" [] + let binDir = testPrefixDir env "bin" + exeExt = exeExtension buildPlatform + shouldExist (binDir "pre-myexe" <.> exeExt) + shouldNotExist (binDir "myexe" <.> exeExt) diff --git a/changelog.d/hooks-prefix.md b/changelog.d/hooks-prefix.md new file mode 100644 index 00000000000..f1216a3dce8 --- /dev/null +++ b/changelog.d/hooks-prefix.md @@ -0,0 +1,10 @@ +--- +synopsis: Add program prefix and suffix to `BuildOptions` +packages: [Cabal, Cabal-hooks] +prs: 11787 +issues: 11168 +--- + +Two new fields of `BuildOptions`, `programPrefix` and `programSuffix`, have +been added. This allows the installed executable program prefix and suffix to +be set by `SetupHooks` for packages with `build-type: Hooks`.