Skip to content

Commit 10c13d8

Browse files
committed
Allow build-type Configure to work with Components
When components were introduced, cabal had support for build-type: Configure, which allows to run a `configure` script prior to building the package. Upon the introduction of components, it became obvious that we can't just configure each and every component, as this easily runs into the situation where the `configure` script is run potentially concurrently for all components. Due to recent changes to cabal-install and lib:Cabal, cabal is CWD aware, and concurrently executed `configure` scripts won't step on each other anymore. However, build-type is a global option for cabal files, and is usually used to produce a <pkg>.buildinfo file. This file is then used to augment the Main Library and Executables only. This change now tracks whether or not we are building a main library or executable component, and if we do, retains only for these components the build-type: Configure from the package description. For all other components, we will fall back to the default build-type: Simple. For end users who want to depend on package configured values, they will need to set their sub libraries, testsuites and benchmark components to depend on the main library, and import any configured values from there. For lib:Cabal, which doesn't know about components when configure is invoked, we will continue to execute configure. There is no impact on lib:Cabal in this change. This can appraoch may be further improved once we have turned Setup (Setup.hs/SetupHooks.hs) into a separate Setup component on which each component depends. Notably for Make, Configure, and Simple, cabal-install does not need to compiler a Setup.hs/SetupHooks.hs and can often rely on the act-as-setup (internal setup) method.
1 parent dfe29cd commit 10c13d8

File tree

19 files changed

+3238
-13
lines changed

19 files changed

+3238
-13
lines changed

cabal-install/src/Distribution/Client/Configure.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ configureSetupScript
299299
, useDependenciesExclusive = not defaultSetupDeps && isJust explicitSetupDeps
300300
, useVersionMacros = not defaultSetupDeps && isJust explicitSetupDeps
301301
, isInteractive = False
302+
, isMainLibOrExeComponent = True
302303
}
303304
where
304305
-- When we are compiling a legacy setup script without an explicit

cabal-install/src/Distribution/Client/ProjectPlanning.hs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1712,19 +1712,17 @@ elaborateInstallPlan
17121712
why_not_per_component g =
17131713
cuz_buildtype ++ cuz_spec ++ cuz_length ++ cuz_flag
17141714
where
1715-
-- We have to disable per-component for now with
1716-
-- Configure-type scripts in order to prevent parallel
1717-
-- invocation of the same `./configure` script.
1718-
-- See https://github.com/haskell/cabal/issues/4548
1719-
--
1720-
-- Moreover, at this point in time, only non-Custom setup scripts
1721-
-- are supported. Implementing per-component builds with
1722-
-- Custom would require us to create a new 'ElabSetup'
1723-
-- type, and teach all of the code paths how to handle it.
1715+
-- Custom and Hooks are not implemented. Implementing
1716+
-- per-component builds with Custom would require us to create a
1717+
-- new 'ElabSetup' type, and teach all of the code paths how to
1718+
-- handle it.
17241719
-- Once you've implemented this, swap it for the code below.
17251720
cuz_buildtype =
17261721
case bt of
1727-
PD.Configure -> [CuzBuildType CuzConfigureBuildType]
1722+
PD.Configure -> []
1723+
-- Configure is supported, but we only support configuring the
1724+
-- main library in cabal. Other components will need to depend
1725+
-- on the main library for configured data.
17281726
PD.Custom -> [CuzBuildType CuzCustomBuildType]
17291727
PD.Hooks -> [CuzBuildType CuzHooksBuildType]
17301728
PD.Make -> [CuzBuildType CuzMakeBuildType]
@@ -3879,6 +3877,16 @@ setupHsScriptOptions
38793877
, forceExternalSetupMethod = isParallelBuild
38803878
, setupCacheLock = Just cacheLock
38813879
, isInteractive = False
3880+
, isMainLibOrExeComponent = case elabPkgOrComp of
3881+
-- if it's a package, it's all together, so we have to assume it's
3882+
-- at least a library or executable.
3883+
ElabPackage _ -> True
3884+
-- if it's a component, we have to check if it's a Main Library or Executable
3885+
-- as opposed to SubLib, FLib, Test, Bench, or Setup component.
3886+
ElabComponent (ElaboratedComponent{compSolverName = CD.ComponentLib}) -> True
3887+
ElabComponent (ElaboratedComponent{compSolverName = CD.ComponentExe _}) -> True
3888+
-- everything else is not a main lib or exe component
3889+
ElabComponent _ -> False
38823890
}
38833891

38843892
-- | To be used for the input for elaborateInstallPlan.

cabal-install/src/Distribution/Client/SetupWrapper.hs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,12 @@ data SetupScriptOptions = SetupScriptOptions
315315
-- ^ Is the task we are going to run an interactive foreground task,
316316
-- or an non-interactive background task? Based on this flag we
317317
-- decide whether or not to delegate ctrl+c to the spawned task
318+
, isMainLibOrExeComponent :: Bool
319+
-- ^ Let the setup script logic know if it is being run to build a main
320+
-- library or executable component. This is used to determine if we should
321+
-- use the configure command, if the build-type is 'Configure'. For
322+
-- configure, only the main library and execomponents have 'configure'
323+
-- support, and thus we can skip running configure for other components.
318324
}
319325

320326
defaultSetupScriptOptions :: SetupScriptOptions
@@ -339,6 +345,7 @@ defaultSetupScriptOptions =
339345
, forceExternalSetupMethod = False
340346
, setupCacheLock = Nothing
341347
, isInteractive = False
348+
, isMainLibOrExeComponent = True
342349
}
343350

344351
workingDir :: SetupScriptOptions -> FilePath
@@ -375,7 +382,14 @@ getSetup verbosity options mpkg = do
375382
(useCabalVersion options)
376383
(orLaterVersion (mkVersion (cabalSpecMinimumLibraryVersion (specVersion pkg))))
377384
}
378-
buildType' = buildType pkg
385+
-- We retain Configure only for the main library and executable components.
386+
-- For other components, we rewrite the buildType to Simple to skip the
387+
-- configure step. This is because the configure step is not supported for
388+
-- other components. Configure can only impact MainLib and Exe through
389+
-- .buildinfo files.
390+
buildType' = case (buildType pkg, isMainLibOrExeComponent options) of
391+
(Configure, False) -> Simple
392+
(bt, _) -> bt
379393
(version, method, options'') <-
380394
getSetupMethod verbosity options' pkg buildType'
381395
return
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# cabal build
2+
Configuration is affected by the following files:
3+
- cabal.project
4+
Resolving dependencies...
5+
Build profile: -w ghc-<GHCVER> -O1
6+
In order, the following will be built:
7+
- test-pkg-0.1.0.0 (lib) (first run)
8+
Configuring library for test-pkg-0.1.0.0...
9+
Preprocessing library for test-pkg-0.1.0.0...
10+
Building library for test-pkg-0.1.0.0...
11+
# cabal v2-build
12+
Configuration is affected by the following files:
13+
- cabal.project
14+
Build profile: -w ghc-<GHCVER> -O1
15+
In order, the following will be built:
16+
- test-pkg-0.1.0.0 (exe:exe) (first run)
17+
Configuring executable 'exe' for test-pkg-0.1.0.0...
18+
Preprocessing executable 'exe' for test-pkg-0.1.0.0...
19+
Building executable 'exe' for test-pkg-0.1.0.0...
20+
# cabal v2-run
21+
Configuration is affected by the following files:
22+
- cabal.project
23+
# cabal v2-run
24+
Configuration is affected by the following files:
25+
- cabal.project
26+
Build profile: -w ghc-<GHCVER> -O1
27+
In order, the following will be built:
28+
- test-pkg-0.1.0.0 (exe:exe-dep) (first run)
29+
Configuring executable 'exe-dep' for test-pkg-0.1.0.0...
30+
Preprocessing executable 'exe-dep' for test-pkg-0.1.0.0...
31+
Building executable 'exe-dep' for test-pkg-0.1.0.0...
32+
# cabal v2-build
33+
Configuration is affected by the following files:
34+
- cabal.project
35+
Build profile: -w ghc-<GHCVER> -O1
36+
In order, the following will be built:
37+
- test-pkg-0.1.0.0 (lib:foo) (first run)
38+
Configuring library 'foo' for test-pkg-0.1.0.0...
39+
Preprocessing library 'foo' for test-pkg-0.1.0.0...
40+
Building library 'foo' for test-pkg-0.1.0.0...
41+
# cabal v2-build
42+
Configuration is affected by the following files:
43+
- cabal.project
44+
Build profile: -w ghc-<GHCVER> -O1
45+
In order, the following will be built:
46+
- test-pkg-0.1.0.0 (lib:bar) (first run)
47+
Configuring library 'bar' for test-pkg-0.1.0.0...
48+
Preprocessing library 'bar' for test-pkg-0.1.0.0...
49+
Building library 'bar' for test-pkg-0.1.0.0...
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
packages: test-pkg
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import Test.Cabal.Prelude
2+
-- Test build-tool-depends between two packages
3+
main = cabalTest $ do
4+
-- main library, and executable should run configure and generate a
5+
-- buildinfo file.
6+
cabal' "build" ["test-pkg:test-pkg"] >>=
7+
assertOutputContains "config.status: creating test-pkg.buildinfo"
8+
cabal' "v2-build" ["test-pkg:exe"] >>=
9+
assertOutputContains "config.status: creating test-pkg.buildinfo"
10+
-- configure values should not be embeddable in the executable.
11+
cabal' "v2-run" ["test-pkg:exe"] >>=
12+
assertOutputContains "Hi-Exe"
13+
-- configure values should be embeddable in the library.
14+
cabal' "v2-run" ["test-pkg:exe-dep"] >>=
15+
assertOutputContains "Hi-Lib"
16+
-- sublibs should not run configure
17+
cabal' "v2-build" ["test-pkg:lib:foo"] >>=
18+
assertOutputDoesNotContain "config.status: creating test-pkg.buildinfo"
19+
cabal' "v2-build" ["test-pkg:lib:bar"] >>=
20+
assertOutputDoesNotContain "config.status: creating test-pkg.buildinfo"
21+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Revision history for test-pkg
2+
3+
## 0.1.0.0 -- YYYY-mm-dd
4+
5+
* First version. Released on an unsuspecting world.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
Copyright (c) 2025, Moritz Angermann
2+
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are met:
6+
7+
* Redistributions of source code must retain the above copyright
8+
notice, this list of conditions and the following disclaimer.
9+
10+
* Redistributions in binary form must reproduce the above
11+
copyright notice, this list of conditions and the following
12+
disclaimer in the documentation and/or other materials provided
13+
with the distribution.
14+
15+
* Neither the name of the copyright holder nor the names of its
16+
contributors may be used to endorse or promote products derived
17+
from this software without specific prior written permission.
18+
19+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23+
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

0 commit comments

Comments
 (0)