Hadrian: various improvements around the 'test' rule
authorAlp Mestanogullari <alpmestan@gmail.com>
Tue, 5 Mar 2019 12:22:46 +0000 (13:22 +0100)
committerMarge Bot <ben+marge-bot@smart-cactus.org>
Fri, 8 Mar 2019 10:50:26 +0000 (05:50 -0500)
- introduce a -k/--keep-test-files flag to prevent cleanup
- add -dstg-lint to the options that are always passed to tests
- infer library ways from the compiler to be tested instead of getting them
  from the flavour (like make)
- likewise for figuring out whether the compiler to be tested is "debugged"
- specify config.exeext
- correctly specify config.in_tree_compiler, instead of always passing True
- fix formatting of how we pass a few test options
- add (potential) extensions to check-* program names
- build check-* programs with the compiler to be tested
- set TEST_HC_OPTS_INTERACTIVE and PYTHON env vars when running tests

hadrian/src/CommandLine.hs
hadrian/src/Oracles/TestSettings.hs
hadrian/src/Rules/Test.hs
hadrian/src/Settings/Builders/Make.hs
hadrian/src/Settings/Builders/RunTest.hs
hadrian/src/Settings/Default.hs

index 75e9812..9c9cf9f 100644 (file)
@@ -15,7 +15,7 @@ import System.Environment
 
 import qualified Data.Set as Set
 
-data TestSpeed = Slow | Average | Fast deriving (Show, Eq)
+data TestSpeed = TestSlow | TestNormal | TestFast deriving (Show, Eq)
 
 -- | All arguments that can be passed to Hadrian via the command line.
 data CommandLineArgs = CommandLineArgs
@@ -45,7 +45,8 @@ defaultCommandLineArgs = CommandLineArgs
 
 -- | These arguments are used by the `test` target.
 data TestArgs = TestArgs
-    { testCompiler   :: String
+    { testKeepFiles  :: Bool
+    , testCompiler   :: String
     , testConfigFile :: String
     , testConfigs    :: [String]
     , testJUnit      :: Maybe FilePath
@@ -61,14 +62,15 @@ data TestArgs = TestArgs
 -- | Default value for `TestArgs`.
 defaultTestArgs :: TestArgs
 defaultTestArgs = TestArgs
-    { testCompiler   = "stage2"
+    { testKeepFiles  = False
+    , testCompiler   = "stage2"
     , testConfigFile = "testsuite/config/ghc"
     , testConfigs    = []
     , testJUnit      = Nothing
     , testOnly       = []
     , testOnlyPerf   = False
     , testSkipPerf   = False
-    , testSpeed      = Fast
+    , testSpeed      = TestNormal
     , testSummary    = Nothing
     , testVerbosity  = Nothing
     , testWays       = [] }
@@ -119,6 +121,9 @@ readProgressInfo ms =
     set :: ProgressInfo -> CommandLineArgs -> CommandLineArgs
     set flag flags = flags { progressInfo = flag }
 
+readTestKeepFiles :: Either String (CommandLineArgs -> CommandLineArgs)
+readTestKeepFiles = Right $ \flags -> flags { testArgs = (testArgs flags) { testKeepFiles = True } }
+
 readTestCompiler :: Maybe String -> Either String (CommandLineArgs -> CommandLineArgs)
 readTestCompiler compiler = maybe (Left "Cannot parse compiler") (Right . set) compiler
   where
@@ -158,9 +163,9 @@ readTestSpeed ms =
     maybe (Left "Cannot parse test-speed") (Right . set) (go =<< lower <$> ms)
   where
     go :: String -> Maybe TestSpeed
-    go "fast"    = Just Fast
-    go "slow"    = Just Slow
-    go "average" = Just Average
+    go "fast"    = Just TestFast
+    go "slow"    = Just TestSlow
+    go "normal"  = Just TestNormal
     go _         = Nothing
     set :: TestSpeed -> CommandLineArgs -> CommandLineArgs
     set flag flags = flags { testArgs = (testArgs flags) {testSpeed = flag} }
@@ -217,6 +222,8 @@ optDescrs =
       "Progress info style (None, Brief, Normal or Unicorn)."
     , Option [] ["docs"] (OptArg readDocsArg "TARGET")
       "Strip down docs targets (none, no-haddocks, no-sphinx[-{html, pdfs, man}]."
+    , Option ['k'] ["keep-test-files"] (NoArg readTestKeepFiles)
+      "Keep all the files generated when running the testsuite."
     , Option [] ["test-compiler"] (OptArg readTestCompiler "TEST_COMPILER")
       "Use given compiler [Default=stage2]."
     , Option [] ["test-config-file"] (OptArg readTestConfigFile "CONFIG_FILE")
index 1bf75b5..9d93e10 100644 (file)
@@ -2,10 +2,16 @@
 -- | compiler. We need to search this file for required keys and setting
 -- | required for testsuite e.g. WORDSIZE, HOSTOS etc.
 
-module Oracles.TestSettings (TestSetting (..), testSetting, testRTSSettings) where
+module Oracles.TestSettings
+  ( TestSetting (..), testSetting, testRTSSettings
+  , getCompilerPath, getBinaryDirectory
+  ) where
 
 import Base
 import Hadrian.Oracles.TextFile
+import Oracles.Setting (topDirectory, setting, Setting(..))
+import Settings (programContext)
+import Packages
 
 testConfigFile :: Action FilePath
 testConfigFile = buildRoot <&> (-/- "test/ghcconfig")
@@ -67,3 +73,23 @@ testRTSSettings :: Action [String]
 testRTSSettings = do
     file <- testConfigFile
     words <$> lookupValueOrError file "GhcRTSWays"
+
+-- | Directory to look for binaries.
+--   We assume that required programs are present in the same binary directory
+--   in which ghc is stored and that they have their conventional name.
+getBinaryDirectory :: String -> Action FilePath
+getBinaryDirectory "stage0" = takeDirectory <$> setting SystemGhc
+getBinaryDirectory "stage1" = liftM2 (-/-) topDirectory (stageBinPath Stage0)
+getBinaryDirectory "stage2" = liftM2 (-/-) topDirectory (stageBinPath Stage1)
+getBinaryDirectory compiler = pure $ takeDirectory compiler
+
+-- | Get the path to the given @--test-compiler@.
+getCompilerPath :: String -> Action FilePath
+getCompilerPath "stage0" = setting SystemGhc
+getCompilerPath "stage1" = liftM2 (-/-) topDirectory (fullPath Stage0 ghc)
+getCompilerPath "stage2" = liftM2 (-/-) topDirectory (fullPath Stage1 ghc)
+getCompilerPath compiler = pure compiler
+
+-- | Get the full path to the given program.
+fullPath :: Stage -> Package -> Action FilePath
+fullPath stage pkg = programPath =<< programContext stage pkg
index b72c1b9..55ef19a 100644 (file)
@@ -3,8 +3,11 @@ module Rules.Test (testRules) where
 import System.Environment
 
 import Base
+import CommandLine
 import Expression
+import Flavour
 import Oracles.Setting
+import Oracles.TestSettings
 import Packages
 import Settings
 import Settings.Default
@@ -16,7 +19,21 @@ ghcConfigHsPath :: FilePath
 ghcConfigHsPath = "testsuite/mk/ghc-config.hs"
 
 ghcConfigProgPath :: FilePath
-ghcConfigProgPath = "test/bin/ghc-config"
+ghcConfigProgPath = "test/bin/ghc-config" <.> exe
+
+checkPprProgPath, checkPprSourcePath :: FilePath
+checkPprProgPath = "test/bin/check-ppr" <.> exe
+checkPprSourcePath = "utils/check-ppr/Main.hs"
+
+checkApiAnnotationsProgPath, checkApiAnnotationsSourcePath :: FilePath
+checkApiAnnotationsProgPath = "test/bin/check-api-annotations" <.> exe
+checkApiAnnotationsSourcePath = "utils/check-api-annotations/Main.hs"
+
+checkPrograms :: [(FilePath, FilePath)]
+checkPrograms =
+    [ (checkPprProgPath, checkPprSourcePath)
+    , (checkApiAnnotationsProgPath, checkApiAnnotationsSourcePath)
+    ]
 
 ghcConfigPath :: FilePath
 ghcConfigPath = "test/ghcconfig"
@@ -27,23 +44,35 @@ testRules = do
     root <- buildRootRules
 
     -- Using program shipped with testsuite to generate ghcconfig file.
-    root -/- ghcConfigProgPath ~> do
-        ghc <- builderPath $ Ghc CompileHs Stage0
-        createDirectory $ takeDirectory (root -/- ghcConfigProgPath)
-        cmd ghc [ghcConfigHsPath, "-o" , root -/- ghcConfigProgPath]
-
-    -- TODO : Use input test compiler and not just stage2 compiler.
-    root -/- ghcConfigPath ~> do
-        ghcPath <- needFile Stage1 ghc
+    root -/- ghcConfigProgPath %> \_ -> do
+        ghc0Path <- (<.> exe) <$> getCompilerPath "stage0"
+        cmd [ghc0Path] [ghcConfigHsPath, "-o" , root -/- ghcConfigProgPath]
+
+    -- Rules for building check-ppr and check-ppr-annotations with the compiler
+    -- we are going to test (in-tree or out-of-tree).
+    forM_ checkPrograms $ \(progPath, sourcePath) ->
+        root -/- progPath %> \path -> do
+            testGhc <- testCompiler <$> userSetting defaultTestArgs
+            top <- topDirectory
+            when (testGhc `elem` ["stage1", "stage2", "stage3"]) $ do
+                let stg = stageOf testGhc
+                need . (:[]) =<< programPath (Context stg ghc vanilla)
+            bindir <- getBinaryDirectory testGhc
+            cmd [bindir </> "ghc" <.> exe]
+                ["-package", "ghc", "-o", top -/- path, top -/- sourcePath]
+
+    root -/- ghcConfigPath %> \_ -> do
+        args <- userSetting defaultTestArgs
+        let testGhc = testCompiler args
+            stg = stageOf testGhc
+        ghcPath <- getCompilerPath testGhc
+        when (testGhc `elem` ["stage1", "stage2", "stage3"]) $
+            need . (:[]) =<< programPath (Context stg ghc vanilla)
         need [root -/- ghcConfigProgPath]
         cmd [FileStdout $ root -/- ghcConfigPath] (root -/- ghcConfigProgPath)
             [ghcPath]
 
-    root -/- timeoutPath ~> timeoutProgBuilder
-
-    "validate" ~> do
-        needTestBuilders
-        build $ target (vanillaContext Stage2 compiler) (Make "testsuite/tests") [] []
+    root -/- timeoutPath %> \_ -> timeoutProgBuilder
 
     "test" ~> do
         needTestBuilders
@@ -52,6 +81,9 @@ testRules = do
         -- Prepare Ghc configuration file for input compiler.
         need [root -/- ghcConfigPath, root -/- timeoutPath]
 
+        args <- userSetting defaultTestArgs
+        ghcPath <- getCompilerPath (testCompiler args)
+
         -- TODO This approach doesn't work.
         -- Set environment variables for test's Makefile.
         env <- sequence
@@ -61,18 +93,28 @@ testRules = do
 
         makePath        <- builderPath $ Make ""
         top             <- topDirectory
-        ghcPath         <- (top -/-) <$> builderPath (Ghc CompileHs Stage2)
         ghcFlags        <- runTestGhcFlags
-        checkPprPath    <- (top -/-) <$> needFile Stage1 checkPpr
-        annotationsPath <- (top -/-) <$> needFile Stage1 checkApiAnnotations
+        let ghciFlags = ghcFlags ++ unwords
+              [ "--interactive", "-v0", "-ignore-dot-ghci"
+              , "-fno-ghci-history"
+              ]
+
+        pythonPath      <- builderPath Python
+        need [ root -/- checkPprProgPath, root -/- checkApiAnnotationsProgPath ]
 
         -- Set environment variables for test's Makefile.
+        -- TODO: Ideally we would define all those env vars in 'env', so that
+        --       Shake can keep track of them, but it is not as easy as it seems
+        --       to get that to work.
         liftIO $ do
             setEnv "MAKE" makePath
+            setEnv "PYTHON" pythonPath
             setEnv "TEST_HC" ghcPath
             setEnv "TEST_HC_OPTS" ghcFlags
-            setEnv "CHECK_PPR" checkPprPath
-            setEnv "CHECK_API_ANNOTATIONS" annotationsPath
+            setEnv "TEST_HC_OPTS_INTERACTIVE" ghciFlags
+            setEnv "CHECK_PPR" (top -/- root -/- checkPprProgPath)
+            setEnv "CHECK_API_ANNOTATIONS"
+                   (top -/- root -/- checkApiAnnotationsProgPath)
 
         -- Execute the test target.
         -- We override the verbosity setting to make sure the user can see
@@ -80,15 +122,6 @@ testRules = do
         withVerbosity Loud $ buildWithCmdOptions env $
             target (vanillaContext Stage2 compiler) RunTest [] []
 
--- | Build extra programs and libraries required by testsuite
-needTestsuitePackages :: Action ()
-needTestsuitePackages = do
-    targets   <- mapM (needFile Stage1) =<< testsuitePackages
-    -- iserv is not supported under Windows
-    windows <- windowsHost
-    when (not windows) needIservBins
-    need targets
-
 -- | Build the timeout program.
 -- See: https://github.com/ghc/ghc/blob/master/testsuite/timeout/Makefile#L23
 timeoutProgBuilder :: Action ()
@@ -108,27 +141,47 @@ timeoutProgBuilder = do
             writeFile' (root -/- timeoutPath) script
             makeExecutable (root -/- timeoutPath)
 
-needIservBins :: Action ()
-needIservBins = do
-    rtsways <- interpretInContext (vanillaContext Stage1 ghc) getRtsWays
-    need =<< traverse programPath
-               [ Context Stage1 iserv w
-               | w <- [vanilla, profiling, dynamic]
-               , w `elem` rtsways
-               ]
-
 needTestBuilders :: Action ()
 needTestBuilders = do
-    needBuilder $ Ghc CompileHs Stage2
-    needBuilder $ GhcPkg Update Stage1
-    needBuilder Hpc
-    needBuilder $ Hsc2Hs Stage1
-    needTestsuitePackages
+    testGhc <- testCompiler <$> userSetting defaultTestArgs
+    when (testGhc `elem` ["stage1", "stage2", "stage3"]) needTestsuitePackages
+
+-- | Build extra programs and libraries required by testsuite
+needTestsuitePackages :: Action ()
+needTestsuitePackages = do
+    testGhc <- testCompiler <$> userSetting defaultTestArgs
+    when (testGhc `elem` ["stage1", "stage2", "stage3"]) $ do
+        let stg = stageOf testGhc
+        allpkgs   <- packages <$> flavour
+        stgpkgs   <- allpkgs (succ stg)
+        testpkgs  <- testsuitePackages
+        targets <- mapM (needFile stg) (stgpkgs ++ testpkgs)
+        needIservBins
+        need targets
+
+-- stage 1 ghc lives under stage0/bin,
+-- stage 2 ghc lives under stage1/bin, etc
+stageOf :: String -> Stage
+stageOf "stage1" = Stage0
+stageOf "stage2" = Stage1
+stageOf "stage3" = Stage2
+stageOf _ = error "unexpected stage argument"
+
+needIservBins :: Action ()
+needIservBins = do
+    -- iserv is not supported under Windows
+    windows <- windowsHost
+    when (not windows) $ do
+        testGhc <- testCompiler <$> userSetting defaultTestArgs
+        let stg = stageOf testGhc
+        rtsways <- interpretInContext (vanillaContext stg ghc) getRtsWays
+        need =<< traverse programPath
+            [ Context stg iserv w
+            | w <- [vanilla, profiling, dynamic]
+            , w `elem` rtsways
+            ]
 
 needFile :: Stage -> Package -> Action FilePath
 needFile stage pkg
--- TODO (Alp): we might sometimes need more than vanilla!
--- This should therefore depend on what test ways
--- we are going to use, I suppose?
     | isLibrary pkg = pkgConfFile (Context stage pkg profilingDynamic)
     | otherwise     = programPath =<< programContext stage pkg
index 0433888..56bb8e3 100644 (file)
@@ -37,6 +37,6 @@ validateBuilderArgs = builder (Make "testsuite/tests") ? do
 
 -- | Support for speed of validation
 setTestSpeed :: TestSpeed -> String
-setTestSpeed Fast    = "fasttest"
-setTestSpeed Average = "test"
-setTestSpeed Slow    = "slowtest"
+setTestSpeed TestFast   = "fasttest"
+setTestSpeed TestNormal = "test"
+setTestSpeed TestSlow   = "slowtest"
index 834cacf..ae85cf5 100644 (file)
@@ -39,7 +39,7 @@ runTestGhcFlags = do
     -- Take flags to send to the Haskell compiler from test.mk.
     -- See: https://github.com/ghc/ghc/blob/master/testsuite/mk/test.mk#L37
     unwords <$> sequence
-        [ pure " -dcore-lint -dcmm-lint -no-user-package-db -rtsopts"
+        [ pure " -dcore-lint -dstg-lint -dcmm-lint -no-user-package-db -rtsopts"
         , pure ghcOpts
         , pure ghcExtraFlags
         , ifMinGhcVer "711" "-fno-warn-missed-specialisations"
@@ -59,18 +59,19 @@ runTestBuilderArgs = builder RunTest ? do
             [ [ pkgPath pkg -/- "tests", pkgPath pkg -/- "tests-ghc" ]
             | pkg <- pkgs, isLibrary pkg, pkg /= rts, pkg /= libffi ]
 
-    flav    <- expr flavour
+    testGhc <- expr (testCompiler <$> userSetting defaultTestArgs)
     rtsWays <- expr testRTSSettings
-    libWays <- libraryWays flav
+    libWays <- expr (inferLibraryWays testGhc)
     let hasRtsWay w = elem w rtsWays
         hasLibWay w = elem w libWays
-        debugged    = ghcDebugged flav
     hasDynamic          <- getBooleanSetting TestGhcDynamic
     hasDynamicByDefault <- getBooleanSetting TestGhcDynamicByDefault
     withNativeCodeGen   <- getBooleanSetting TestGhcWithNativeCodeGen
     withInterpreter     <- getBooleanSetting TestGhcWithInterpreter
     unregisterised      <- getBooleanSetting TestGhcUnregisterised
     withSMP             <- getBooleanSetting TestGhcWithSMP
+    debugged            <- read <$> getTestSetting TestGhcDebugged
+    keepFiles           <- expr (testKeepFiles <$> userSetting defaultTestArgs)
 
     windows     <- expr windowsHost
     darwin      <- expr osxHost
@@ -94,8 +95,9 @@ runTestBuilderArgs = builder RunTest ? do
             , pure ["--rootdir=" ++ test | test <- libTests]
             , arg "-e", arg $ "windows=" ++ show windows
             , arg "-e", arg $ "darwin=" ++ show darwin
-            , arg "-e", arg $ "config.local=True"
-            , arg "-e", arg $ "config.cleanup=False" -- Don't clean up.
+            , arg "-e", arg $ "config.local=False"
+            , arg "-e", arg $ "config.cleanup=" ++ show (not keepFiles)
+            , arg "-e", arg $ "config.exeext=" ++ quote exe
             , arg "-e", arg $ "config.compiler_debugged=" ++ quote (yesNo debugged)
             , arg "-e", arg $ "ghc_debugged=" ++ quote (yesNo debugged)
             , arg "-e", arg $ asZeroOne "ghc_with_native_codegen=" withNativeCodeGen
@@ -116,9 +118,6 @@ runTestBuilderArgs = builder RunTest ? do
             , arg "-e", arg $ "config.ghc_dynamic=" ++ show hasDynamic
             , arg "-e", arg $ "config.ghc_built_by_llvm=" ++ show ghcBuiltByLlvm
 
-            -- Use default value, see:
-            -- https://github.com/ghc/ghc/blob/master/testsuite/mk/boilerplate.mk
-            , arg "-e", arg $ "config.in_tree_compiler=True"
             , arg "-e", arg $ "config.top=" ++ show (top -/- "testsuite")
             , arg "-e", arg $ "config.wordsize=" ++ show wordsize
             , arg "-e", arg $ "config.os="       ++ show os
@@ -137,8 +136,8 @@ getTestArgs = do
     -- targets specified in the TEST env var
     testEnvTargets <- maybe [] words <$> expr (liftIO $ lookupEnv "TEST")
     args            <- expr $ userSetting defaultTestArgs
-    bindir          <- expr $ setBinaryDirectory (testCompiler args)
-    compiler        <- expr $ setCompiler (testCompiler args)
+    bindir          <- expr $ getBinaryDirectory (testCompiler args)
+    compiler        <- expr $ getCompilerPath (testCompiler args)
     globalVerbosity <- shakeVerbosity <$> expr getShakeOptions
     let configFileArg= ["--config-file=" ++ (testConfigFile args)]
         testOnlyArg  =  map ("--only=" ++) (testOnly args ++ testEnvTargets)
@@ -150,10 +149,10 @@ getTestArgs = do
                            else Nothing
         speedArg     = ["-e", "config.speed=" ++ setTestSpeed (testSpeed args)]
         summaryArg   = case testSummary args of
-                           Just filepath -> Just $ "--summary-file" ++ quote filepath
+                           Just filepath -> Just $ "--summary-file " ++ show filepath
                            Nothing -> Just $ "--summary-file=testsuite_summary.txt"
         junitArg     = case testJUnit args of
-                           Just filepath -> Just $ "--junit " ++ quote filepath
+                           Just filepath -> Just $ "--junit=" ++ filepath
                            Nothing -> Nothing
         configArgs   = concat [["-e", configArg] | configArg <- testConfigs args]
         verbosityArg = case testVerbosity args of
@@ -165,46 +164,72 @@ getTestArgs = do
         haddockArg   = ["--config", "haddock=" ++ show (bindir -/- "haddock")]
         hp2psArg     = ["--config", "hp2ps=" ++ show (bindir -/- "hp2ps")]
         hpcArg       = ["--config", "hpc=" ++ show (bindir -/- "hpc")]
+        inTreeArg    = [ "-e", "config.in_tree_compiler=" ++
+          show (testCompiler args `elem` ["stage1", "stage2", "stage3"]) ]
+
     pure $  configFileArg ++ testOnlyArg ++ speedArg
          ++ catMaybes [ onlyPerfArg, skipPerfArg, summaryArg
                       , junitArg, verbosityArg  ]
          ++ configArgs ++ wayArgs ++  compilerArg ++ ghcPkgArg
-         ++ haddockArg ++ hp2psArg ++ hpcArg
-
--- TODO: Switch to 'Stage' as the first argument instead of 'String'.
--- | Directory to look for Binaries
--- | We assume that required programs are present in the same binary directory
--- | in which ghc is stored and that they have their conventional name.
--- | QUESTION : packages can be named different from their conventional names.
--- | For example, ghc-pkg can be named as ghc-pkg-version. In such cases, it will
--- | be impossible to search the binary. Only possible way will be to take user
--- | inputs for these directory also. boilerplate soes not account for this
--- | problem, but simply returns an error. How should we handle such cases?
-setBinaryDirectory :: String -> Action FilePath
-setBinaryDirectory "stage0" = takeDirectory <$> setting SystemGhc
-setBinaryDirectory "stage1" = liftM2 (-/-) topDirectory (stageBinPath Stage0)
-setBinaryDirectory "stage2" = liftM2 (-/-) topDirectory (stageBinPath Stage1)
-setBinaryDirectory compiler = pure $ parentPath compiler
-
--- TODO: Switch to 'Stage' as the first argument instead of 'String'.
--- | Set Test Compiler.
-setCompiler :: String -> Action FilePath
-setCompiler "stage0" = setting SystemGhc
-setCompiler "stage1" = liftM2 (-/-) topDirectory (fullPath Stage0 ghc)
-setCompiler "stage2" = liftM2 (-/-) topDirectory (fullPath Stage1 ghc)
-setCompiler compiler = pure compiler
+         ++ haddockArg ++ hp2psArg ++ hpcArg ++ inTreeArg
 
 -- | Set speed for test
 setTestSpeed :: TestSpeed -> String
-setTestSpeed Slow    = "0"
-setTestSpeed Average = "1"
-setTestSpeed Fast    = "2"
-
--- | Returns parent path of test compiler
--- | TODO: Is there a simpler way to find parent directory?
-parentPath :: String -> String
-parentPath path = intercalate "/" $ init $ splitOn "/" path
-
--- | TODO: Move to Hadrian utilities.
-fullPath :: Stage -> Package -> Action FilePath
-fullPath stage pkg = programPath =<< programContext stage pkg
+setTestSpeed TestSlow   = "0"
+setTestSpeed TestNormal = "1"
+setTestSpeed TestFast   = "2"
+
+-- | The purpose of this function is, given a compiler
+--   (stage 1, 2, 3 or an external one), to infer the ways
+--   that the libraries have been built in.
+--
+--   While we have this data readily available for in-tree compilers
+--   that we build (through the 'Flavour'), that is not the case for
+--   out-of-tree compilers that we may want to test, as is the case when
+--   we are running './validate --hadrian' (it packages up a binary
+--   distribution, installs it somewhere near and tests it).
+--
+--   We therefore proceed in a way that works regardless of whether we are
+--   dealing with an in-tree compiler or not: we ask the GHC's install
+--   ghc-pkg to give us the library directory of its @ghc-prim@ package and
+--   look at what ways are available for the interface file of the
+--   @GHC.PrimopWrappers@ module, like the Make build system does in
+--   @testsuite\/mk\/test.mk@ to compute @HAVE_DYNAMIC@, @HAVE_VANILLA@
+--   and @HAVE_PROFILING@:
+--
+--   - if we find @PrimopWrappers.hi@, we have the vanilla way;
+--   - if we find @PrimopWrappers.dyn_hi@, we have the dynamic way;
+--   - if we find @PrimopWrappers.p_hi@, we have the profiling way.
+inferLibraryWays :: String -> Action [Way]
+inferLibraryWays compiler = do
+  bindir <- getBinaryDirectory compiler
+  Stdout ghcPrimLibdirDirty <- cmd
+    [bindir </> "ghc-pkg" <.> exe]
+    ["field", "ghc-prim", "library-dirs", "--simple-output"]
+  let ghcPrimLibdir = fixup ghcPrimLibdirDirty
+  ways <- catMaybes <$> traverse (lookForWay ghcPrimLibdir) candidateWays
+  return ways
+
+  where lookForWay dir (hifile, w) = do
+          exists <- doesFileExist (dir -/- hifile)
+          if exists then return (Just w) else return Nothing
+
+        candidateWays =
+          [ ("GHC/PrimopWrappers.hi", vanilla)
+          , ("GHC/PrimopWrappers.dyn_hi", dynamic)
+          , ("GHC/PrimopWrappers.p_hi", profiling)
+          ]
+
+        -- If the ghc is in a directory with spaces in a path component,
+        -- 'dir' is prefixed and suffixed with double quotes.
+        -- In all cases, there is a \n at the end.
+        -- This function cleans it all up.
+        fixup = removeQuotes . removeNewline
+
+        removeNewline path
+          | "\n" `isSuffixOf` path = init path
+          | otherwise              = path
+
+        removeQuotes path
+          | "\"" `isPrefixOf` path && "\"" `isSuffixOf` path = tail (init path)
+          | otherwise                                        = path
index b74ee09..d8008fd 100644 (file)
@@ -100,6 +100,7 @@ stage1Packages = do
              , ghcPkg
              , ghcPrim
              , haskeline
+             , hp2ps
              , hsc2hs
              , intLib
              , pretty
@@ -132,7 +133,7 @@ testsuitePackages = do
              , ghci
              , ghcCompact
              , ghcPkg
-             , hp2ps
+             , hpcBin
              , hsc2hs
              , iserv
              , runGhc