Skip to content
Snippets Groups Projects
Commit c98833cd authored by Michael Spencer's avatar Michael Spencer Committed by Jan Svoboda
Browse files

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

This reapplies commit 95033eb3 that reverted commit 1d9e8e13.

The tests were failing on Windows due to spaces and backslashes in paths not being handled carefully.
parent f5b54264
No related branches found
No related tags found
No related merge requests found
Showing
with 200 additions and 5 deletions
......@@ -33,7 +33,6 @@ makeInvocationForModuleBuildWithoutPaths(const ModuleDeps &Deps,
CI.getFrontendOpts().IsSystemModule = Deps.IsSystem;
CI.getLangOpts()->ImplicitModules = false;
CI.getHeaderSearchOpts().ImplicitModuleMaps = false;
return CI;
}
......@@ -179,13 +178,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());
});
......
typedef int inferred;
enum { bigger_than_int = 0x80000000 };
framework module System [system] {
umbrella header "System.h"
}
framework module * {}
[
{
"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"
}
]
......@@ -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: ],
......
// 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 > %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;
// 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: }
#!/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 = dict()
self.translation_units = str()
def getModulePathArgs(modules, full_deps):
cmd = []
for md in modules:
m = full_deps.modules[md['module-name'] + '-' + md['context-hash']]
cmd += [u'-fmodule-map-file=' + m['clang-modulemap-file']]
cmd += [u'-fmodule-file=' + md['module-name'] + '-' + md['context-hash'] + '.pcm']
return cmd
def getCommandLineForModule(module_name, full_deps):
for m in full_deps.modules.values():
if m['name'] == module_name:
module = m
break
else:
raise ModuleNotFoundError(module_name)
cmd = m['command-line']
cmd += getModulePathArgs(m['clang-module-deps'], full_deps)
cmd += [u'-o', m['name'] + '-' + m['context-hash'] + '.pcm']
cmd += [m['clang-modulemap-file']]
return cmd
def getCommandLineForTU(tu, full_deps):
cmd = tu['command-line']
cmd += getModulePathArgs(tu['clang-module-deps'], full_deps)
return cmd
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 = getCommandLineForModule(args.module_name, full_deps)
elif args.tu_index != None:
cmd = getCommandLineForTU(full_deps.translation_units[args.tu_index], full_deps)
print(" ".join(map(quote, cmd)))
except:
print("Unexpected error:", sys.exc_info()[0])
raise
if __name__ == '__main__':
main()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment