From 5e3033a364aa0da113f8ab4be23e6ca2dfd774fa Mon Sep 17 00:00:00 2001 From: Rodrigo Mesquita Date: Tue, 5 Dec 2023 18:12:56 +0000 Subject: [PATCH] HPC artifacts are written and read from pkg-db TODO: Describe design --- Cabal/src/Distribution/Simple/Configure.hs | 18 +++- .../Distribution/Simple/GHC/BuildGeneric.hs | 6 +- .../Distribution/Simple/GHC/BuildOrRepl.hs | 6 +- Cabal/src/Distribution/Simple/GHCJS.hs | 8 +- Cabal/src/Distribution/Simple/Hpc.hs | 13 ++- Cabal/src/Distribution/Simple/Setup/Config.hs | 23 +++++ Cabal/src/Distribution/Simple/Setup/Test.hs | 44 ---------- Cabal/src/Distribution/Simple/Test.hs | 56 ++++++++++-- Cabal/src/Distribution/Simple/Test/ExeV10.hs | 9 +- Cabal/src/Distribution/Simple/Test/LibV09.hs | 8 +- Plan.md | 29 ++++++ .../src/Distribution/Client/Config.hs | 3 +- .../Distribution/Client/ProjectBuilding.hs | 5 +- .../Client/ProjectConfig/Legacy.hs | 7 +- .../Client/ProjectOrchestration.hs | 1 + .../Distribution/Client/ProjectPlanning.hs | 88 +++++++++---------- .../src/Distribution/Client/Setup.hs | 14 +-- 17 files changed, 197 insertions(+), 141 deletions(-) create mode 100644 Plan.md diff --git a/Cabal/src/Distribution/Simple/Configure.hs b/Cabal/src/Distribution/Simple/Configure.hs index b7aabf65f18..a82c614f641 100644 --- a/Cabal/src/Distribution/Simple/Configure.hs +++ b/Cabal/src/Distribution/Simple/Configure.hs @@ -1,5 +1,6 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE RecordWildCards #-} @@ -44,6 +45,7 @@ module Distribution.Simple.Configure , localBuildInfoFile , getInstalledPackages , getInstalledPackagesMonitorFiles + , getInstalledPackageById , getPackageDBContents , configCompilerEx , configCompilerAuxEx @@ -78,7 +80,7 @@ import Distribution.Simple.BuildTarget import Distribution.Simple.BuildToolDepends import Distribution.Simple.Compiler import Distribution.Simple.LocalBuildInfo -import Distribution.Simple.PackageIndex (InstalledPackageIndex) +import Distribution.Simple.PackageIndex (InstalledPackageIndex, lookupUnitId) import qualified Distribution.Simple.PackageIndex as PackageIndex import Distribution.Simple.PreProcess import Distribution.Simple.Program @@ -877,6 +879,12 @@ configure (pkg_descr0, pbi) cfg = do Map.empty buildComponents + -- ROMES:TODO: For per-package configure, we have to determine + -- configureCoverageFor here. Should we enforce something here on that + -- --coverage-for should not include indefinite or instantiations? + -- Then, whatever we discover about package unit ids here, we should write + -- into configFlags, or should we really have a distinct field in LBI? + let lbi = (setCoverageLBI . setProfLBI) LocalBuildInfo @@ -1747,6 +1755,14 @@ getInstalledPackagesMonitorFiles verbosity comp packageDBs progdb platform = ++ prettyShow other return [] +-- | Looks up the 'InstalledPackageInfo' of a given 'UnitId' from the +-- 'PackageDBStack' in the 'LocalBuildInfo'. +getInstalledPackageById :: Verbosity -> LocalBuildInfo -> UnitId -> IO (Maybe InstalledPackageInfo) +getInstalledPackageById verbosity LocalBuildInfo{compiler,withPackageDB,withPrograms} unitid = do + ipindex <- getInstalledPackages verbosity compiler withPackageDB withPrograms + return $ lookupUnitId ipindex unitid + + -- | The user interface specifies the package dbs to use with a combination of -- @--global@, @--user@ and @--package-db=global|user|clear|$file@. -- This function combines the global/user flag and interprets the package-db diff --git a/Cabal/src/Distribution/Simple/GHC/BuildGeneric.hs b/Cabal/src/Distribution/Simple/GHC/BuildGeneric.hs index 16bd94294ee..7ff326aa9b3 100644 --- a/Cabal/src/Distribution/Simple/GHC/BuildGeneric.hs +++ b/Cabal/src/Distribution/Simple/GHC/BuildGeneric.hs @@ -19,7 +19,6 @@ import Distribution.PackageDescription.Utils (cabalBug) import Distribution.Pretty import Distribution.Simple.BuildPaths import Distribution.Simple.Compiler -import Distribution.Simple.Flag (Flag (..), fromFlag, toFlag) import Distribution.Simple.GHC.Build ( checkNeedsRecompilation , componentGhcOptions @@ -39,7 +38,7 @@ import Distribution.Simple.LocalBuildInfo import qualified Distribution.Simple.PackageIndex as PackageIndex import Distribution.Simple.Program import Distribution.Simple.Program.GHC -import Distribution.Simple.Setup.Config +import Distribution.Simple.Setup.Common import Distribution.Simple.Setup.Repl import Distribution.Simple.Utils import Distribution.System @@ -399,10 +398,9 @@ gbuild verbosity numJobs pkg_descr lbi bm clbi = do -- Determine if program coverage should be enabled and if so, what -- '-hpcdir' should be. let isCoverageEnabled = exeCoverage lbi - distPref = fromFlag $ configDistPref $ configFlags lbi hpcdir way | gbuildIsRepl bm = mempty -- HPC is not supported in ghci - | isCoverageEnabled = toFlag $ Hpc.mixDir distPref way + | isCoverageEnabled = toFlag $ Hpc.mixDir (tmpDir extraCompilationArtifacts) way | otherwise = mempty rpaths <- getRPaths lbi clbi diff --git a/Cabal/src/Distribution/Simple/GHC/BuildOrRepl.hs b/Cabal/src/Distribution/Simple/GHC/BuildOrRepl.hs index bfb9ddfa09c..8ae87642b51 100644 --- a/Cabal/src/Distribution/Simple/GHC/BuildOrRepl.hs +++ b/Cabal/src/Distribution/Simple/GHC/BuildOrRepl.hs @@ -9,7 +9,6 @@ import Distribution.Package import Distribution.PackageDescription as PD import Distribution.Simple.BuildPaths import Distribution.Simple.Compiler -import Distribution.Simple.Flag (Flag (..), fromFlag, toFlag) import Distribution.Simple.GHC.Build ( checkNeedsRecompilation , componentGhcOptions @@ -27,7 +26,7 @@ import Distribution.Simple.Program import qualified Distribution.Simple.Program.Ar as Ar import Distribution.Simple.Program.GHC import qualified Distribution.Simple.Program.Ld as Ld -import Distribution.Simple.Setup.Config +import Distribution.Simple.Setup.Common import Distribution.Simple.Setup.Repl import Distribution.Simple.Utils import Distribution.System @@ -96,10 +95,9 @@ buildOrReplLib mReplFlags verbosity numJobs pkg_descr lbi lib clbi = do -- Determine if program coverage should be enabled and if so, what -- '-hpcdir' should be. let isCoverageEnabled = libCoverage lbi - distPref = fromFlag $ configDistPref $ configFlags lbi hpcdir way | forRepl = mempty -- HPC is not supported in ghci - | isCoverageEnabled = toFlag $ Hpc.mixDir distPref way + | isCoverageEnabled = toFlag $ Hpc.mixDir (libTargetDir extraCompilationArtifacts) way | otherwise = mempty createDirectoryIfMissingVerbose verbosity True libTargetDir diff --git a/Cabal/src/Distribution/Simple/GHCJS.hs b/Cabal/src/Distribution/Simple/GHCJS.hs index 1c4d899812d..53f78b7e5e6 100644 --- a/Cabal/src/Distribution/Simple/GHCJS.hs +++ b/Cabal/src/Distribution/Simple/GHCJS.hs @@ -72,7 +72,7 @@ import Distribution.Simple.Program import Distribution.Simple.Program.GHC import qualified Distribution.Simple.Program.HcPkg as HcPkg import qualified Distribution.Simple.Program.Strip as Strip -import Distribution.Simple.Setup.Config +import Distribution.Simple.Setup.Common import Distribution.Simple.Utils import Distribution.System import Distribution.Types.ComponentLocalBuildInfo @@ -515,10 +515,9 @@ buildOrReplLib mReplFlags verbosity numJobs _pkg_descr lbi lib clbi = do -- Determine if program coverage should be enabled and if so, what -- '-hpcdir' should be. let isCoverageEnabled = libCoverage lbi - distPref = fromFlag $ configDistPref $ configFlags lbi hpcdir way | forRepl = mempty -- HPC is not supported in ghci - | isCoverageEnabled = toFlag $ Hpc.mixDir distPref way + | isCoverageEnabled = toFlag $ Hpc.mixDir (libTargetDir extraCompilationArtifacts) way | otherwise = mempty createDirectoryIfMissingVerbose verbosity True libTargetDir @@ -1235,10 +1234,9 @@ gbuild verbosity numJobs pkg_descr lbi bm clbi = do -- Determine if program coverage should be enabled and if so, what -- '-hpcdir' should be. let isCoverageEnabled = exeCoverage lbi - distPref = fromFlag $ configDistPref $ configFlags lbi hpcdir way | gbuildIsRepl bm = mempty -- HPC is not supported in ghci - | isCoverageEnabled = toFlag $ Hpc.mixDir distPref way + | isCoverageEnabled = toFlag $ Hpc.mixDir (tmpDir extraCompilationArtifacts) way | otherwise = mempty rpaths <- getRPaths lbi clbi diff --git a/Cabal/src/Distribution/Simple/Hpc.hs b/Cabal/src/Distribution/Simple/Hpc.hs index e39b75d4ae4..a025fc95403 100644 --- a/Cabal/src/Distribution/Simple/Hpc.hs +++ b/Cabal/src/Distribution/Simple/Hpc.hs @@ -28,21 +28,19 @@ module Distribution.Simple.Hpc import Distribution.Compat.Prelude import Prelude () -import Distribution.ModuleName (main) +import Distribution.ModuleName (main, ModuleName) import Distribution.PackageDescription ( TestSuite (..) , testModules ) import qualified Distribution.PackageDescription as PD import Distribution.Pretty -import Distribution.Simple.Flag (fromFlagOrDefault) import Distribution.Simple.LocalBuildInfo (LocalBuildInfo (..)) import Distribution.Simple.Program ( hpcProgram , requireProgramVersion ) import Distribution.Simple.Program.Hpc (markup, union) -import Distribution.Simple.Setup (TestFlags (..)) import Distribution.Simple.Utils (notice) import Distribution.Types.UnqualComponentName import Distribution.Verbosity (Verbosity ()) @@ -115,14 +113,15 @@ guessWay lbi -- | Generate the HTML markup for a package's test suites. markupPackage :: Verbosity - -> TestFlags + -> [FilePath] + -> [ModuleName] -> LocalBuildInfo -> FilePath -- ^ Testsuite \"dist/\" prefix -> PD.PackageDescription -> [TestSuite] -> IO () -markupPackage verbosity TestFlags{testCoverageDistPrefs, testCoverageLibsModules} lbi testDistPref pkg_descr suites = do +markupPackage verbosity testCoverageDistPrefs testCoverageLibsModules lbi testDistPref pkg_descr suites = do let tixFiles = map (tixFilePath testDistPref way) testNames tixFilesExist <- traverse doesFileExist tixFiles when (and tixFilesExist) $ do @@ -168,5 +167,5 @@ markupPackage verbosity TestFlags{testCoverageDistPrefs, testCoverageLibsModules where way = guessWay lbi testNames = fmap (unUnqualComponentName . testName) suites - mixDirs = map (`mixDir` way) (fromFlagOrDefault [] testCoverageDistPrefs) - included = fromFlagOrDefault [] testCoverageLibsModules + mixDirs = map (`mixDir` way) (testCoverageDistPrefs) + included = testCoverageLibsModules diff --git a/Cabal/src/Distribution/Simple/Setup/Config.hs b/Cabal/src/Distribution/Simple/Setup/Config.hs index 05fd07f33ca..cf3e400890c 100644 --- a/Cabal/src/Distribution/Simple/Setup/Config.hs +++ b/Cabal/src/Distribution/Simple/Setup/Config.hs @@ -54,6 +54,7 @@ import Distribution.Types.DumpBuildInfo import Distribution.Types.GivenComponent import Distribution.Types.Module import Distribution.Types.PackageVersionConstraint +import Distribution.Types.UnitId import Distribution.Utils.NubList import Distribution.Verbosity import qualified Text.PrettyPrint as Disp @@ -220,6 +221,11 @@ data ConfigFlags = ConfigFlags -- ^ Allow depending on private sublibraries. This is used by external -- tools (like cabal-install) so they can add multiple-public-libraries -- compatibility to older ghcs by checking visibility externally. + , configCoverageFor :: Flag [UnitId] + -- ^ The list of libraries to be included in the hpc coverage report for + -- testsuites run with @--enable-coverage@. Notably, this list must exclude + -- indefinite libraries and instantiations because HPC does not support + -- backpack (Nov. 2023). } deriving (Generic, Read, Show, Typeable) @@ -288,6 +294,7 @@ instance Eq ConfigFlags where && equal configDebugInfo && equal configDumpBuildInfo && equal configUseResponseFiles + && equal configCoverageFor where equal f = on (==) f a b @@ -828,6 +835,22 @@ configureOptions showOrParseArgs = configAllowDependingOnPrivateLibs (\v flags -> flags{configAllowDependingOnPrivateLibs = v}) trueArg + , option + "" + ["coverage-for"] + "Module of a project-local library to include in the HPC report" + configCoverageFor + ( \v flags -> + flags + { configCoverageFor = + mergeListFlag (configCoverageFor flags) v + } + ) + ( reqArg' + "MODULE" + (Flag . (: []) . fromString) + (fmap prettyShow . fromFlagOrDefault []) + ) ] where liftInstallDirs = diff --git a/Cabal/src/Distribution/Simple/Setup/Test.hs b/Cabal/src/Distribution/Simple/Setup/Test.hs index c2fa3f14d6d..bee0ccbef1a 100644 --- a/Cabal/src/Distribution/Simple/Setup/Test.hs +++ b/Cabal/src/Distribution/Simple/Setup/Test.hs @@ -40,7 +40,6 @@ import Distribution.Simple.Utils import Distribution.Verbosity import qualified Text.PrettyPrint as Disp -import Distribution.ModuleName (ModuleName) import Distribution.Simple.Setup.Common -- ------------------------------------------------------------ @@ -89,15 +88,6 @@ data TestFlags = TestFlags , testKeepTix :: Flag Bool , testWrapper :: Flag FilePath , testFailWhenNoTestSuites :: Flag Bool - , testCoverageLibsModules :: Flag [ModuleName] - -- ^ The list of all modules from libraries in the local project that should - -- be included in the hpc coverage report. - , testCoverageDistPrefs :: Flag [FilePath] - -- ^ The path to each library local to this project and to the test - -- components being built, to include in coverage reporting (notably, this - -- excludes indefinite libraries and instantiations because HPC does not - -- support backpack - Nov. 2023). Cabal uses these paths as dist prefixes to - -- determine the path to the `mix` dirs of each component to cover. , -- TODO: think about if/how options are passed to test exes testOptions :: [PathTemplate] } @@ -114,8 +104,6 @@ defaultTestFlags = , testKeepTix = toFlag False , testWrapper = NoFlag , testFailWhenNoTestSuites = toFlag False - , testCoverageLibsModules = NoFlag - , testCoverageDistPrefs = NoFlag , testOptions = [] } @@ -221,38 +209,6 @@ testOptions' showOrParseArgs = testFailWhenNoTestSuites (\v flags -> flags{testFailWhenNoTestSuites = v}) trueArg - , option - [] - ["coverage-module"] - "Module of a project-local library to include in the HPC report" - testCoverageLibsModules - ( \v flags -> - flags - { testCoverageLibsModules = - mergeListFlag (testCoverageLibsModules flags) v - } - ) - ( reqArg' - "MODULE" - (Flag . (: []) . fromString) - (fmap prettyShow . fromFlagOrDefault []) - ) - , option - [] - ["coverage-dist-dir"] - "The directory where Cabal puts generated build files of an HPC enabled component" - testCoverageDistPrefs - ( \v flags -> - flags - { testCoverageDistPrefs = - mergeListFlag (testCoverageDistPrefs flags) v - } - ) - ( reqArg' - "DIR" - (Flag . (: [])) - (fromFlagOrDefault []) - ) , option [] ["test-options"] diff --git a/Cabal/src/Distribution/Simple/Test.hs b/Cabal/src/Distribution/Simple/Test.hs index 62158ece57f..3c96648a3ed 100644 --- a/Cabal/src/Distribution/Simple/Test.hs +++ b/Cabal/src/Distribution/Simple/Test.hs @@ -1,4 +1,5 @@ {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE RankNTypes #-} ----------------------------------------------------------------------------- @@ -21,6 +22,8 @@ module Distribution.Simple.Test import Distribution.Compat.Prelude import Prelude () +import Control.Monad +import Distribution.ModuleName import qualified Distribution.PackageDescription as PD import Distribution.Pretty import Distribution.Simple.Compiler @@ -46,6 +49,13 @@ import System.Directory , removeFile ) import System.FilePath (()) +import Distribution.Simple.Setup.Config +import Distribution.Types.LocalBuildInfo (LocalBuildInfo(..)) +import Distribution.Simple.Configure (getInstalledPackageById) +import Distribution.Simple.Setup (fromFlagOrDefault) +import Distribution.Types.InstalledPackageInfo (InstalledPackageInfo(libraryDirs), exposedModules) +import Distribution.Types.ExposedModule +import Distribution.Simple.Setup.Common (extraCompilationArtifacts) -- | Perform the \"@.\/setup test@\" action. test @@ -68,16 +78,20 @@ test args pkg_descr lbi flags = do enabledTests = LBI.enabledTestLBIs pkg_descr lbi doTest - :: ( (PD.TestSuite, LBI.ComponentLocalBuildInfo) + :: [FilePath] + -- ^ The paths to the library components to include in the coverage report + -> [ModuleName] + -- ^ The modules to include in the coverage report + -> ( (PD.TestSuite, LBI.ComponentLocalBuildInfo) , Maybe TestSuiteLog ) -> IO TestSuiteLog - doTest ((suite, clbi), _) = + doTest testCoverageDistPrefs testCoverageLibsModules ((suite, clbi), _) = case PD.testInterface suite of PD.TestSuiteExeV10 _ _ -> - ExeV10.runTest pkg_descr lbi clbi flags suite + ExeV10.runTest pkg_descr lbi clbi testCoverageDistPrefs testCoverageLibsModules flags suite PD.TestSuiteLibV09 _ _ -> - LibV09.runTest pkg_descr lbi clbi flags suite + LibV09.runTest pkg_descr lbi clbi testCoverageDistPrefs testCoverageLibsModules flags suite _ -> return TestSuiteLog @@ -122,9 +136,39 @@ test args pkg_descr lbi flags = do >>= filterM doesFileExist . map (testLogDir ) >>= traverse_ removeFile + -- We configured the unit-ids of libraries we should cover in our coverage + -- report at configure time into the local build info. At build time, we built + -- the hpc artifacts into the extraCompilationArtifacts directory, which, at + -- install time, is copied into the ghc-pkg database files. + -- Now, we get the path to the HPC artifacts and exposed modules of each + -- library by querying the package database keyed by unit-id: + let coverageFor = fromFlagOrDefault [] (configCoverageFor (configFlags lbi)) + ipkginfos <- catMaybes <$> mapM (getInstalledPackageById verbosity lbi) coverageFor + let ( concat -> testCoverageDistPrefs0, + concat -> testCoverageLibsModules ) = + -- ROMES:TODO: Is it right to use libraryDirs here? When do we have + -- more than one library dir for an installed package? + unzip $ map ( \ip -> ( map ( extraCompilationArtifacts) $ libraryDirs ip + , map exposedName $ exposedModules ip ) + ) ipkginfos + + -- Additionally, we find the path to the testsuites' hpc build artifacts + suitesInstalledInfo <- + catMaybes <$> + mapM ( getInstalledPackageById verbosity lbi + . LBI.componentUnitId + . snd . fst ) testsToRun + let testCoverageDistPrefs = + testCoverageDistPrefs0 + ++ ( concat + . map ( map ( extraCompilationArtifacts) + . libraryDirs + ) + $ suitesInstalledInfo ) + let totalSuites = length testsToRun notice verbosity $ "Running " ++ show totalSuites ++ " test suites..." - suites <- traverse doTest testsToRun + suites <- traverse (doTest testCoverageDistPrefs testCoverageLibsModules) testsToRun let packageLog = (localPackageLog pkg_descr lbi){testSuites = suites} packageLogFile = () testLogDir $ @@ -133,7 +177,7 @@ test args pkg_descr lbi flags = do writeFile packageLogFile $ show packageLog when (LBI.testCoverage lbi) $ - markupPackage verbosity flags lbi distPref pkg_descr $ + markupPackage verbosity testCoverageDistPrefs testCoverageLibsModules lbi distPref pkg_descr $ map (fst . fst) testsToRun unless allOk exitFailure diff --git a/Cabal/src/Distribution/Simple/Test/ExeV10.hs b/Cabal/src/Distribution/Simple/Test/ExeV10.hs index af734c5123e..6931a3601cc 100644 --- a/Cabal/src/Distribution/Simple/Test/ExeV10.hs +++ b/Cabal/src/Distribution/Simple/Test/ExeV10.hs @@ -8,6 +8,7 @@ module Distribution.Simple.Test.ExeV10 import Distribution.Compat.Prelude import Prelude () +import Distribution.ModuleName import Distribution.Compat.Environment import qualified Distribution.PackageDescription as PD import Distribution.Simple.Build.PathsModule @@ -44,10 +45,14 @@ runTest :: PD.PackageDescription -> LBI.LocalBuildInfo -> LBI.ComponentLocalBuildInfo + -> [FilePath] + -- ^ The paths to the library components to include in the coverage report + -> [ModuleName] + -- ^ The modules to include in the coverage report -> TestFlags -> PD.TestSuite -> IO TestSuiteLog -runTest pkg_descr lbi clbi flags suite = do +runTest pkg_descr lbi clbi testCoverageDistPrefs testCoverageLibModules flags suite = do let isCoverageEnabled = LBI.testCoverage lbi way = guessWay lbi tixDir_ = tixDir distPref way @@ -178,7 +183,7 @@ runTest pkg_descr lbi clbi flags suite = do when (null $ PD.allLibraries pkg_descr) $ dieWithException verbosity TestCoverageSupport - markupPackage verbosity flags lbi distPref pkg_descr [suite] + markupPackage verbosity testCoverageDistPrefs testCoverageLibModules lbi distPref pkg_descr [suite] return suiteLog where diff --git a/Cabal/src/Distribution/Simple/Test/LibV09.hs b/Cabal/src/Distribution/Simple/Test/LibV09.hs index 3204ce12227..347d07e1510 100644 --- a/Cabal/src/Distribution/Simple/Test/LibV09.hs +++ b/Cabal/src/Distribution/Simple/Test/LibV09.hs @@ -58,10 +58,14 @@ runTest :: PD.PackageDescription -> LBI.LocalBuildInfo -> LBI.ComponentLocalBuildInfo + -> [FilePath] + -- ^ The paths to the library components to include in the coverage report + -> [ModuleName] + -- ^ The modules to include in the coverage report -> TestFlags -> PD.TestSuite -> IO TestSuiteLog -runTest pkg_descr lbi clbi flags suite = do +runTest pkg_descr lbi clbi testCoverageDistPrefs testCoverageLibModules flags suite = do let isCoverageEnabled = LBI.testCoverage lbi way = guessWay lbi @@ -194,7 +198,7 @@ runTest pkg_descr lbi clbi flags suite = do when (null $ PD.allLibraries pkg_descr) $ dieWithException verbosity TestCoverageSupport - markupPackage verbosity flags lbi distPref pkg_descr [suite] + markupPackage verbosity testCoverageDistPrefs testCoverageLibModules lbi distPref pkg_descr [suite] return suiteLog where diff --git a/Plan.md b/Plan.md new file mode 100644 index 00000000000..de7e22fe6ed --- /dev/null +++ b/Plan.md @@ -0,0 +1,29 @@ +Plan: + +[ ] cabal-install determines units to cover +[ ] Cabal determines units to cover on its own when it is being built per package +[ ] cabal-install passes --coverage-for= to ./Setup configure for each + component that we configure + +[x] Cabal configure accepts --coverage-for= + +-- For libraries with --enable-coverage +[x] ./Setup build will write the hpc directories into extraSomethingArtifacts +[x] ./Setup install will copy the extraSomethingArtifacts to the pkg-db entry for + that component + +-- For testsuite +[ ] ./Setup test will read all --coverage-for= from LBI +[ ] Then read the hpc directories from the extraSomethingArtifacts for each of + the units-ids (that should be installed) +[ ] Then pass those directories to the `hpc markup --hpcdir=$(ghc-pkg read unit-id | ls hpc)` call + + +-- Whole package +./Setup configure --coverage-for= + +[ ] How do we handle interface files in whole-package setup configure? That's + basically what we need. + +[ ] In the commit message mention interface file analogy + diff --git a/cabal-install/src/Distribution/Client/Config.hs b/cabal-install/src/Distribution/Client/Config.hs index feaf10a6360..0fe93081bd7 100644 --- a/cabal-install/src/Distribution/Client/Config.hs +++ b/cabal-install/src/Distribution/Client/Config.hs @@ -531,6 +531,7 @@ instance Semigroup SavedConfig where , configDumpBuildInfo = combine configDumpBuildInfo , configAllowDependingOnPrivateLibs = combine configAllowDependingOnPrivateLibs + , configCoverageFor = combine configCoverageFor } where combine = combine' savedConfigureFlags @@ -636,8 +637,6 @@ instance Semigroup SavedConfig where , testKeepTix = combine testKeepTix , testWrapper = combine testWrapper , testFailWhenNoTestSuites = combine testFailWhenNoTestSuites - , testCoverageLibsModules = combine testCoverageLibsModules - , testCoverageDistPrefs = combine testCoverageDistPrefs , testOptions = lastNonEmpty testOptions } where diff --git a/cabal-install/src/Distribution/Client/ProjectBuilding.hs b/cabal-install/src/Distribution/Client/ProjectBuilding.hs index 1b00113d8e7..84ae5da18e8 100644 --- a/cabal-install/src/Distribution/Client/ProjectBuilding.hs +++ b/cabal-install/src/Distribution/Client/ProjectBuilding.hs @@ -1356,6 +1356,7 @@ buildAndInstallUnpackedPackage configureFlags v = flip filterConfigureFlags v $ setupHsConfigureFlags + plan rpkg pkgshared verbosity @@ -1714,6 +1715,7 @@ buildInplaceUnpackedPackage configureFlags v = flip filterConfigureFlags v $ setupHsConfigureFlags + plan rpkg pkgshared verbosity @@ -1734,11 +1736,8 @@ buildInplaceUnpackedPackage testFlags v = flip filterTestFlags v $ setupHsTestFlags - plan pkg - pkgshared verbosity - distDirLayout builddir testArgs _ = setupHsTestArgs pkg diff --git a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs index 1ddff54b7f7..d949437f5d6 100644 --- a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs +++ b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs @@ -727,6 +727,7 @@ convertLegacyPerPackageFlags , configDebugInfo = packageConfigDebugInfo , configDumpBuildInfo = packageConfigDumpBuildInfo , configRelocatable = packageConfigRelocatable + , configCoverageFor = _ } = configFlags packageConfigProgramPaths = MapLast (Map.fromList configProgramPaths) packageConfigProgramArgs = MapMappend (Map.fromListWith (++) configProgramArgs) @@ -767,8 +768,6 @@ convertLegacyPerPackageFlags , testKeepTix = packageConfigTestKeepTix , testWrapper = packageConfigTestWrapper , testFailWhenNoTestSuites = packageConfigTestFailWhenNoTestSuites - , testCoverageLibsModules = _ - , testCoverageDistPrefs = _ , testOptions = packageConfigTestTestOptions } = testFlags @@ -1039,6 +1038,7 @@ convertToLegacyAllPackageConfig , configUseResponseFiles = mempty , configDumpBuildInfo = mempty , configAllowDependingOnPrivateLibs = mempty + , configCoverageFor = mempty } haddockFlags = @@ -1115,6 +1115,7 @@ convertToLegacyPerPackageConfig PackageConfig{..} = , configUseResponseFiles = mempty , configDumpBuildInfo = packageConfigDumpBuildInfo , configAllowDependingOnPrivateLibs = mempty + , configCoverageFor = mempty } installFlags = @@ -1162,8 +1163,6 @@ convertToLegacyPerPackageConfig PackageConfig{..} = , testKeepTix = packageConfigTestKeepTix , testWrapper = packageConfigTestWrapper , testFailWhenNoTestSuites = packageConfigTestFailWhenNoTestSuites - , testCoverageLibsModules = mempty - , testCoverageDistPrefs = mempty , testOptions = packageConfigTestTestOptions } diff --git a/cabal-install/src/Distribution/Client/ProjectOrchestration.hs b/cabal-install/src/Distribution/Client/ProjectOrchestration.hs index 18ea8cf826c..1800f52d7ff 100644 --- a/cabal-install/src/Distribution/Client/ProjectOrchestration.hs +++ b/cabal-install/src/Distribution/Client/ProjectOrchestration.hs @@ -1039,6 +1039,7 @@ printPlan showConfigureFlags elab = let fullConfigureFlags = setupHsConfigureFlags + elaboratedPlan (ReadyPackage elab) elaboratedShared verbosity diff --git a/cabal-install/src/Distribution/Client/ProjectPlanning.hs b/cabal-install/src/Distribution/Client/ProjectPlanning.hs index 4417b1eef24..77a3852480a 100644 --- a/cabal-install/src/Distribution/Client/ProjectPlanning.hs +++ b/cabal-install/src/Distribution/Client/ProjectPlanning.hs @@ -21,7 +21,7 @@ module Distribution.Client.ProjectPlanning , BuildStyle (..) , CabalFileText - -- * Producing the elaborated install plan + -- * Producing the elaborated install plan , rebuildProjectConfig , rebuildInstallPlan @@ -149,7 +149,6 @@ import Distribution.Simple.Program.Db import Distribution.Simple.Program.Find import Distribution.Simple.Setup ( Flag (..) - , TestFlags (testCoverageDistPrefs) , flagToList , flagToMaybe , fromFlagOrDefault @@ -4085,12 +4084,14 @@ computeInstallDirs storeDirLayout defaultInstallDirs elaboratedShared elab -- make the various Setup.hs {configure,build,copy} flags setupHsConfigureFlags - :: ElaboratedReadyPackage + :: ElaboratedInstallPlan + -> ElaboratedReadyPackage -> ElaboratedSharedConfig -> Verbosity -> FilePath -> Cabal.ConfigFlags setupHsConfigureFlags + plan (ReadyPackage elab@ElaboratedConfiguredPackage{..}) sharedConfig@ElaboratedSharedConfig{..} verbosity @@ -4236,6 +4237,8 @@ setupHsConfigureFlags Just _ -> error "non-library dependency" Nothing -> LMainLibName + configCoverageFor = determineCoverageFor elabPkgSourceId plan + setupHsConfigureArgs :: ElaboratedConfiguredPackage -> [String] @@ -4282,14 +4285,11 @@ setupHsBuildArgs (ElaboratedConfiguredPackage{elabPkgOrComp = ElabComponent _}) [] setupHsTestFlags - :: ElaboratedInstallPlan - -> ElaboratedConfiguredPackage - -> ElaboratedSharedConfig + :: ElaboratedConfiguredPackage -> Verbosity - -> DistDirLayout -> FilePath -> Cabal.TestFlags -setupHsTestFlags plan (ElaboratedConfiguredPackage{..}) sharedConfig verbosity distDirLayout builddir = +setupHsTestFlags (ElaboratedConfiguredPackage{..}) verbosity builddir = Cabal.TestFlags { testDistPref = toFlag builddir , testVerbosity = toFlag verbosity @@ -4299,47 +4299,8 @@ setupHsTestFlags plan (ElaboratedConfiguredPackage{..}) sharedConfig verbosity d , testKeepTix = toFlag elabTestKeepTix , testWrapper = maybe mempty toFlag elabTestWrapper , testFailWhenNoTestSuites = toFlag elabTestFailWhenNoTestSuites - , testCoverageLibsModules = toFlag covIncludeModules - , testCoverageDistPrefs = toFlag covLibsDistPref , testOptions = elabTestTestOptions } - where - -- The path to dist dir of each of the libraries to consider in hpc, from which Cabal determines the path to the `mix` dir. - covLibsDistPref = map (distBuildDirectory distDirLayout . elabDistDirParams sharedConfig) librariesToCover - -- The list of modules from libraries to consider in hpc, that Cabal passes to the hpc markup call - -- This list includes all modules, not only the exposed ones. - covIncludeModules = concatMap (\ElaboratedConfiguredPackage{elabModuleShape = modShape} -> Map.keys $ modShapeProvides modShape) librariesToCover - - -- The list of non-pre-existing libraries without module holes, i.e. the - -- main library and sub-libraries components of all the local packages in - -- the project that do not require instantiations or are instantiations, - -- and the testsuite component. - -- - -- TODO: I think that if the packages it depends on are still uninstalled, - -- this seemingly includes the packages that are not local to the project?! - -- Weird, because we filter on localToProject! - -- Try it on cabal-install: cabal test --enable-coverage cabal-install - librariesToCover = - mapMaybe - ( \case - InstallPlan.Installed elab - | shouldCoverPkg elab -> Just elab - InstallPlan.Configured elab - | shouldCoverPkg elab -> Just elab - _ -> Nothing - ) - $ Graph.toList - $ InstallPlan.toGraph plan - - shouldCoverPkg ElaboratedConfiguredPackage{elabModuleShape = modShape, elabPkgSourceId = pkgId} = - elabLocalToProject - && not (isIndefiniteOrInstantiation modShape) - -- TODO(#9493): We can only cover libraries in the same package - -- as the testsuite - && pkgId == elabPkgSourceId - - isIndefiniteOrInstantiation :: ModuleShape -> Bool - isIndefiniteOrInstantiation = not . Set.null . modShapeRequires setupHsTestArgs :: ElaboratedConfiguredPackage -> [String] -- TODO: Does the issue #3335 affects test as well @@ -4681,3 +4642,36 @@ inplaceBinRoot inplaceBinRoot layout config package = distBuildDirectory layout (elabDistDirParams config package) "build" + +-------------------------------------------------------------------------------- +-- Configure --coverage-for flags + +-- The list of non-pre-existing libraries without module holes, i.e. the +-- main library and sub-libraries components of all the local packages in +-- the project that do not require instantiations or are instantiations. +determineCoverageFor :: PackageId + -- ^ The 'PackageId' of the package or component being configured + -> ElaboratedInstallPlan + -> Flag [UnitId] +determineCoverageFor configuredPkgSourceId plan = Flag $ + mapMaybe + ( \case + InstallPlan.Installed elab + | shouldCoverPkg elab -> Just $ elabUnitId elab + InstallPlan.Configured elab + | shouldCoverPkg elab -> Just $ elabUnitId elab + _ -> Nothing + ) + $ Graph.toList + $ InstallPlan.toGraph plan + where + shouldCoverPkg ElaboratedConfiguredPackage{elabModuleShape, elabPkgSourceId, elabLocalToProject} = + elabLocalToProject + && not (isIndefiniteOrInstantiation elabModuleShape) + -- TODO(#9493): We can only cover libraries in the same package + -- as the testsuite + && configuredPkgSourceId == elabPkgSourceId + + isIndefiniteOrInstantiation :: ModuleShape -> Bool + isIndefiniteOrInstantiation = not . Set.null . modShapeRequires + diff --git a/cabal-install/src/Distribution/Client/Setup.hs b/cabal-install/src/Distribution/Client/Setup.hs index 5489706ac8e..348d7fcd1e2 100644 --- a/cabal-install/src/Distribution/Client/Setup.hs +++ b/cabal-install/src/Distribution/Client/Setup.hs @@ -802,8 +802,8 @@ filterConfigureFlags flags cabalLibVersion } -- Cabal < 1.10.0 doesn't know about '--disable-tests'. flags_1_10_0 = flags_1_12_0{configTests = NoFlag} - -- Cabal < 1.3.10 does not grok the '--constraints' flag. - flags_1_3_10 = flags_1_10_0{configConstraints = []} + -- Cabal < 1.3.10 does not grok the '--constraints' flag nor --coverage-for. + flags_1_3_10 = flags_1_10_0{configConstraints = [], configCoverageFor = NoFlag} -- | Get the package database settings from 'ConfigFlags', accounting for -- @--package-db@ and @--user@ flags. @@ -1093,24 +1093,18 @@ filterTestFlags :: TestFlags -> Version -> TestFlags filterTestFlags flags cabalLibVersion -- NB: we expect the latest version to be the most common case, -- so test it first. - | cabalLibVersion >= mkVersion [3, 11, 0] = flags_latest + | cabalLibVersion >= mkVersion [3, 0, 0] = flags_latest -- The naming convention is that flags_version gives flags with -- all flags *introduced* in version eliminated. -- It is NOT the latest version of Cabal library that -- these flags work for; version of introduction is a more -- natural metric. - | cabalLibVersion < mkVersion [3, 11, 0] = flags_3_10_0 | cabalLibVersion < mkVersion [3, 0, 0] = flags_3_0_0 | otherwise = error "the impossible just happened" -- see first guard where flags_latest = flags - flags_3_10_0 = - flags_latest - { Cabal.testCoverageLibsModules = NoFlag - , Cabal.testCoverageDistPrefs = NoFlag - } flags_3_0_0 = - flags_3_10_0 + flags_latest { -- Cabal < 3.0 doesn't know about --test-wrapper Cabal.testWrapper = NoFlag }