From a178c23fb7234e18a0f6a59f53f64e1490c3df85 Mon Sep 17 00:00:00 2001 From: Rodrigo Mesquita Date: Thu, 20 Jun 2024 10:52:50 +0100 Subject: [PATCH] Cabal: Add flag to ignore build tool dependencies Add a flag to disable the hard requirement on the build-tools-(depends) declared on the Cabal package. When this flag is enabled (--ignore-build-tools), a build-tool which can't be found does not block compilation. Fixes #10061 --- .../Distribution/Utils/Structured.hs | 2 +- Cabal/src/Distribution/Simple/Configure.hs | 50 ++++++++++--------- Cabal/src/Distribution/Simple/Setup/Config.hs | 15 ++++++ .../src/Distribution/Client/Config.hs | 1 + .../Client/ProjectConfig/Legacy.hs | 2 + .../Distribution/Client/ProjectPlanning.hs | 1 + .../src/Distribution/Client/Setup.hs | 10 ++-- .../PackageTests/IgnoreBuildTools/Hello.hs | 7 +++ .../IgnoreBuildTools/client.cabal | 13 +++++ .../PackageTests/IgnoreBuildTools/setup.out | 5 ++ .../IgnoreBuildTools/setup.test.hs | 5 ++ 11 files changed, 84 insertions(+), 27 deletions(-) create mode 100644 cabal-testsuite/PackageTests/IgnoreBuildTools/Hello.hs create mode 100644 cabal-testsuite/PackageTests/IgnoreBuildTools/client.cabal create mode 100644 cabal-testsuite/PackageTests/IgnoreBuildTools/setup.out create mode 100644 cabal-testsuite/PackageTests/IgnoreBuildTools/setup.test.hs diff --git a/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs b/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs index 54624a617c3..69d507c9d7e 100644 --- a/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs +++ b/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs @@ -41,7 +41,7 @@ md5CheckGenericPackageDescription proxy = md5Check proxy md5CheckLocalBuildInfo :: Proxy LocalBuildInfo -> Assertion md5CheckLocalBuildInfo proxy = md5Check proxy #if MIN_VERSION_base(4,19,0) - 0xdff58fe5e7f9568c67cd982eaba7edc2 + 0x7698165c53daaa3058415d0c89870fb8 #else 0x4e50a4a95779b862edde3d6696797251 #endif diff --git a/Cabal/src/Distribution/Simple/Configure.hs b/Cabal/src/Distribution/Simple/Configure.hs index 8d90b0d8822..0adefb57086 100644 --- a/Cabal/src/Distribution/Simple/Configure.hs +++ b/Cabal/src/Distribution/Simple/Configure.hs @@ -848,29 +848,33 @@ configurePackage cfg lbc0 pkg_descr00 flags enabled comp platform programDb0 pac -- right before calling configurePackage? -- Configure certain external build tools, see below for which ones. - let requiredBuildTools = do - bi <- enabledBuildInfos pkg_descr0 enabled - -- First, we collect any tool dep that we know is external. This is, - -- in practice: - -- - -- 1. `build-tools` entries on the whitelist - -- - -- 2. `build-tool-depends` that aren't from the current package. - let externBuildToolDeps = - [ LegacyExeDependency (unUnqualComponentName eName) versionRange - | buildTool@(ExeDependency _ eName versionRange) <- - getAllToolDependencies pkg_descr0 bi - , not $ isInternal pkg_descr0 buildTool - ] - -- Second, we collect any build-tools entry we don't know how to - -- desugar. We'll never have any idea how to build them, so we just - -- hope they are already on the PATH. - let unknownBuildTools = - [ buildTool - | buildTool <- buildTools bi - , Nothing == desugarBuildTool pkg_descr0 buildTool - ] - externBuildToolDeps ++ unknownBuildTools + let requiredBuildTools + -- If --ignore-build-tools is set, no build tool is required: + | fromFlagOrDefault False $ configIgnoreBuildTools cfg = + [] + | otherwise = do + bi <- enabledBuildInfos pkg_descr0 enabled + -- First, we collect any tool dep that we know is external. This is, + -- in practice: + -- + -- 1. `build-tools` entries on the whitelist + -- + -- 2. `build-tool-depends` that aren't from the current package. + let externBuildToolDeps = + [ LegacyExeDependency (unUnqualComponentName eName) versionRange + | buildTool@(ExeDependency _ eName versionRange) <- + getAllToolDependencies pkg_descr0 bi + , not $ isInternal pkg_descr0 buildTool + ] + -- Second, we collect any build-tools entry we don't know how to + -- desugar. We'll never have any idea how to build them, so we just + -- hope they are already on the PATH. + let unknownBuildTools = + [ buildTool + | buildTool <- buildTools bi + , Nothing == desugarBuildTool pkg_descr0 buildTool + ] + externBuildToolDeps ++ unknownBuildTools programDb1 <- configureAllKnownPrograms (lessVerbose verbosity) programDb0 diff --git a/Cabal/src/Distribution/Simple/Setup/Config.hs b/Cabal/src/Distribution/Simple/Setup/Config.hs index 14e76c7d769..385f61dd973 100644 --- a/Cabal/src/Distribution/Simple/Setup/Config.hs +++ b/Cabal/src/Distribution/Simple/Setup/Config.hs @@ -228,6 +228,10 @@ data ConfigFlags = ConfigFlags -- testsuites run with @--enable-coverage@. Notably, this list must exclude -- indefinite libraries and instantiations because HPC does not support -- backpack (Nov. 2023). + , configIgnoreBuildTools :: Flag Bool + -- ^ When this flag is set, all tools declared in `build-tool`s and + -- `build-tool-depends` will be ignored. This allows a Cabal package with + -- build-tool-dependencies to be built even if the tool is not found. } deriving (Generic, Read, Show, Typeable) @@ -319,7 +323,9 @@ instance Eq ConfigFlags where && equal configDebugInfo && equal configDumpBuildInfo && equal configUseResponseFiles + && equal configAllowDependingOnPrivateLibs && equal configCoverageFor + && equal configIgnoreBuildTools where equal f = on (==) f a b @@ -856,6 +862,15 @@ configureOptions showOrParseArgs = (Flag . (: []) . fromString) (fmap prettyShow . fromFlagOrDefault []) ) + , option + "" + ["ignore-build-tools"] + ( "Ignore build tool dependencies. " + ++ "If set, declared build tools needn't be found for compilation to proceed." + ) + configIgnoreBuildTools + (\v flags -> flags{configIgnoreBuildTools = v}) + trueArg ] where liftInstallDirs = diff --git a/cabal-install/src/Distribution/Client/Config.hs b/cabal-install/src/Distribution/Client/Config.hs index d9b91c959d0..a69bc9869fd 100644 --- a/cabal-install/src/Distribution/Client/Config.hs +++ b/cabal-install/src/Distribution/Client/Config.hs @@ -545,6 +545,7 @@ instance Semigroup SavedConfig where , configAllowDependingOnPrivateLibs = combine configAllowDependingOnPrivateLibs , configCoverageFor = combine configCoverageFor + , configIgnoreBuildTools = combine configIgnoreBuildTools } where combine = combine' savedConfigureFlags diff --git a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs index ddb6f615264..fe3442b0652 100644 --- a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs +++ b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs @@ -1112,6 +1112,7 @@ convertToLegacyAllPackageConfig , configDumpBuildInfo = mempty , configAllowDependingOnPrivateLibs = mempty , configCoverageFor = mempty + , configIgnoreBuildTools = mempty } haddockFlags = @@ -1188,6 +1189,7 @@ convertToLegacyPerPackageConfig PackageConfig{..} = , configDumpBuildInfo = packageConfigDumpBuildInfo , configAllowDependingOnPrivateLibs = mempty , configCoverageFor = mempty + , configIgnoreBuildTools = mempty } installFlags = diff --git a/cabal-install/src/Distribution/Client/ProjectPlanning.hs b/cabal-install/src/Distribution/Client/ProjectPlanning.hs index efc4ebbd1e4..3edace51bba 100644 --- a/cabal-install/src/Distribution/Client/ProjectPlanning.hs +++ b/cabal-install/src/Distribution/Client/ProjectPlanning.hs @@ -3960,6 +3960,7 @@ setupHsConfigureFlags configPrograms_ = mempty -- never use, shouldn't exist configUseResponseFiles = mempty configAllowDependingOnPrivateLibs = Flag $ not $ libraryVisibilitySupported pkgConfigCompiler + configIgnoreBuildTools = mempty cidToGivenComponent :: ConfiguredId -> GivenComponent cidToGivenComponent (ConfiguredId srcid mb_cn cid) = GivenComponent (packageName srcid) ln cid diff --git a/cabal-install/src/Distribution/Client/Setup.hs b/cabal-install/src/Distribution/Client/Setup.hs index 8fea76bae3b..e1273f35790 100644 --- a/cabal-install/src/Distribution/Client/Setup.hs +++ b/cabal-install/src/Distribution/Client/Setup.hs @@ -679,7 +679,7 @@ filterConfigureFlags' :: ConfigFlags -> Version -> ConfigFlags filterConfigureFlags' 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, 12, 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 @@ -701,15 +701,19 @@ filterConfigureFlags' flags cabalLibVersion | cabalLibVersion < mkVersion [2, 5, 0] = flags_2_5_0 | cabalLibVersion < mkVersion [3, 7, 0] = flags_3_7_0 | cabalLibVersion < mkVersion [3, 11, 0] = flags_3_11_0 + | cabalLibVersion < mkVersion [3, 12, 0] = flags_3_12_0 | otherwise = error "the impossible just happened" -- see first guard where - flags_latest = - flags + flags_latest = flags + + flags_3_12_0 = + flags_latest { -- Cabal >= 1.19.1 uses '--dependency' and does not need '--constraint'. -- Note: this is not in the wrong place. configConstraints gets -- repopulated in flags_1_19_1 but it needs to be set to empty for -- newer versions first. configConstraints = [] + , configIgnoreBuildTools = NoFlag } flags_3_11_0 = diff --git a/cabal-testsuite/PackageTests/IgnoreBuildTools/Hello.hs b/cabal-testsuite/PackageTests/IgnoreBuildTools/Hello.hs new file mode 100644 index 00000000000..4c2772407db --- /dev/null +++ b/cabal-testsuite/PackageTests/IgnoreBuildTools/Hello.hs @@ -0,0 +1,7 @@ +module Main where + +a :: String +a = "0000" + +main :: IO () +main = putStrLn a diff --git a/cabal-testsuite/PackageTests/IgnoreBuildTools/client.cabal b/cabal-testsuite/PackageTests/IgnoreBuildTools/client.cabal new file mode 100644 index 00000000000..fc69b378236 --- /dev/null +++ b/cabal-testsuite/PackageTests/IgnoreBuildTools/client.cabal @@ -0,0 +1,13 @@ +cabal-version: 3.0 +name: client +version: 0.1.0.0 +license: MIT +category: Testing +build-type: Simple + +executable hello-world + main-is: Hello.hs + build-depends: base + build-tool-depends: pre-proc:zero-to-one, another:non-existent + -- build-tools: somethingnonexists + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/IgnoreBuildTools/setup.out b/cabal-testsuite/PackageTests/IgnoreBuildTools/setup.out new file mode 100644 index 00000000000..de3c1b9d6bc --- /dev/null +++ b/cabal-testsuite/PackageTests/IgnoreBuildTools/setup.out @@ -0,0 +1,5 @@ +# Setup configure +Configuring client-0.1.0.0... +# Setup build +Preprocessing executable 'hello-world' for client-0.1.0.0... +Building executable 'hello-world' for client-0.1.0.0... diff --git a/cabal-testsuite/PackageTests/IgnoreBuildTools/setup.test.hs b/cabal-testsuite/PackageTests/IgnoreBuildTools/setup.test.hs new file mode 100644 index 00000000000..0a0297ad454 --- /dev/null +++ b/cabal-testsuite/PackageTests/IgnoreBuildTools/setup.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude +-- Test --ignore-build-tools ignores build-tools and build-tool-depends +main = setupTest $ do + setup "configure" ["--ignore-build-tools"] + setup "build" []