diff --git a/haskell-gi.cabal b/haskell-gi.cabal
--- a/haskell-gi.cabal
+++ b/haskell-gi.cabal
@@ -1,5 +1,5 @@
 name:                haskell-gi
-version:             0.15
+version:             0.17
 synopsis:            Generate Haskell bindings for GObject Introspection capable libraries
 description:         Generate Haskell bindings for GObject Introspection capable libraries. This includes most notably
                      Gtk+, but many other libraries in the GObject ecosystem provide introspection data too.
@@ -23,7 +23,7 @@
 Library
   pkgconfig-depends:   gobject-introspection-1.0 >= 1.42, gobject-2.0 >= 2.36
   build-depends:       base >= 4.7 && < 5,
-                       haskell-gi-base == 0.15,
+                       haskell-gi-base == 0.17,
                        Cabal >= 1.24,
                        containers,
                        directory,
diff --git a/lib/Data/GI/CodeGen/CabalHooks.hs b/lib/Data/GI/CodeGen/CabalHooks.hs
--- a/lib/Data/GI/CodeGen/CabalHooks.hs
+++ b/lib/Data/GI/CodeGen/CabalHooks.hs
@@ -11,19 +11,22 @@
 import Distribution.PackageDescription
 
 import Data.GI.CodeGen.API (loadGIRInfo)
-import Data.GI.CodeGen.Code (genCode, writeModuleTree)
+import Data.GI.CodeGen.Code (genCode, writeModuleTree, listModuleTree)
 import Data.GI.CodeGen.CodeGen (genModule)
 import Data.GI.CodeGen.Config (Config(..))
 import Data.GI.CodeGen.Overrides (parseOverridesFile, girFixups,
                                   filterAPIsAndDeps)
 import Data.GI.CodeGen.Util (ucFirst)
 
-import Data.Maybe (fromJust)
+import Data.Maybe (fromJust, fromMaybe)
 import qualified Data.Map as M
 import Data.Text (Text)
 import qualified Data.Text as T
 import qualified Data.Text.IO as TIO
 
+import System.Directory (doesFileExist)
+import System.FilePath ((</>), (<.>))
+
 type ConfHook = (GenericPackageDescription, HookedBuildInfo) -> ConfigFlags
               -> IO LocalBuildInfo
 
@@ -54,7 +57,11 @@
                     overrides = ovs}
 
   m <- genCode cfg allAPIs ["GI", ucFirst name] (genModule apis)
-  moduleList <- writeModuleTree verbosity outputDir m
+  alreadyDone <- doesFileExist (fromMaybe "" outputDir
+                                </> "GI" </> T.unpack (ucFirst name) <.> "hs")
+  moduleList <- if not alreadyDone
+                then writeModuleTree verbosity outputDir m
+                else return (listModuleTree m)
 
   let em' = map (MN.fromString . T.unpack) moduleList
       ctd' = ((condTreeData . fromJust . condLibrary) gpd) {exposedModules = em'}
diff --git a/lib/Data/GI/CodeGen/Code.hs b/lib/Data/GI/CodeGen/Code.hs
--- a/lib/Data/GI/CodeGen/Code.hs
+++ b/lib/Data/GI/CodeGen/Code.hs
@@ -10,6 +10,7 @@
     , evalCodeGen
 
     , writeModuleTree
+    , listModuleTree
     , writeModuleCode
     , codeToText
     , transitiveModuleDeps
@@ -736,6 +737,13 @@
   writeModuleInfo verbose dirPrefix minfo
   return $ (dotModuleName (moduleName minfo) : submoduleNames)
 
+-- | Return the list of modules `writeModuleCode` would write, without
+-- actually writing anything to disk.
+listModules :: ModuleInfo -> [Text]
+listModules minfo =
+    let submoduleNames = concatMap listModules (M.elems (submodules minfo))
+    in dotModuleName (moduleName minfo) : submoduleNames
+
 -- | List of reexports from the ".Types" module.
 typeReexports :: ModuleName -> [Text] -> Text
 typeReexports typesModule bootFiles =
@@ -787,3 +795,11 @@
 writeModuleTree :: Bool -> Maybe FilePath -> ModuleInfo -> IO [Text]
 writeModuleTree verbose dirPrefix minfo =
   (:) <$> writeTypes dirPrefix minfo <*> writeModuleCode verbose dirPrefix minfo
+
+-- | Return the list of modules that would be written by
+-- `writeModuleTree`, without actually writing anything to disk.
+listModuleTree :: ModuleInfo -> [Text]
+listModuleTree minfo =
+    let pkgRoot = take 2 (moduleName minfo)
+        typesModule = pkgRoot ++ ["Types"]
+    in dotModuleName typesModule : listModules minfo
