[commit: ghc] wip/nfs-locking: Initial version of FindMissingInclude (c2d7e2a)

git at git.haskell.org git at git.haskell.org
Fri Oct 27 00:38:41 UTC 2017


Repository : ssh://git@git.haskell.org/ghc

On branch  : wip/nfs-locking
Link       : http://ghc.haskell.org/trac/ghc/changeset/c2d7e2aa683c89d9b1464734ea9ae68ff735655c/ghc

>---------------------------------------------------------------

commit c2d7e2aa683c89d9b1464734ea9ae68ff735655c
Author: Michal Terepeta <michal.terepeta at gmail.com>
Date:   Sat Jul 23 16:50:31 2016 +0200

    Initial version of FindMissingInclude
    
    This allows finding missing includes for `.c` files (this is important
    for all the cases where we generate the includes during the build
    process).
    
    We're using GCC's `-MM` `-MG` options and iterate as long as we get
    new includes. Since this would return all includes verbatim from the
    `#include`, we check which ones are actually generated and what are
    their final paths.
    
    Note: this is currently applied only to `.c` files and does not (yet?)
    work for `.hs` files (there are issues with things like ifdefs for
    package versions that cause GCC to error out).
    
    Signed-off-by: Michal Terepeta <michal.terepeta at gmail.com>


>---------------------------------------------------------------

c2d7e2aa683c89d9b1464734ea9ae68ff735655c
 src/Builder.hs              |  3 ++-
 src/Rules/Compile.hs        | 40 ++++++++++++++++++++++++++++++++++++++++
 src/Rules/Generate.hs       | 17 ++++++++++++++++-
 src/Settings/Builders/Cc.hs | 13 ++++++++++++-
 4 files changed, 70 insertions(+), 3 deletions(-)

diff --git a/src/Builder.hs b/src/Builder.hs
index 17198e7..1974eff 100644
--- a/src/Builder.hs
+++ b/src/Builder.hs
@@ -21,7 +21,8 @@ import Stage
 -- 3) Linking object files & static libraries into an executable.
 -- We have CcMode for CC and GhcMode for GHC.
 
-data CcMode = CompileC | FindCDependencies
+-- TODO: Consider merging FindCDependencies and FindMissingInclude
+data CcMode = CompileC | FindCDependencies | FindMissingInclude
     deriving (Eq, Generic, Show)
 
 data GhcMode = CompileHs | FindHsDependencies | LinkHs
diff --git a/src/Rules/Compile.hs b/src/Rules/Compile.hs
index fd6cd32..001068a 100644
--- a/src/Rules/Compile.hs
+++ b/src/Rules/Compile.hs
@@ -5,9 +5,16 @@ import Context
 import Expression
 import Oracles.Dependencies
 import Rules.Actions
+import Rules.Generate
 import Settings.Paths
 import Target
 
+import Development.Shake.Util
+
+import Data.Maybe
+import Data.List
+import qualified Data.Set as Set
+
 compilePackage :: [(Resource, Int)] -> Context -> Rules ()
 compilePackage rs context at Context {..} = do
     let path = buildPath context
@@ -22,6 +29,9 @@ compilePackage rs context at Context {..} = do
         if ("//*.c" ?== src)
         then do
             need $ src : deps
+            -- TODO: Improve parallelism by collecting all dependencies and
+            -- need'ing them all at once
+            mapM_  (needGenerated context) . filter ("//*.c" ?==) $ src : deps
             build $ Target context (Cc CompileC stage) [src] [obj]
         else do
             need $ src : deps
@@ -39,3 +49,33 @@ needCompileDependencies :: Context -> Action ()
 needCompileDependencies context at Context {..} = do
     when (isLibrary package) $ need =<< return <$> pkgConfFile context
     needContext =<< contextDependencies context
+
+needGenerated :: Context -> FilePath -> Action ()
+needGenerated context origFile = go Set.empty
+  where
+    go :: Set.Set String -> Action ()
+    go done = withTempFile $ \outFile -> do
+        let builder = Cc FindMissingInclude $ stage context
+            target = Target context builder [origFile] [outFile]
+        build target
+        deps <- parseFile outFile
+
+        -- Get the full path if the include refers to a generated file and call
+        -- `need` on it.
+        needed <- liftM catMaybes $
+            interpretInContext context (mapM getPathIfGenerated deps)
+        need needed
+
+        let newdone = Set.fromList needed `Set.union` done
+        -- If we added a new file to the set of needed files, let's try one more
+        -- time, since the new file might include a genreated header of itself
+        -- (which we'll `need`).
+        when (Set.size newdone > Set.size done) (go newdone)
+
+    parseFile :: FilePath -> Action [String]
+    parseFile file = do
+        input <- liftIO $ readFile file
+        case parseMakefile input of
+            [(_file, deps)] -> return deps
+            _               -> return []
+
diff --git a/src/Rules/Generate.hs b/src/Rules/Generate.hs
index 988b3d7..34874db 100644
--- a/src/Rules/Generate.hs
+++ b/src/Rules/Generate.hs
@@ -1,6 +1,7 @@
 module Rules.Generate (
     generatePackageCode, generateRules, installTargets, copyRules,
-    includesDependencies, derivedConstantsPath, generatedDependencies
+    includesDependencies, derivedConstantsPath, generatedDependencies,
+    getPathIfGenerated
     ) where
 
 import qualified System.Directory as IO
@@ -196,3 +197,17 @@ generateRules = do
 emptyTarget :: Context
 emptyTarget = vanillaContext (error "Rules.Generate.emptyTarget: unknown stage")
                              (error "Rules.Generate.emptyTarget: unknown package")
+
+getPathIfGenerated :: FilePath -> Expr (Maybe FilePath)
+getPathIfGenerated include = do
+  generated <- generatedFiles
+  -- For includes of generated files, we cannot get the full path of the file
+  -- (since it might be included due to some include dir, i.e., through `-I`).
+  -- So here we try both the name and the path.
+  let nameOrPath (name, path) = include == name || include == path
+  return . fmap snd $ find nameOrPath generated
+
+generatedFiles :: Expr [(FilePath, FilePath)]
+generatedFiles = do
+  deps <- generatedDependencies
+  return [ (takeFileName fp, fp) | fp <- deps ]
diff --git a/src/Settings/Builders/Cc.hs b/src/Settings/Builders/Cc.hs
index 354d2b4..36a172e 100644
--- a/src/Settings/Builders/Cc.hs
+++ b/src/Settings/Builders/Cc.hs
@@ -26,7 +26,18 @@ ccBuilderArgs = mconcat
                 , arg $ dropExtension output -<.> "o"
                 , arg "-x"
                 , arg "c"
-                , arg =<< getInput ] ]
+                , arg =<< getInput ]
+
+    , builder (Cc FindMissingInclude) ? do
+        mconcat [ arg "-E"
+                , arg "-MM"
+                , arg "-MG"
+                , commonCcArgs
+                , arg "-MF"
+                , arg =<< getOutput
+                , arg =<< getInput
+                ]
+    ]
 
 commonCcArgs :: Args
 commonCcArgs = mconcat [ append =<< getPkgDataList CcArgs



More information about the ghc-commits mailing list