Implement "ghc --abi-hash M1 M2 ..."
authorSimon Marlow <marlowsd@gmail.com>
Wed, 29 Jul 2009 13:21:25 +0000 (13:21 +0000)
committerSimon Marlow <marlowsd@gmail.com>
Wed, 29 Jul 2009 13:21:25 +0000 (13:21 +0000)
This prints a combined hash of the ABIs exposed by the modules listed
on the command line.  It will be used by Cabal for generating a
package Id based on the actual ABI of a package.

ghc/Main.hs

index 22275e2..4c18d26 100644 (file)
@@ -27,6 +27,7 @@ import DriverMkDepend ( doMkDependHS )
 import InteractiveUI   ( interactiveUI, ghciWelcomeMsg )
 #endif
 
+
 -- Various other random stuff that we need
 import Config
 import HscTypes
@@ -45,6 +46,14 @@ import Util
 import Panic
 -- import MonadUtils       ( liftIO )
 
+-- Imports for --abi-hash
+import HscTypes            ( ModIface(mi_mod_hash) )
+import LoadIface           ( loadUserInterface )
+import Module              ( mkModuleName )
+import Finder              ( findImportedModule, cannotFindInterface )
+import TcRnMonad           ( initIfaceCheck )
+import Binary              ( openBinMem, put_, fingerprintBinMem )
+
 -- Standard Haskell libraries
 import System.IO
 import System.Environment
@@ -131,6 +140,7 @@ main' postLoadMode dflags0 args flagWarnings = do
                DoEval _        -> (CompManager, HscInterpreted, LinkInMemory)
                DoMake          -> (CompManager, dflt_target,    LinkBinary)
                DoMkDependHS    -> (MkDepend,    dflt_target,    LinkBinary)
+               DoAbiHash       -> (OneShot,     dflt_target,    LinkBinary)
                _               -> (OneShot,     dflt_target,    LinkBinary)
 
   let dflags1 = dflags0{ ghcMode   = mode,
@@ -203,6 +213,7 @@ main' postLoadMode dflags0 args flagWarnings = do
        StopBefore p           -> oneShot hsc_env p srcs >> GHC.printWarnings
        DoInteractive          -> interactiveUI srcs Nothing
        DoEval exprs           -> interactiveUI srcs $ Just $ reverse exprs
+       DoAbiHash              -> abiHash srcs
 
   liftIO $ dumpFinalStats dflags3
 
@@ -394,11 +405,13 @@ data PostLoadMode
   | DoMake                  -- ghc --make
   | DoInteractive           -- ghc --interactive
   | DoEval [String]         -- ghc -e foo -e bar => DoEval ["bar", "foo"]
+  | DoAbiHash               -- ghc --abi-hash
 
 doMkDependHSMode, doMakeMode, doInteractiveMode :: Mode
 doMkDependHSMode = mkPostLoadMode DoMkDependHS
 doMakeMode = mkPostLoadMode DoMake
 doInteractiveMode = mkPostLoadMode DoInteractive
+doAbiHashMode = mkPostLoadMode DoAbiHash
 
 showInterfaceMode :: FilePath -> Mode
 showInterfaceMode fp = mkPostLoadMode (ShowInterface fp)
@@ -519,6 +532,8 @@ mode_flags =
          Supported
   , Flag "-interactive" (PassFlag (setMode doInteractiveMode))
          Supported
+  , Flag "-abi-hash"    (PassFlag (setMode doAbiHashMode))
+         Supported
   , Flag "e"            (HasArg   (\s -> setMode (doEvalMode s) "-e"))
          Supported
 
@@ -701,6 +716,48 @@ countFS entries longest is_z has_z (b:bs) =
        countFS entries' longest' (is_z + is_zs) (has_z + has_zs) bs
 
 -- -----------------------------------------------------------------------------
+-- ABI hash support
+
+{-
+        ghc --abi-hash Data.Foo System.Bar
+
+Generates a combined hash of the ABI for modules Data.Foo and
+System.Bar.  The modules must already be compiled, and appropriate -i
+options may be necessary in order to find the .hi files.
+
+This is used by Cabal for generating the InstalledPackageId for a
+package.  The InstalledPackageId must change when the visible ABI of
+the package chagnes, so during registration Cabal calls ghc --abi-hash
+to get a hash of the package's ABI.
+-}
+
+abiHash :: [(String, Maybe Phase)] -> Ghc ()
+abiHash strs = do
+  hsc_env <- getSession
+  let dflags = hsc_dflags hsc_env
+
+  liftIO $ do
+
+  let find_it str = do
+         let modname = mkModuleName str
+         r <- findImportedModule hsc_env modname Nothing
+         case r of
+           Found _ m -> return m
+           _error    -> ghcError $ CmdLineError $ showSDoc $
+                          cannotFindInterface dflags modname r
+
+  mods <- mapM find_it (map fst strs)
+
+  let get_iface mod = loadUserInterface False (text "abiHash") mod
+  ifaces <- initIfaceCheck hsc_env $ mapM get_iface mods
+
+  bh <- openBinMem (3*1024) -- just less than a block
+  mapM_ (put_ bh . mi_mod_hash) ifaces
+  f <- fingerprintBinMem bh
+
+  putStrLn (showSDoc (ppr f))
+
+-- -----------------------------------------------------------------------------
 -- Util
 
 unknownFlagsErr :: [String] -> a