Skip to content

Commit da15a6f

Browse files
committed
Fix build-tools PATH usage with per-component new-build
Signed-off-by: Edward Z. Yang <[email protected]>
1 parent 4b4690b commit da15a6f

File tree

13 files changed

+131
-18
lines changed

13 files changed

+131
-18
lines changed

cabal-install/Distribution/Client/Configure.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ configureSetupScript packageDBs
203203
, useDistPref = distPref
204204
, useLoggingHandle = Nothing
205205
, useWorkingDir = Nothing
206+
, useExtraPathEnv = []
206207
, setupCacheLock = lock
207208
, useWin32CleanHack = False
208209
, forceExternalSetupMethod = forceExternal

cabal-install/Distribution/Client/ProjectBuilding.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,8 @@ buildInplaceUnpackedPackage verbosity
11991199
pkg buildStatus
12001200
allSrcFiles buildResult
12011201

1202+
-- PURPOSELY omitted: no copy!
1203+
12021204
mipkg <- whenReRegister $
12031205
annotateFailureNoLog InstallFailed $ do
12041206
-- Register locally

cabal-install/Distribution/Client/ProjectPlanning.hs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,9 +1060,9 @@ elaborateInstallPlan platform compiler compilerprogdb
10601060
internalPkgSet = pkgInternalPackages pkg
10611061
comps_graph = Cabal.mkComponentsGraph (pkgEnabled pkg) pd internalPkgSet
10621062

1063-
buildComponent :: (Map PackageName ConfiguredId, Map String ConfiguredId)
1063+
buildComponent :: (Map PackageName ConfiguredId, Map String (ConfiguredId, FilePath))
10641064
-> (Cabal.Component, [Cabal.ComponentName])
1065-
-> ((Map PackageName ConfiguredId, Map String ConfiguredId),
1065+
-> ((Map PackageName ConfiguredId, Map String (ConfiguredId, FilePath)),
10661066
ElaboratedComponent)
10671067
buildComponent (internal_map, exe_map) (comp, _cdeps) =
10681068
((internal_map', exe_map'), ecomp)
@@ -1079,6 +1079,8 @@ elaborateInstallPlan platform compiler compilerprogdb
10791079
internal_lib_deps,
10801080
elabComponentExeDependencies =
10811081
internal_exe_deps,
1082+
elabComponentExeDependencyPaths =
1083+
internal_exe_dep_paths,
10821084
elabComponentInstallDirs = installDirs,
10831085
-- These are filled in later
10841086
elabComponentBuildTargets = [],
@@ -1106,11 +1108,12 @@ elaborateInstallPlan platform compiler compilerprogdb
11061108
= [ confid'
11071109
| Dependency pkgname _ <- PD.targetBuildDepends bi
11081110
, Just confid' <- [Map.lookup pkgname internal_map] ]
1109-
internal_exe_deps
1110-
= [ confInstId confid'
1111+
(internal_exe_deps, internal_exe_dep_paths)
1112+
= unzip $
1113+
[ (confInstId confid', path)
11111114
| Dependency (PackageName toolname) _ <- PD.buildTools bi
11121115
, toolname `elem` map PD.exeName (PD.executables pd)
1113-
, Just confid' <- [Map.lookup toolname exe_map]
1116+
, Just (confid', path) <- [Map.lookup toolname exe_map]
11141117
]
11151118
internal_map' = case cname of
11161119
CLibName
@@ -1119,8 +1122,25 @@ elaborateInstallPlan platform compiler compilerprogdb
11191122
-> Map.insert (PackageName libname) confid internal_map
11201123
_ -> internal_map
11211124
exe_map' = case cname of
1122-
CExeName exename -> Map.insert exename confid exe_map
1123-
_ -> exe_map
1125+
CExeName exename
1126+
-> Map.insert exename (confid, inplace_bin_dir) exe_map
1127+
_ -> exe_map
1128+
-- NB: For inplace NOT InstallPaths.bindir installDirs; for an
1129+
-- inplace build those values are utter nonsense. So we
1130+
-- have to guess where the directory is going to be.
1131+
-- Fortunately this is "stable" part of Cabal API.
1132+
-- But the way we get the build directory is A HORRIBLE
1133+
-- HACK.
1134+
inplace_bin_dir
1135+
| shouldBuildInplaceOnly spkg
1136+
= distBuildDirectory
1137+
(elabDistDirParams elaboratedSharedConfig (ElabComponent ecomp)) </>
1138+
"build" </> case Cabal.componentNameString cname of
1139+
Just n -> n
1140+
Nothing -> ""
1141+
| otherwise
1142+
= InstallDirs.bindir installDirs
1143+
11241144

11251145
installDirs
11261146
| shouldBuildInplaceOnly spkg
@@ -2044,7 +2064,7 @@ setupHsScriptOptions :: ElaboratedReadyPackage
20442064
-> SetupScriptOptions
20452065
-- TODO: Fix this so custom is a separate component. Custom can ALWAYS
20462066
-- be a separate component!!!
2047-
setupHsScriptOptions (ReadyPackage (getElaboratedPackage -> ElaboratedPackage{..}))
2067+
setupHsScriptOptions (ReadyPackage pkg_or_comp)
20482068
ElaboratedSharedConfig{..} srcdir builddir
20492069
isParallelBuild cacheLock =
20502070
SetupScriptOptions {
@@ -2062,10 +2082,13 @@ setupHsScriptOptions (ReadyPackage (getElaboratedPackage -> ElaboratedPackage{..
20622082
useDistPref = builddir,
20632083
useLoggingHandle = Nothing, -- this gets set later
20642084
useWorkingDir = Just srcdir,
2085+
useExtraPathEnv = elabExeDependencyPaths pkg_or_comp,
20652086
useWin32CleanHack = False, --TODO: [required eventually]
20662087
forceExternalSetupMethod = isParallelBuild,
20672088
setupCacheLock = Just cacheLock
20682089
}
2090+
where
2091+
ElaboratedPackage{..} = getElaboratedPackage pkg_or_comp
20692092

20702093

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

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module Distribution.Client.ProjectPlanning.Types (
1717
elabInstallDirs,
1818
elabDistDirParams,
1919
elabRequiresRegistration,
20+
elabExeDependencyPaths,
2021
elabBuildTargets,
2122
elabReplTarget,
2223
elabBuildHaddocks,
@@ -170,6 +171,10 @@ elabBuildHaddocks :: ElaboratedConfiguredPackage -> Bool
170171
elabBuildHaddocks (ElabPackage pkg) = pkgBuildHaddocks pkg
171172
elabBuildHaddocks (ElabComponent comp) = elabComponentBuildHaddocks comp
172173

174+
elabExeDependencyPaths :: ElaboratedConfiguredPackage -> [FilePath]
175+
elabExeDependencyPaths (ElabPackage _) = [] -- TODO: not implemented
176+
elabExeDependencyPaths (ElabComponent comp) = elabComponentExeDependencyPaths comp
177+
173178
getElaboratedPackage :: ElaboratedConfiguredPackage -> ElaboratedPackage
174179
getElaboratedPackage (ElabPackage pkg) = pkg
175180
getElaboratedPackage (ElabComponent comp) = elabComponentPackage comp
@@ -209,6 +214,8 @@ data ElaboratedComponent
209214
-- | The order-only dependencies of this component; e.g.,
210215
-- if you depend on an executable it goes here.
211216
elabComponentExeDependencies :: [ComponentId],
217+
-- | The file paths of all our executable dependencies.
218+
elabComponentExeDependencyPaths :: [FilePath],
212219
-- | The 'ElaboratedPackage' this component came from
213220
elabComponentPackage :: ElaboratedPackage,
214221
-- | What in this component should we build (TRANSIENT, see 'pkgBuildTargets')

cabal-install/Distribution/Client/SetupWrapper.hs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ import Distribution.Simple.Program
5252
, getProgramSearchPath, getDbProgramOutput, runDbProgram, ghcProgram
5353
, ghcjsProgram )
5454
import Distribution.Simple.Program.Find
55-
( programSearchPathAsPATHVar )
55+
( programSearchPathAsPATHVar, ProgramSearchPathEntry(ProgramSearchPathDir) )
5656
import Distribution.Simple.Program.Run
5757
( getEffectiveEnvironment )
5858
import qualified Distribution.Simple.Program.Strip as Strip
@@ -80,7 +80,7 @@ import Distribution.Simple.Utils
8080
, createDirectoryIfMissingVerbose, installExecutableFile
8181
, copyFileVerbose, rewriteFile, intercalate )
8282
import Distribution.Client.Utils
83-
( inDir, tryCanonicalizePath
83+
( inDir, tryCanonicalizePath, withExtraPathEnv
8484
, existsAndIsMoreRecentThan, moreRecentFile, withEnv
8585
#if mingw32_HOST_OS
8686
, canonicalizePathNoThrow
@@ -160,6 +160,8 @@ data SetupScriptOptions = SetupScriptOptions {
160160
useDistPref :: FilePath,
161161
useLoggingHandle :: Maybe Handle,
162162
useWorkingDir :: Maybe FilePath,
163+
-- | Extra things to add to PATH when invoking the setup script.
164+
useExtraPathEnv :: [FilePath],
163165
forceExternalSetupMethod :: Bool,
164166

165167
-- | List of dependencies to use when building Setup.hs.
@@ -228,6 +230,7 @@ defaultSetupScriptOptions = SetupScriptOptions {
228230
useDistPref = defaultDistPref,
229231
useLoggingHandle = Nothing,
230232
useWorkingDir = Nothing,
233+
useExtraPathEnv = [],
231234
useWin32CleanHack = False,
232235
forceExternalSetupMethod = False,
233236
setupCacheLock = Nothing
@@ -304,9 +307,10 @@ internalSetupMethod verbosity options _ bt mkargs = do
304307
let args = mkargs cabalVersion
305308
info verbosity $ "Using internal setup method with build-type " ++ show bt
306309
++ " and args:\n " ++ show args
307-
inDir (useWorkingDir options) $
310+
inDir (useWorkingDir options) $ do
308311
withEnv "HASKELL_DIST_DIR" (useDistPref options) $
309-
buildTypeAction bt args
312+
withExtraPathEnv (useExtraPathEnv options) $
313+
buildTypeAction bt args
310314

311315
buildTypeAction :: BuildType -> ([String] -> IO ())
312316
buildTypeAction Simple = Simple.defaultMainArgs
@@ -335,7 +339,8 @@ selfExecSetupMethod verbosity options _pkg bt mkargs = do
335339
++ show logHandle
336340

337341
searchpath <- programSearchPathAsPATHVar
338-
(getProgramSearchPath (useProgramConfig options))
342+
(map ProgramSearchPathDir (useExtraPathEnv options) ++
343+
getProgramSearchPath (useProgramConfig options))
339344
env <- getEffectiveEnvironment [("PATH", Just searchpath)
340345
,("HASKELL_DIST_DIR", Just (useDistPref options))]
341346

@@ -689,7 +694,8 @@ externalSetupMethod verbosity options pkg bt mkargs = do
689694
where
690695
doInvoke path' = do
691696
searchpath <- programSearchPathAsPATHVar
692-
(getProgramSearchPath (useProgramConfig options'))
697+
(map ProgramSearchPathDir (useExtraPathEnv options') ++
698+
getProgramSearchPath (useProgramConfig options'))
693699
env <- getEffectiveEnvironment [("PATH", Just searchpath)
694700
,("HASKELL_DIST_DIR", Just (useDistPref options))]
695701

cabal-install/Distribution/Client/Utils.hs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ module Distribution.Client.Utils ( MergeResult(..)
44
, mergeBy, duplicates, duplicatesBy
55
, readMaybe
66
, inDir, withEnv, logDirChange
7+
, withExtraPathEnv
78
, determineNumJobs, numberOfProcessors
89
, removeExistingFile
910
, withTempFileName
@@ -18,7 +19,7 @@ module Distribution.Client.Utils ( MergeResult(..)
1819
, relaxEncodingErrors)
1920
where
2021

21-
import Distribution.Compat.Environment ( lookupEnv, setEnv, unsetEnv )
22+
import Distribution.Compat.Environment
2223
import Distribution.Compat.Exception ( catchIO )
2324
import Distribution.Compat.Time ( getModTime )
2425
import Distribution.Simple.Setup ( Flag(..) )
@@ -31,14 +32,15 @@ import Control.Monad
3132
( when )
3233
import Data.Bits
3334
( (.|.), shiftL, shiftR )
35+
import System.FilePath
3436
import Data.Char
3537
( ord, chr )
3638
#if MIN_VERSION_base(4,6,0)
3739
import Text.Read
3840
( readMaybe )
3941
#endif
4042
import Data.List
41-
( isPrefixOf, sortBy, groupBy )
43+
( isPrefixOf, sortBy, groupBy, intercalate )
4244
import Data.Word
4345
( Word8, Word32)
4446
import Foreign.C.Types ( CInt(..) )
@@ -47,8 +49,6 @@ import qualified Control.Exception as Exception
4749
import System.Directory
4850
( canonicalizePath, doesFileExist, getCurrentDirectory
4951
, removeFile, setCurrentDirectory )
50-
import System.FilePath
51-
( (</>), isAbsolute, takeDrive, splitPath, joinPath )
5252
import System.IO
5353
( Handle, hClose, openTempFile
5454
#if MIN_VERSION_base(4,4,0)
@@ -153,6 +153,23 @@ withEnv k v m = do
153153
Nothing -> unsetEnv k
154154
Just old -> setEnv k old)
155155

156+
-- | Executes the action, increasing the PATH environment
157+
-- in some way
158+
--
159+
-- Warning: This operation is NOT thread-safe, because the
160+
-- environment variables are a process-global concept.
161+
withExtraPathEnv :: [FilePath] -> IO a -> IO a
162+
withExtraPathEnv paths m = do
163+
oldPathSplit <- getSearchPath
164+
let newPath = mungePath $ intercalate [searchPathSeparator] (paths ++ oldPathSplit)
165+
oldPath = mungePath $ intercalate [searchPathSeparator] oldPathSplit
166+
-- TODO: This is a horrible hack to work around the fact that
167+
-- setEnv can't take empty values as an argument
168+
mungePath p | p == "" = "/dev/null"
169+
| otherwise = p
170+
setEnv "PATH" newPath
171+
m `Exception.finally` setEnv "PATH" oldPath
172+
156173
-- | Log directory change in 'make' compatible syntax
157174
logDirChange :: (String -> IO ()) -> Maybe FilePath -> IO a -> IO a
158175
logDirChange _ Nothing m = m

cabal-install/cabal-install.cabal

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ Extra-Source-Files:
7777
tests/IntegrationTests/multiple-source/p/p.cabal
7878
tests/IntegrationTests/multiple-source/q/Setup.hs
7979
tests/IntegrationTests/multiple-source/q/q.cabal
80+
tests/IntegrationTests/new-build/BuildToolsPath.sh
81+
tests/IntegrationTests/new-build/BuildToolsPath/A.hs
82+
tests/IntegrationTests/new-build/BuildToolsPath/MyCustomPreprocessor.hs
83+
tests/IntegrationTests/new-build/BuildToolsPath/build-tools-path.cabal
84+
tests/IntegrationTests/new-build/BuildToolsPath/cabal.project
85+
tests/IntegrationTests/new-build/BuildToolsPath/hello/Hello.hs
8086
tests/IntegrationTests/new-build/T3460.sh
8187
tests/IntegrationTests/new-build/T3460/C.hs
8288
tests/IntegrationTests/new-build/T3460/Setup.hs
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
. ./common.sh
2+
cd BuildToolsPath
3+
cabal new-build build-tools-path hello-world
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{-# OPTIONS_GHC -F -pgmF my-custom-preprocessor #-}
2+
module A where
3+
4+
a :: String
5+
a = "0000"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module Main where
2+
3+
import System.Environment
4+
import System.IO
5+
6+
main :: IO ()
7+
main = do
8+
(_:source:target:_) <- getArgs
9+
let f '0' = '1'
10+
f c = c
11+
writeFile target . map f =<< readFile source
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: build-tools-path
2+
version: 0.1.0.0
3+
synopsis: Checks build-tools are put in PATH
4+
license: BSD3
5+
category: Testing
6+
build-type: Simple
7+
cabal-version: >=1.10
8+
9+
executable my-custom-preprocessor
10+
main-is: MyCustomPreprocessor.hs
11+
build-depends: base, directory
12+
default-language: Haskell2010
13+
14+
library
15+
exposed-modules: A
16+
build-depends: base
17+
build-tools: my-custom-preprocessor
18+
-- ^ Note the internal dependency.
19+
default-language: Haskell2010
20+
21+
executable hello-world
22+
main-is: Hello.hs
23+
build-depends: base, build-tools-path
24+
default-language: Haskell2010
25+
hs-source-dirs: hello
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
packages: .
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

0 commit comments

Comments
 (0)