diff --git a/ChangeLog.md b/ChangeLog.md index fe585620ac..f4b3010416 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,21 @@ # Changelog +## Unreleased changes + +Release notes: + +Major changes: + +Behaviour changes: + +Other enhancements: + +Bug fixes: + +* For versions of Cabal before 1.24, ensure that the dependencies of + non-buildable components are part of the build plan to work around an old + Cabal bug. + ## v1.6.1 Major changes: diff --git a/src/Stack/BuildPlan.hs b/src/Stack/BuildPlan.hs index 5d6b6c0c21..8bd0a7346c 100644 --- a/src/Stack/BuildPlan.hs +++ b/src/Stack/BuildPlan.hs @@ -198,7 +198,7 @@ gpdPackageDeps -> Map FlagName Bool -> Map PackageName VersionRange gpdPackageDeps gpd cv platform flags = - Map.filterWithKey (const . (/= name)) (packageDependencies pkgDesc) + Map.filterWithKey (const . (/= name)) (packageDependencies cv pkgDesc) where name = gpdPackageName gpd -- Since tests and benchmarks are both enabled, doesn't matter diff --git a/src/Stack/Package.hs b/src/Stack/Package.hs index cbef327ca9..cf07877779 100644 --- a/src/Stack/Package.hs +++ b/src/Stack/Package.hs @@ -356,7 +356,7 @@ packageFromPackageDescription packageConfig pkgFlags (PackageDescriptionPair pkg pkgId = package pkg name = fromCabalPackageName (pkgName pkgId) deps = M.filterWithKey (const . not . isMe) (M.union - (packageDependencies pkg) + (packageDependencies (packageConfigCompilerVersion packageConfig) pkg) -- We include all custom-setup deps - if present - in the -- package deps themselves. Stack always works with the -- invariant that there will be a single installed package @@ -602,12 +602,36 @@ getBuildComponentDir Nothing = Nothing getBuildComponentDir (Just name) = parseRelDir (name FilePath. (name ++ "-tmp")) -- | Get all dependencies of the package (buildable targets only). -packageDependencies :: PackageDescription -> Map PackageName VersionRange -packageDependencies pkg = +-- +-- Note that for Cabal versions 1.22 and earlier, there is a bug where +-- Cabal requires dependencies for non-buildable components to be +-- present. We're going to use GHC version as a proxy for Cabal +-- library version in this case for simplicity, so we'll check for GHC +-- being 7.10 or earlier. This obviously makes our function a lot more +-- fun to write... +packageDependencies + :: CompilerVersion 'CVActual + -> PackageDescription + -> Map PackageName VersionRange +packageDependencies ghcVersion pkg' = M.fromListWith intersectVersionRanges $ map (depName &&& depRange) $ concatMap targetBuildDepends (allBuildInfo' pkg) ++ maybe [] setupDepends (setupBuildInfo pkg) + where + pkg + | getGhcVersion ghcVersion >= $(mkVersion "8.0") = pkg' + -- Set all components to buildable. Only need to worry about + -- library, exe, test, and bench, since others didn't exist in + -- older Cabal versions + | otherwise = pkg' + { library = (\c -> c { libBuildInfo = go (libBuildInfo c) }) <$> library pkg' + , executables = (\c -> c { buildInfo = go (buildInfo c) }) <$> executables pkg' + , testSuites = (\c -> c { testBuildInfo = go (testBuildInfo c) }) <$> testSuites pkg' + , benchmarks = (\c -> c { benchmarkBuildInfo = go (benchmarkBuildInfo c) }) <$> benchmarks pkg' + } + + go bi = bi { buildable = True } -- | Get all dependencies of the package (buildable targets only). -- diff --git a/src/Stack/Snapshot.hs b/src/Stack/Snapshot.hs index a14007678e..b6027d2d89 100644 --- a/src/Stack/Snapshot.hs +++ b/src/Stack/Snapshot.hs @@ -769,7 +769,7 @@ calculate gpd platform compilerVersion loc flags hide options = , lpiGhcOptions = options , lpiPackageDeps = Map.map fromVersionRange $ Map.filterWithKey (const . (/= name)) - $ packageDependencies pd + $ packageDependencies compilerVersion pd , lpiProvidedExes = Set.fromList $ map (ExeName . T.pack . C.unUnqualComponentName . C.exeName) diff --git a/test/integration/tests/cabal-non-buildable-bug/Main.hs b/test/integration/tests/cabal-non-buildable-bug/Main.hs new file mode 100644 index 0000000000..5ec188065b --- /dev/null +++ b/test/integration/tests/cabal-non-buildable-bug/Main.hs @@ -0,0 +1,18 @@ +import StackTest + +main :: IO () +main = do + -- Newer Cabal: dry run and building should succeed, because they'll + -- both ignore the do-not-build + writeFile "stack.yaml" "resolver: ghc-8.0.2" + stack ["build", "--dry-run"] + stack ["build"] + + -- Older Cabal: both should fail, because they'll both try to + -- include the non-buildable component. If there's a regression, the + -- dry run will succeed (because Stack will use the proper logic) + -- and build will fail (because Cabal will be using its broken + -- logic). + writeFile "stack.yaml" "resolver: ghc-7.10.3" + stackErr ["build"] + stackErr ["build", "--dry-run"] diff --git a/test/integration/tests/cabal-non-buildable-bug/files/.gitignore b/test/integration/tests/cabal-non-buildable-bug/files/.gitignore new file mode 100644 index 0000000000..0008ca1636 --- /dev/null +++ b/test/integration/tests/cabal-non-buildable-bug/files/.gitignore @@ -0,0 +1,2 @@ +stack.yaml +foo.cabal diff --git a/test/integration/tests/cabal-non-buildable-bug/files/package.yaml b/test/integration/tests/cabal-non-buildable-bug/files/package.yaml new file mode 100644 index 0000000000..67f3a25c46 --- /dev/null +++ b/test/integration/tests/cabal-non-buildable-bug/files/package.yaml @@ -0,0 +1,14 @@ +name: foo +version: "0" + +dependencies: +- base + +library: {} + +executables: + not-built: + main: Main.hs + dependencies: + - does-not-exist + buildable: false