Skip to content

Commit 5588dc3

Browse files
committed
Fix build-tools ordering regression (haskell#3257, haskell#1541)
When converting the component graph to operate in terms of UnitIds instead of CNames I accidentally introduced a regression where we stopped respecting build-tools when determining an ordering to build things. This commit fixes the regression (though perhaps not in the most clean/performant way you could manage it.) It also fixes a latent bug if internal libraries aren't processed in the correct order. Signed-off-by: Edward Z. Yang <[email protected]>
1 parent 6943080 commit 5588dc3

File tree

8 files changed

+110
-10
lines changed

8 files changed

+110
-10
lines changed

Cabal/Distribution/Simple/Configure.hs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ import Text.PrettyPrint
127127
import Distribution.Compat.Environment ( lookupEnv )
128128
import Distribution.Compat.Exception ( catchExit, catchIO )
129129

130+
import Data.Graph (graphFromEdges, topSort)
131+
130132
-- | The errors that can be thrown when reading the @setup-config@ file.
131133
data ConfigStateFileError
132134
= ConfigStateFileNoHeader -- ^ No header found.
@@ -1436,7 +1438,7 @@ mkComponentsGraph pkg_descr internalPkgDeps =
14361438
| c <- pkgEnabledComponents pkg_descr ]
14371439
in case checkComponentsCyclic graph of
14381440
Just ccycle -> Left [ cname | (_,cname,_) <- ccycle ]
1439-
Nothing -> Right [ (c, cdeps) | (c, _, cdeps) <- graph ]
1441+
Nothing -> Right [ (c, cdeps) | (c, _, cdeps) <- topSortFromEdges graph ]
14401442
where
14411443
-- The dependencies for the given component
14421444
componentDeps component =
@@ -1620,6 +1622,12 @@ computeCompatPackageKey comp pkg_name pkg_version (SimpleUnitId (ComponentId str
16201622
| otherwise = str
16211623

16221624

1625+
topSortFromEdges :: Ord key => [(node, key, [key])]
1626+
-> [(node, key, [key])]
1627+
topSortFromEdges es =
1628+
let (graph, vertexToNode, _) = graphFromEdges es
1629+
in reverse (map vertexToNode (topSort graph))
1630+
16231631
mkComponentsLocalBuildInfo :: ConfigFlags
16241632
-> Compiler
16251633
-> InstalledPackageIndex
@@ -1635,14 +1643,15 @@ mkComponentsLocalBuildInfo cfg comp installedPackages pkg_descr
16351643
graph flagAssignment =
16361644
foldM go [] graph
16371645
where
1638-
go :: [(ComponentLocalBuildInfo, [UnitId])]
1639-
-> (Component, [ComponentName])
1640-
-> IO [(ComponentLocalBuildInfo, [UnitId])]
1641-
go z (component, _) = do
1646+
go z (component, dep_cnames) = do
16421647
clbi <- componentLocalBuildInfo z component
1643-
-- TODO: Maybe just store the internal deps in the clbi?
1644-
let dep_uids = map fst (filter (\(_,e) -> e `elem` internalPkgDeps)
1645-
(componentPackageDeps clbi))
1648+
-- NB: We want to preserve cdeps because it contains extra
1649+
-- information like build-tools ordering
1650+
let dep_uids = [ componentUnitId dep_clbi
1651+
| cname <- dep_cnames
1652+
-- Being in z relies on topsort!
1653+
, (dep_clbi, _) <- z
1654+
, componentLocalName dep_clbi == cname ]
16461655
return ((clbi, dep_uids):z)
16471656

16481657
-- The allPkgDeps contains all the package deps for the whole package
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module A where
2+
3+
a :: String
4+
a = "hello from A"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module Main where
2+
3+
import A
4+
5+
main :: IO ()
6+
main = putStrLn a
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module Main where
2+
3+
import System.Directory
4+
import System.Environment
5+
6+
main :: IO ()
7+
main = do
8+
(source:target:_) <- getArgs
9+
copyFile source target
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{-# OPTIONS_GHC -Wall #-}
2+
3+
import Distribution.PackageDescription
4+
import Distribution.Simple
5+
import Distribution.Simple.LocalBuildInfo
6+
import Distribution.Simple.PreProcess
7+
import Distribution.Simple.Utils
8+
import System.Exit
9+
import System.FilePath
10+
import System.Process (rawSystem)
11+
12+
main :: IO ()
13+
main = defaultMainWithHooks
14+
simpleUserHooks { hookedPreProcessors = [("pre", myCustomPreprocessor)] }
15+
where
16+
myCustomPreprocessor :: BuildInfo -> LocalBuildInfo -> ComponentLocalBuildInfo -> PreProcessor
17+
myCustomPreprocessor _bi lbi _clbi =
18+
PreProcessor {
19+
platformIndependent = True,
20+
runPreProcessor = mkSimplePreProcessor $ \inFile outFile verbosity ->
21+
do info verbosity ("Preprocessing " ++ inFile ++ " to " ++ outFile)
22+
callProcess progPath [inFile, outFile]
23+
}
24+
where
25+
builddir = buildDir lbi
26+
progName = "my-custom-preprocessor"
27+
progPath = builddir </> progName </> progName
28+
29+
-- Backwards compat with process < 1.2.
30+
callProcess :: FilePath -> [String] -> IO ()
31+
callProcess path args =
32+
do exitCode <- rawSystem path args
33+
case exitCode of ExitSuccess -> return ()
34+
f@(ExitFailure _) -> fail $ "callProcess " ++ show path
35+
++ " " ++ show args ++ " failed: "
36+
++ show f
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: internal-preprocessor-test
2+
version: 0.1.0.0
3+
synopsis: Internal custom preprocessor example.
4+
description: See https://github.com/haskell/cabal/issues/1541#issuecomment-30155513
5+
license: GPL-3
6+
author: Mikhail Glushenkov
7+
maintainer: [email protected]
8+
category: Testing
9+
build-type: Custom
10+
cabal-version: >=1.10
11+
12+
-- Note that exe comes before the library.
13+
-- The reason is backwards compat: old versions of Cabal (< 1.18)
14+
-- don't have a proper component build graph, so components are
15+
-- built in declaration order.
16+
executable my-custom-preprocessor
17+
main-is: MyCustomPreprocessor.hs
18+
build-depends: base, directory
19+
default-language: Haskell2010
20+
21+
library
22+
exposed-modules: A
23+
build-depends: base
24+
build-tools: my-custom-preprocessor
25+
-- ^ Note the internal dependency.
26+
default-language: Haskell2010
27+
28+
executable hello-world
29+
main-is: Hello.hs
30+
build-depends: base, internal-preprocessor-test
31+
default-language: Haskell2010

Cabal/tests/PackageTests/PackageTester.hs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,8 +381,7 @@ rawCompileSetup verbosity suite e path = do
381381
r <- rawRun verbosity (Just path) (ghcPath suite) e $
382382
[ "--make"] ++
383383
ghcPackageDBParams (ghcVersion suite) (packageDBStack suite) ++
384-
[ "-hide-all-packages"
385-
, "-package base"
384+
[ "-hide-package Cabal"
386385
#ifdef LOCAL_COMPONENT_ID
387386
-- This is best, but we don't necessarily have it
388387
-- if we're bootstrapping with old Cabal.

Cabal/tests/PackageTests/Tests.hs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,12 @@ tests config = do
330330
cabal "build" ["myprog"]
331331
cabal "copy" ["myprog"]
332332

333+
-- Test internal custom preprocessor
334+
tc "CustomPreProcess" $ do
335+
cabal_build []
336+
runExe' "hello-world" []
337+
>>= assertOutputContains "hello from A"
338+
333339
where
334340
ghc_pkg_guess bin_name = do
335341
cwd <- packageDir

0 commit comments

Comments
 (0)