[clang] 7defab0 - Reapply "[clang][deps] Support inferred modules"

Jan Svoboda via cfe-commits cfe-commits at lists.llvm.org
Thu May 20 03:42:32 PDT 2021


Author: Michael Spencer
Date: 2021-05-20T12:41:52+02:00
New Revision: 7defab082070adf3d04b326ba160b029394edc7c

URL: https://github.com/llvm/llvm-project/commit/7defab082070adf3d04b326ba160b029394edc7c
DIFF: https://github.com/llvm/llvm-project/commit/7defab082070adf3d04b326ba160b029394edc7c.diff

LOG: Reapply "[clang][deps] Support inferred modules"

This reverts commit 76b8754d and ensures the PCM files are created in the correct directory (not in the current working directory).

Added: 
    clang/test/ClangScanDeps/Inputs/frameworks/Inferred.framework/Frameworks/Sub.framework/Headers/Sub.h
    clang/test/ClangScanDeps/Inputs/frameworks/Inferred.framework/Headers/Inferred.h
    clang/test/ClangScanDeps/Inputs/frameworks/System.framework/Headers/System.h
    clang/test/ClangScanDeps/Inputs/frameworks/System.framework/Modules/module.modulemap
    clang/test/ClangScanDeps/Inputs/frameworks/module.modulemap
    clang/test/ClangScanDeps/Inputs/modules_inferred_cdb.json
    clang/test/ClangScanDeps/modules-inferred-explicit-build.m
    clang/test/ClangScanDeps/modules-inferred.m
    clang/utils/module-deps-to-rsp.py

Modified: 
    clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
    clang/test/ClangScanDeps/modules-full.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
index 51b7fc48628c1..dfd853822327e 100644
--- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -33,7 +33,6 @@ makeInvocationForModuleBuildWithoutPaths(const ModuleDeps &Deps,
   CI.getFrontendOpts().IsSystemModule = Deps.IsSystem;
 
   CI.getLangOpts()->ImplicitModules = false;
-  CI.getHeaderSearchOpts().ImplicitModuleMaps = false;
 
   return CI;
 }
@@ -57,10 +56,16 @@ std::vector<std::string> ModuleDeps::getCanonicalCommandLine(
     std::function<StringRef(ModuleID)> LookupPCMPath,
     std::function<const ModuleDeps &(ModuleID)> LookupModuleDeps) const {
   CompilerInvocation CI(Invocation);
+  FrontendOptions &FrontendOpts = CI.getFrontendOpts();
+
+  InputKind ModuleMapInputKind(FrontendOpts.DashX.getLanguage(),
+                               InputKind::Format::ModuleMap);
+  FrontendOpts.Inputs.emplace_back(ClangModuleMapFile, ModuleMapInputKind);
+  FrontendOpts.OutputFile = std::string(LookupPCMPath(ID));
 
   dependencies::detail::collectPCMAndModuleMapPaths(
       ClangModuleDeps, LookupPCMPath, LookupModuleDeps,
-      CI.getFrontendOpts().ModuleFiles, CI.getFrontendOpts().ModuleMapFiles);
+      FrontendOpts.ModuleFiles, FrontendOpts.ModuleMapFiles);
 
   return serializeCompilerInvocation(CI);
 }
@@ -179,13 +184,22 @@ ModuleID ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
   const FileEntry *ModuleMap = Instance.getPreprocessor()
                                    .getHeaderSearchInfo()
                                    .getModuleMap()
-                                   .getContainingModuleMapFile(M);
+                                   .getModuleMapFileForUniquing(M);
   MD.ClangModuleMapFile = std::string(ModuleMap ? ModuleMap->getName() : "");
 
   serialization::ModuleFile *MF =
       MDC.Instance.getASTReader()->getModuleManager().lookup(M->getASTFile());
   MDC.Instance.getASTReader()->visitInputFiles(
       *MF, true, true, [&](const serialization::InputFile &IF, bool isSystem) {
+        // __inferred_module.map is the result of the way in which an implicit
+        // module build handles inferred modules. It adds an overlay VFS with
+        // this file in the proper directory and relies on the rest of Clang to
+        // handle it like normal. With explicitly built modules we don't need
+        // to play VFS tricks, so replace it with the correct module map.
+        if (IF.getFile()->getName().endswith("__inferred_module.map")) {
+          MD.FileDeps.insert(ModuleMap->getName());
+          return;
+        }
         MD.FileDeps.insert(IF.getFile()->getName());
       });
 

diff  --git a/clang/test/ClangScanDeps/Inputs/frameworks/Inferred.framework/Frameworks/Sub.framework/Headers/Sub.h b/clang/test/ClangScanDeps/Inputs/frameworks/Inferred.framework/Frameworks/Sub.framework/Headers/Sub.h
new file mode 100644
index 0000000000000..e69de29bb2d1d

diff  --git a/clang/test/ClangScanDeps/Inputs/frameworks/Inferred.framework/Headers/Inferred.h b/clang/test/ClangScanDeps/Inputs/frameworks/Inferred.framework/Headers/Inferred.h
new file mode 100644
index 0000000000000..1855e4fad5f8d
--- /dev/null
+++ b/clang/test/ClangScanDeps/Inputs/frameworks/Inferred.framework/Headers/Inferred.h
@@ -0,0 +1 @@
+typedef int inferred;

diff  --git a/clang/test/ClangScanDeps/Inputs/frameworks/System.framework/Headers/System.h b/clang/test/ClangScanDeps/Inputs/frameworks/System.framework/Headers/System.h
new file mode 100644
index 0000000000000..a90c62886749f
--- /dev/null
+++ b/clang/test/ClangScanDeps/Inputs/frameworks/System.framework/Headers/System.h
@@ -0,0 +1 @@
+enum { bigger_than_int = 0x80000000 };

diff  --git a/clang/test/ClangScanDeps/Inputs/frameworks/System.framework/Modules/module.modulemap b/clang/test/ClangScanDeps/Inputs/frameworks/System.framework/Modules/module.modulemap
new file mode 100644
index 0000000000000..51f72f6642351
--- /dev/null
+++ b/clang/test/ClangScanDeps/Inputs/frameworks/System.framework/Modules/module.modulemap
@@ -0,0 +1,3 @@
+framework module System [system] {
+  umbrella header "System.h"
+}

diff  --git a/clang/test/ClangScanDeps/Inputs/frameworks/module.modulemap b/clang/test/ClangScanDeps/Inputs/frameworks/module.modulemap
new file mode 100644
index 0000000000000..e3bad873c7e7b
--- /dev/null
+++ b/clang/test/ClangScanDeps/Inputs/frameworks/module.modulemap
@@ -0,0 +1 @@
+framework module * {}

diff  --git a/clang/test/ClangScanDeps/Inputs/modules_inferred_cdb.json b/clang/test/ClangScanDeps/Inputs/modules_inferred_cdb.json
new file mode 100644
index 0000000000000..e88dc88fa1b49
--- /dev/null
+++ b/clang/test/ClangScanDeps/Inputs/modules_inferred_cdb.json
@@ -0,0 +1,7 @@
+[
+{
+  "directory": "DIR",
+  "command": "clang -E DIR/modules_cdb_input.cpp -FFRAMEWORKS -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-modules -fimplicit-module-maps -pedantic -Werror",
+  "file": "DIR/modules_cdb_input.cpp"
+}
+]

diff  --git a/clang/test/ClangScanDeps/modules-full.cpp b/clang/test/ClangScanDeps/modules-full.cpp
index ebd86e79a3fb8..a8d18abea41e6 100644
--- a/clang/test/ClangScanDeps/modules-full.cpp
+++ b/clang/test/ClangScanDeps/modules-full.cpp
@@ -48,7 +48,6 @@
 // CHECK:              "-emit-module"
 // CHECK-NO-ABS-NOT:   "-fmodule-file={{.*}}"
 // CHECK-ABS:          "-fmodule-file=[[PREFIX]]/module-cache{{(_clangcl)?}}/[[CONTEXT_HASH_H1]]/header2-{{[A-Z0-9]+}}.pcm"
-// CHECK-NOT:          "-fimplicit-module-maps"
 // CHECK:              "-fmodule-name=header1"
 // CHECK:              "-fno-implicit-modules"
 // CHECK:            ],
@@ -65,7 +64,6 @@
 // CHECK-NEXT:       "command-line": [
 // CHECK-NEXT:         "-cc1",
 // CHECK:              "-emit-module",
-// CHECK-NOT:          "-fimplicit-module-maps",
 // CHECK:              "-fmodule-name=header1",
 // CHECK:              "-fno-implicit-modules",
 // CHECK:            ],
@@ -82,7 +80,6 @@
 // CHECK-NEXT:       "command-line": [
 // CHECK-NEXT:         "-cc1",
 // CHECK:              "-emit-module",
-// CHECK-NOT:          "-fimplicit-module-maps",
 // CHECK:              "-fmodule-name=header2",
 // CHECK:              "-fno-implicit-modules",
 // CHECK:            ],

diff  --git a/clang/test/ClangScanDeps/modules-inferred-explicit-build.m b/clang/test/ClangScanDeps/modules-inferred-explicit-build.m
new file mode 100644
index 0000000000000..4471eb38fdb74
--- /dev/null
+++ b/clang/test/ClangScanDeps/modules-inferred-explicit-build.m
@@ -0,0 +1,22 @@
+// RUN: rm -rf %t.dir
+// RUN: rm -rf %t.cdb
+// RUN: mkdir -p %t.dir
+// RUN: cp %s %t.dir/modules_cdb_input.cpp
+// RUN: sed -e "s|DIR|%/t.dir|g" -e "s|FRAMEWORKS|%/S/Inputs/frameworks|g" -e "s|-E|-x objective-c -E|g" \
+// RUN:   %S/Inputs/modules_inferred_cdb.json > %t.cdb
+//
+// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -format experimental-full \
+// RUN:   -mode preprocess-minimized-sources -generate-modules-path-args > %t.db
+// RUN: %python %S/../../utils/module-deps-to-rsp.py %t.db --module-name=Inferred > %t.inferred.cc1.rsp
+// RUN: %python %S/../../utils/module-deps-to-rsp.py %t.db --module-name=System > %t.system.cc1.rsp
+// RUN: %python %S/../../utils/module-deps-to-rsp.py %t.db --tu-index=0 > %t.tu.rsp
+// RUN: %clang @%t.inferred.cc1.rsp -pedantic -Werror
+// RUN: %clang @%t.system.cc1.rsp -pedantic -Werror
+// RUN: %clang -x objective-c -fsyntax-only %t.dir/modules_cdb_input.cpp \
+// RUN:   -F%S/Inputs/frameworks -fmodules -fimplicit-module-maps \
+// RUN:   -pedantic -Werror @%t.tu.rsp
+
+#include <Inferred/Inferred.h>
+#include <System/System.h>
+
+inferred a = bigger_than_int;

diff  --git a/clang/test/ClangScanDeps/modules-inferred.m b/clang/test/ClangScanDeps/modules-inferred.m
new file mode 100644
index 0000000000000..19a7ee0a4c8fe
--- /dev/null
+++ b/clang/test/ClangScanDeps/modules-inferred.m
@@ -0,0 +1,61 @@
+// RUN: rm -rf %t.dir
+// RUN: rm -rf %t.cdb
+// RUN: mkdir -p %t.dir
+// RUN: cp %s %t.dir/modules_cdb_input.cpp
+// RUN: sed -e "s|DIR|%/t.dir|g" -e "s|FRAMEWORKS|%/S/Inputs/frameworks|g" \
+// RUN:   %/S/Inputs/modules_inferred_cdb.json > %t.cdb
+//
+// RUN: echo -%t.dir > %t.result
+// RUN: echo -%S >> %t.result
+// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -format experimental-full \
+// RUN:   -generate-modules-path-args -mode preprocess-minimized-sources >> %t.result
+// RUN: cat %t.result | sed -e 's/\\\\/\//g' -e 's/\\/\//g' | FileCheck --check-prefixes=CHECK %s
+
+#include <Inferred/Inferred.h>
+
+inferred a = 0;
+
+// CHECK: -[[PREFIX:.*]]
+// CHECK-NEXT: -[[SOURCEDIR:.*]]
+// CHECK-NEXT: {
+// CHECK-NEXT:   "modules": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:       "clang-module-deps": [],
+// CHECK-NEXT:       "clang-modulemap-file": "[[SOURCEDIR]]/Inputs/frameworks/module.modulemap",
+// CHECK-NEXT:       "command-line": [
+// CHECK-NEXT:         "-cc1",
+// CHECK:              "-emit-module",
+// CHECK:              "-fmodule-name=Inferred",
+// CHECK:              "-fno-implicit-modules",
+// CHECK:            ],
+// CHECK-NEXT:       "context-hash": "[[CONTEXT_HASH_H1:[A-Z0-9]+]]",
+// CHECK-NEXT:       "file-deps": [
+// CHECK-NEXT:         "[[SOURCEDIR]]/Inputs/frameworks/Inferred.framework/Frameworks/Sub.framework/Headers/Sub.h",
+// CHECK-NEXT:         "[[SOURCEDIR]]/Inputs/frameworks/Inferred.framework/Headers/Inferred.h",
+// CHECK-NEXT:         "[[SOURCEDIR]]/Inputs/frameworks/module.modulemap"
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "name": "Inferred"
+// CHECK-NEXT:     }
+// CHECK-NEXT:   ],
+// CHECK-NEXT:   "translation-units": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:       "clang-context-hash": "[[CONTEXT_HASH_H1]]",
+// CHECK-NEXT:       "clang-module-deps": [
+// CHECK-NEXT:         {
+// CHECK-NEXT:           "context-hash": "[[CONTEXT_HASH_H1]]",
+// CHECK-NEXT:           "module-name": "Inferred"
+// CHECK-NEXT:         }
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "command-line": [
+// CHECK-NEXT:         "-fno-implicit-modules",
+// CHECK-NEXT:         "-fno-implicit-module-maps",
+// CHECK-NEXT:         "-fmodule-file=[[PREFIX]]/module-cache/[[CONTEXT_HASH_H1]]/Inferred-{{[A-Z0-9]+}}.pcm",
+// CHECK-NEXT:         "-fmodule-map-file=[[SOURCEDIR]]/Inputs/frameworks/module.modulemap"
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "file-deps": [
+// CHECK-NEXT:         "[[PREFIX]]/modules_cdb_input.cpp"
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "input-file": "[[PREFIX]]/modules_cdb_input.cpp"
+// CHECK-NEXT:     }
+// CHECK-NEXT:   ]
+// CHECK-NEXT: }

diff  --git a/clang/utils/module-deps-to-rsp.py b/clang/utils/module-deps-to-rsp.py
new file mode 100755
index 0000000000000..416b4e6a88749
--- /dev/null
+++ b/clang/utils/module-deps-to-rsp.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+
+# Converts clang-scan-deps output into response files.
+#   * For modules, arguments in the resulting response file are enough to build a PCM.
+#   * For translation units, the response file needs to be added to the original Clang invocation from compilation
+#     database.
+#
+# Usage:
+#
+#   clang-scan-deps -compilation-database compile_commands.json ... > deps.json
+#   module-deps-to-rsp.py deps.json --module-name=ModuleName > module_name.cc1.rsp
+#   module-deps-to-rsp.py deps.json --tu-index=0 > tu.rsp
+#   clang @module_name.cc1.rsp
+#   clang ... @tu.rsp
+
+import argparse
+import json
+import sys
+
+class ModuleNotFoundError(Exception):
+  def __init__(self, module_name):
+    self.module_name = module_name
+
+class FullDeps:
+  def __init__(self):
+    self.modules = {}
+    self.translation_units = []
+
+def findModule(module_name, full_deps):
+  for m in full_deps.modules.values():
+    if m['name'] == module_name:
+      return m
+  raise ModuleNotFoundError(module_name)
+
+def parseFullDeps(json):
+  ret = FullDeps()
+  for m in json['modules']:
+    ret.modules[m['name'] + '-' + m['context-hash']] = m
+  ret.translation_units = json['translation-units']
+  return ret
+
+def quote(str):
+  return '"' + str.replace("\\", "\\\\") + '"'
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument("full_deps_file", help="Path to the full dependencies json file",
+                      type=str)
+  action = parser.add_mutually_exclusive_group(required=True)
+  action.add_argument("--module-name", help="The name of the module to get arguments for",
+                      type=str)
+  action.add_argument("--tu-index", help="The index of the translation unit to get arguments for",
+                      type=int)
+  args = parser.parse_args()
+
+  full_deps = parseFullDeps(json.load(open(args.full_deps_file, 'r')))
+
+  try:
+    cmd = []
+
+    if args.module_name:
+      cmd = findModule(args.module_name, full_deps)['command-line']
+    elif args.tu_index != None:
+      cmd = full_deps.translation_units[args.tu_index]['command-line']
+
+    print(" ".join(map(quote, cmd)))
+  except:
+    print("Unexpected error:", sys.exc_info()[0])
+    raise
+
+if __name__ == '__main__':
+  main()


        


More information about the cfe-commits mailing list