From 801272a98c719280da26cbaad7592e975c70f44f Mon Sep 17 00:00:00 2001 From: Ben Langmuir Date: Tue, 25 Feb 2014 18:23:47 +0000 Subject: [PATCH] Add a driver option -ivfsoverlay Reads the description of a virtual filesystem from a file and overlays it over the real file system. llvm-svn: 202176 --- .../clang/Basic/DiagnosticFrontendKinds.td | 5 ++++ clang/include/clang/Driver/Options.td | 2 ++ clang/include/clang/Lex/HeaderSearchOptions.h | 7 +++++ clang/lib/Basic/VirtualFileSystem.cpp | 2 +- clang/lib/Frontend/CompilerInvocation.cpp | 4 +++ clang/lib/Frontend/FrontendAction.cpp | 26 +++++++++++++++++++ clang/test/Driver/vfsoverlay.c | 5 ++++ clang/test/VFS/Inputs/actual_header.h | 1 + clang/test/VFS/Inputs/actual_module.map | 4 +++ clang/test/VFS/Inputs/include_real.h | 1 + clang/test/VFS/Inputs/invalid-yaml.yaml | 4 +++ clang/test/VFS/Inputs/missing-key.yaml | 4 +++ clang/test/VFS/Inputs/public_header.h | 1 + clang/test/VFS/Inputs/unknown-key.yaml | 5 ++++ clang/test/VFS/Inputs/unknown-value.yaml | 5 ++++ clang/test/VFS/Inputs/vfsoverlay.yaml | 21 +++++++++++++++ clang/test/VFS/framework-import.m | 9 +++++++ clang/test/VFS/implicit-include.c | 7 +++++ .../test/VFS/include-mixed-real-and-virtual.c | 14 ++++++++++ clang/test/VFS/include-real-from-virtual.c | 12 +++++++++ clang/test/VFS/include-virtual-from-real.c | 12 +++++++++ clang/test/VFS/include.c | 9 +++++++ clang/test/VFS/module-import.m | 9 +++++++ clang/test/VFS/parse-errors.c | 14 ++++++++++ 24 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 clang/test/Driver/vfsoverlay.c create mode 100644 clang/test/VFS/Inputs/actual_header.h create mode 100644 clang/test/VFS/Inputs/actual_module.map create mode 100644 clang/test/VFS/Inputs/include_real.h create mode 100644 clang/test/VFS/Inputs/invalid-yaml.yaml create mode 100644 clang/test/VFS/Inputs/missing-key.yaml create mode 100644 clang/test/VFS/Inputs/public_header.h create mode 100644 clang/test/VFS/Inputs/unknown-key.yaml create mode 100644 clang/test/VFS/Inputs/unknown-value.yaml create mode 100644 clang/test/VFS/Inputs/vfsoverlay.yaml create mode 100644 clang/test/VFS/framework-import.m create mode 100644 clang/test/VFS/implicit-include.c create mode 100644 clang/test/VFS/include-mixed-real-and-virtual.c create mode 100644 clang/test/VFS/include-real-from-virtual.c create mode 100644 clang/test/VFS/include-virtual-from-real.c create mode 100644 clang/test/VFS/include.c create mode 100644 clang/test/VFS/module-import.m create mode 100644 clang/test/VFS/parse-errors.c diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 21809ad63ff1..2b36d38a3f1b 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -158,4 +158,9 @@ def warn_module_config_macro_undef : Warning< InGroup; def note_module_def_undef_here : Note< "macro was %select{defined|#undef'd}0 here">; + +def err_missing_vfs_overlay_file : Error< + "virtual filesystem overlay file '%0' not found">, DefaultFatal; +def err_invalid_vfs_overlay : Error< + "invalid virtual filesystem overlay file '%0'">, DefaultFatal; } diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index d2192586d915..019850be3de3 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -966,6 +966,8 @@ def iwithsysroot : JoinedOrSeparate<["-"], "iwithsysroot">, Group HelpText<"Add directory to SYSTEM include search path, " "absolute paths are relative to -isysroot">, MetaVarName<"">, Flags<[CC1Option]>; +def ivfsoverlay : JoinedOrSeparate<["-"], "ivfsoverlay">, Group, Flags<[CC1Option]>, + HelpText<"Overlay the virtual filesystem described by file over the real file system">; def i : Joined<["-"], "i">, Group; def keep__private__externs : Flag<["-"], "keep_private_externs">; def l : JoinedOrSeparate<["-"], "l">, Flags<[LinkerInput, RenderJoined]>; diff --git a/clang/include/clang/Lex/HeaderSearchOptions.h b/clang/include/clang/Lex/HeaderSearchOptions.h index b471b8cafe48..5abcdad2d579 100644 --- a/clang/include/clang/Lex/HeaderSearchOptions.h +++ b/clang/include/clang/Lex/HeaderSearchOptions.h @@ -129,6 +129,9 @@ public: /// \brief The set of user-provided module-map-files. llvm::SetVector ModuleMapFiles; + /// \brief The set of user-provided virtual filesystem overlay files. + std::vector VFSOverlayFiles; + /// Include the compiler builtin includes. unsigned UseBuiltinIncludes : 1; @@ -172,6 +175,10 @@ public: void AddSystemHeaderPrefix(StringRef Prefix, bool IsSystemHeader) { SystemHeaderPrefixes.push_back(SystemHeaderPrefix(Prefix, IsSystemHeader)); } + + void AddVFSOverlayFile(StringRef Name) { + VFSOverlayFiles.push_back(Name); + } }; } // end namespace clang diff --git a/clang/lib/Basic/VirtualFileSystem.cpp b/clang/lib/Basic/VirtualFileSystem.cpp index 881e1663953f..539cbb740971 100644 --- a/clang/lib/Basic/VirtualFileSystem.cpp +++ b/clang/lib/Basic/VirtualFileSystem.cpp @@ -761,7 +761,7 @@ error_code VFSFromYAML::openFileForRead(const Twine &Path, if (!F) // FIXME: errc::not_a_file? return error_code(errc::invalid_argument, system_category()); - return ExternalFS->openFileForRead(Path, Result); + return ExternalFS->openFileForRead(F->getExternalContentsPath(), Result); } IntrusiveRefCntPtr diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 4ef5cfef7c0b..ad2d37cc2973 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1020,6 +1020,10 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { I != E; ++I) Opts.AddSystemHeaderPrefix((*I)->getValue(), (*I)->getOption().matches(OPT_isystem_prefix)); + + for (arg_iterator I = Args.filtered_begin(OPT_ivfsoverlay), + E = Args.filtered_end(); I != E; ++I) + Opts.AddVFSOverlayFile((*I)->getValue()); } void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index 72377d84572a..6cfa12168dbf 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -211,6 +211,32 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, return true; } + if (!CI.getHeaderSearchOpts().VFSOverlayFiles.empty()) { + IntrusiveRefCntPtr + Overlay(new vfs::OverlayFileSystem(vfs::getRealFileSystem())); + // earlier vfs files are on the bottom + const std::vector &Files = + CI.getHeaderSearchOpts().VFSOverlayFiles; + for (std::vector::const_iterator I = Files.begin(), + E = Files.end(); + I != E; ++I) { + OwningPtr Buffer; + if (llvm::errc::success != llvm::MemoryBuffer::getFile(*I, Buffer)) { + CI.getDiagnostics().Report(diag::err_missing_vfs_overlay_file) << *I; + goto failure; + } + + IntrusiveRefCntPtr FS = + vfs::getVFSFromYAML(Buffer.take(), /*DiagHandler*/0); + if (!FS.getPtr()) { + CI.getDiagnostics().Report(diag::err_invalid_vfs_overlay) << *I; + goto failure; + } + Overlay->pushOverlay(FS); + } + CI.setVirtualFileSystem(Overlay); + } + // Set up the file and source managers, if needed. if (!CI.hasFileManager()) CI.createFileManager(); diff --git a/clang/test/Driver/vfsoverlay.c b/clang/test/Driver/vfsoverlay.c new file mode 100644 index 000000000000..6ae494544f9f --- /dev/null +++ b/clang/test/Driver/vfsoverlay.c @@ -0,0 +1,5 @@ +// RUN: %clang -ivfsoverlay foo.h -### %s 2>&1 | FileCheck %s +// CHECK: "-ivfsoverlay" "foo.h" + +// RUN: not %clang -ivfsoverlay foo.h %s 2>&1 | FileCheck -check-prefix=CHECK-MISSING %s +// CHECK-MISSING: virtual filesystem overlay file 'foo.h' not found diff --git a/clang/test/VFS/Inputs/actual_header.h b/clang/test/VFS/Inputs/actual_header.h new file mode 100644 index 000000000000..f61e58620c65 --- /dev/null +++ b/clang/test/VFS/Inputs/actual_header.h @@ -0,0 +1 @@ +void bar(void); diff --git a/clang/test/VFS/Inputs/actual_module.map b/clang/test/VFS/Inputs/actual_module.map new file mode 100644 index 000000000000..282dac37c7b0 --- /dev/null +++ b/clang/test/VFS/Inputs/actual_module.map @@ -0,0 +1,4 @@ +module not_real { + header "not_real.h" + export * +} diff --git a/clang/test/VFS/Inputs/include_real.h b/clang/test/VFS/Inputs/include_real.h new file mode 100644 index 000000000000..0750c6527221 --- /dev/null +++ b/clang/test/VFS/Inputs/include_real.h @@ -0,0 +1 @@ +#include "real.h" diff --git a/clang/test/VFS/Inputs/invalid-yaml.yaml b/clang/test/VFS/Inputs/invalid-yaml.yaml new file mode 100644 index 000000000000..2a6c6667ce4d --- /dev/null +++ b/clang/test/VFS/Inputs/invalid-yaml.yaml @@ -0,0 +1,4 @@ +{ + 'version': 0, + 'roots': [] +] diff --git a/clang/test/VFS/Inputs/missing-key.yaml b/clang/test/VFS/Inputs/missing-key.yaml new file mode 100644 index 000000000000..5d18c244ee56 --- /dev/null +++ b/clang/test/VFS/Inputs/missing-key.yaml @@ -0,0 +1,4 @@ +{ + 'version': 0, + 'roots': [ { 'name' : 'foo', 'external-contents': 'bar' } ] +} diff --git a/clang/test/VFS/Inputs/public_header.h b/clang/test/VFS/Inputs/public_header.h new file mode 100644 index 000000000000..471107762b15 --- /dev/null +++ b/clang/test/VFS/Inputs/public_header.h @@ -0,0 +1 @@ +void from_framework(void); diff --git a/clang/test/VFS/Inputs/unknown-key.yaml b/clang/test/VFS/Inputs/unknown-key.yaml new file mode 100644 index 000000000000..ec7d8261d95f --- /dev/null +++ b/clang/test/VFS/Inputs/unknown-key.yaml @@ -0,0 +1,5 @@ +{ + 'version': 0, + 'unknown-key': 'value', + 'roots': [] +} diff --git a/clang/test/VFS/Inputs/unknown-value.yaml b/clang/test/VFS/Inputs/unknown-value.yaml new file mode 100644 index 000000000000..4e90b2134cc8 --- /dev/null +++ b/clang/test/VFS/Inputs/unknown-value.yaml @@ -0,0 +1,5 @@ +{ + 'version': 0, + 'case-sensitive': 'Maybe?', + 'roots': [] +} diff --git a/clang/test/VFS/Inputs/vfsoverlay.yaml b/clang/test/VFS/Inputs/vfsoverlay.yaml new file mode 100644 index 000000000000..331ed333168f --- /dev/null +++ b/clang/test/VFS/Inputs/vfsoverlay.yaml @@ -0,0 +1,21 @@ +{ + 'version': 0, + 'roots': [ + { 'name': 'OUT_DIR', 'type': 'directory', + 'contents': [ + { 'name': 'not_real.h', 'type': 'file', + 'external-contents': 'INPUT_DIR/actual_header.h' + }, + { 'name': 'module.map', 'type': 'file', + 'external-contents': 'INPUT_DIR/actual_module.map' + }, + { 'name': 'include_real.h', 'type': 'file', + 'external-contents': 'INPUT_DIR/include_real.h' + }, + { 'name': 'SomeFramework.framework/Headers/public_header.h', 'type': 'file', + 'external-contents': 'INPUT_DIR/public_header.h' + } + ] + } + ] +} diff --git a/clang/test/VFS/framework-import.m b/clang/test/VFS/framework-import.m new file mode 100644 index 000000000000..b40bc549c0a9 --- /dev/null +++ b/clang/test/VFS/framework-import.m @@ -0,0 +1,9 @@ +// RUN: sed -e "s:INPUT_DIR:%S/Inputs:g" -e "s:OUT_DIR:%t:g" %S/Inputs/vfsoverlay.yaml > %t.yaml +// RUN: %clang_cc1 -Werror -F %t -ivfsoverlay %t.yaml -fsyntax-only %s +// REQUIRES: shell + +#import + +void foo() { + from_framework(); +} diff --git a/clang/test/VFS/implicit-include.c b/clang/test/VFS/implicit-include.c new file mode 100644 index 000000000000..acf665bee248 --- /dev/null +++ b/clang/test/VFS/implicit-include.c @@ -0,0 +1,7 @@ +// RUN: sed -e "s:INPUT_DIR:%S/Inputs:g" -e "s:OUT_DIR:%t:g" %S/Inputs/vfsoverlay.yaml > %t.yaml +// RUN: %clang_cc1 -Werror -ivfsoverlay %t.yaml -I %t -include "not_real.h" -fsyntax-only %s +// REQUIRES: shell + +void foo() { + bar(); +} diff --git a/clang/test/VFS/include-mixed-real-and-virtual.c b/clang/test/VFS/include-mixed-real-and-virtual.c new file mode 100644 index 000000000000..e1f5f952cd4e --- /dev/null +++ b/clang/test/VFS/include-mixed-real-and-virtual.c @@ -0,0 +1,14 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: echo "void baz(void);" > %t/real.h +// RUN: sed -e "s:INPUT_DIR:%S/Inputs:g" -e "s:OUT_DIR:%t:g" %S/Inputs/vfsoverlay.yaml > %t.yaml +// RUN: %clang_cc1 -Werror -ivfsoverlay %t.yaml -I %t -fsyntax-only %s +// REQUIRES: shell + +#include "not_real.h" +#include "real.h" + +void foo() { + bar(); + baz(); +} diff --git a/clang/test/VFS/include-real-from-virtual.c b/clang/test/VFS/include-real-from-virtual.c new file mode 100644 index 000000000000..65707b551643 --- /dev/null +++ b/clang/test/VFS/include-real-from-virtual.c @@ -0,0 +1,12 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: echo "void baz(void);" > %t/real.h +// RUN: sed -e "s:INPUT_DIR:%S/Inputs:g" -e "s:OUT_DIR:%t:g" %S/Inputs/vfsoverlay.yaml > %t.yaml +// RUN: %clang_cc1 -Werror -ivfsoverlay %t.yaml -I %t -fsyntax-only %s +// REQUIRES: shell + +#include "include_real.h" + +void foo() { + baz(); +} diff --git a/clang/test/VFS/include-virtual-from-real.c b/clang/test/VFS/include-virtual-from-real.c new file mode 100644 index 000000000000..c8f6059608d7 --- /dev/null +++ b/clang/test/VFS/include-virtual-from-real.c @@ -0,0 +1,12 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: echo '#include "not_real.h"' > %t/include_not_real.h +// RUN: sed -e "s:INPUT_DIR:%S/Inputs:g" -e "s:OUT_DIR:%t:g" %S/Inputs/vfsoverlay.yaml > %t.yaml +// RUN: %clang_cc1 -Werror -ivfsoverlay %t.yaml -I %t -fsyntax-only %s +// REQUIRES: shell + +#include "include_not_real.h" + +void foo() { + bar(); +} diff --git a/clang/test/VFS/include.c b/clang/test/VFS/include.c new file mode 100644 index 000000000000..8cd04dd45212 --- /dev/null +++ b/clang/test/VFS/include.c @@ -0,0 +1,9 @@ +// RUN: sed -e "s:INPUT_DIR:%S/Inputs:g" -e "s:OUT_DIR:%t:g" %S/Inputs/vfsoverlay.yaml > %t.yaml +// RUN: %clang_cc1 -Werror -I %t -ivfsoverlay %t.yaml -fsyntax-only %s +// REQUIRES: shell + +#include "not_real.h" + +void foo() { + bar(); +} diff --git a/clang/test/VFS/module-import.m b/clang/test/VFS/module-import.m new file mode 100644 index 000000000000..80f0ea58f1d4 --- /dev/null +++ b/clang/test/VFS/module-import.m @@ -0,0 +1,9 @@ +// RUN: sed -e "s:INPUT_DIR:%S/Inputs:g" -e "s:OUT_DIR:%t:g" %S/Inputs/vfsoverlay.yaml > %t.yaml +// RUN: %clang_cc1 -Werror -fmodules -fmodules-cache-path=%t -ivfsoverlay %t.yaml -I %t -fsyntax-only %s +// REQUIRES: shell + +@import not_real; + +void foo() { + bar(); +} diff --git a/clang/test/VFS/parse-errors.c b/clang/test/VFS/parse-errors.c new file mode 100644 index 000000000000..7194efc65a5d --- /dev/null +++ b/clang/test/VFS/parse-errors.c @@ -0,0 +1,14 @@ +// RUN: not %clang_cc1 -ivfsoverlay %S/Inputs/invalid-yaml.yaml -fsyntax-only %s 2>&1 | FileCheck %s +// CHECK: invalid virtual filesystem overlay file + +// RUN: not %clang_cc1 -ivfsoverlay %S/Inputs/missing-key.yaml -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-MISSING-TYPE %s +// CHECK-MISSING-TYPE: missing key 'type' +// CHECK-MISSING-TYPE: invalid virtual filesystem overlay file + +// RUN: not %clang_cc1 -ivfsoverlay %S/Inputs/unknown-key.yaml -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-KEY %s +// CHECK-UNKNOWN-KEY: unknown key +// CHECK-UNKNOWN-KEY: invalid virtual filesystem overlay file + +// RUN: not %clang_cc1 -ivfsoverlay %S/Inputs/unknown-value.yaml -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-VALUE %s +// CHECK-UNKNOWN-VALUE: expected boolean value +// CHECK-UNKNOWN-VALUE: invalid virtual filesystem overlay file