From 89de580b52889e160a604bd735fc4e79147661cb 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@202176 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../clang/Basic/DiagnosticFrontendKinds.td | 5 ++++ include/clang/Driver/Options.td | 2 ++ include/clang/Lex/HeaderSearchOptions.h | 7 +++++ lib/Basic/VirtualFileSystem.cpp | 2 +- lib/Frontend/CompilerInvocation.cpp | 4 +++ lib/Frontend/FrontendAction.cpp | 26 +++++++++++++++++++ test/Driver/vfsoverlay.c | 5 ++++ test/VFS/Inputs/actual_header.h | 1 + test/VFS/Inputs/actual_module.map | 4 +++ test/VFS/Inputs/include_real.h | 1 + test/VFS/Inputs/invalid-yaml.yaml | 4 +++ test/VFS/Inputs/missing-key.yaml | 4 +++ test/VFS/Inputs/public_header.h | 1 + test/VFS/Inputs/unknown-key.yaml | 5 ++++ test/VFS/Inputs/unknown-value.yaml | 5 ++++ test/VFS/Inputs/vfsoverlay.yaml | 21 +++++++++++++++ test/VFS/framework-import.m | 9 +++++++ test/VFS/implicit-include.c | 7 +++++ test/VFS/include-mixed-real-and-virtual.c | 14 ++++++++++ test/VFS/include-real-from-virtual.c | 12 +++++++++ test/VFS/include-virtual-from-real.c | 12 +++++++++ test/VFS/include.c | 9 +++++++ test/VFS/module-import.m | 9 +++++++ test/VFS/parse-errors.c | 14 ++++++++++ 24 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 test/Driver/vfsoverlay.c create mode 100644 test/VFS/Inputs/actual_header.h create mode 100644 test/VFS/Inputs/actual_module.map create mode 100644 test/VFS/Inputs/include_real.h create mode 100644 test/VFS/Inputs/invalid-yaml.yaml create mode 100644 test/VFS/Inputs/missing-key.yaml create mode 100644 test/VFS/Inputs/public_header.h create mode 100644 test/VFS/Inputs/unknown-key.yaml create mode 100644 test/VFS/Inputs/unknown-value.yaml create mode 100644 test/VFS/Inputs/vfsoverlay.yaml create mode 100644 test/VFS/framework-import.m create mode 100644 test/VFS/implicit-include.c create mode 100644 test/VFS/include-mixed-real-and-virtual.c create mode 100644 test/VFS/include-real-from-virtual.c create mode 100644 test/VFS/include-virtual-from-real.c create mode 100644 test/VFS/include.c create mode 100644 test/VFS/module-import.m create mode 100644 test/VFS/parse-errors.c diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index 21809ad63f..2b36d38a3f 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/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/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index d2192586d9..019850be3d 100644 --- a/include/clang/Driver/Options.td +++ b/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/include/clang/Lex/HeaderSearchOptions.h b/include/clang/Lex/HeaderSearchOptions.h index b471b8cafe..5abcdad2d5 100644 --- a/include/clang/Lex/HeaderSearchOptions.h +++ b/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/lib/Basic/VirtualFileSystem.cpp b/lib/Basic/VirtualFileSystem.cpp index 881e166395..539cbb7409 100644 --- a/lib/Basic/VirtualFileSystem.cpp +++ b/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/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 4ef5cfef7c..ad2d37cc29 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/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/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index 72377d8457..6cfa12168d 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/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/test/Driver/vfsoverlay.c b/test/Driver/vfsoverlay.c new file mode 100644 index 0000000000..6ae494544f --- /dev/null +++ b/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/test/VFS/Inputs/actual_header.h b/test/VFS/Inputs/actual_header.h new file mode 100644 index 0000000000..f61e58620c --- /dev/null +++ b/test/VFS/Inputs/actual_header.h @@ -0,0 +1 @@ +void bar(void); diff --git a/test/VFS/Inputs/actual_module.map b/test/VFS/Inputs/actual_module.map new file mode 100644 index 0000000000..282dac37c7 --- /dev/null +++ b/test/VFS/Inputs/actual_module.map @@ -0,0 +1,4 @@ +module not_real { + header "not_real.h" + export * +} diff --git a/test/VFS/Inputs/include_real.h b/test/VFS/Inputs/include_real.h new file mode 100644 index 0000000000..0750c65272 --- /dev/null +++ b/test/VFS/Inputs/include_real.h @@ -0,0 +1 @@ +#include "real.h" diff --git a/test/VFS/Inputs/invalid-yaml.yaml b/test/VFS/Inputs/invalid-yaml.yaml new file mode 100644 index 0000000000..2a6c6667ce --- /dev/null +++ b/test/VFS/Inputs/invalid-yaml.yaml @@ -0,0 +1,4 @@ +{ + 'version': 0, + 'roots': [] +] diff --git a/test/VFS/Inputs/missing-key.yaml b/test/VFS/Inputs/missing-key.yaml new file mode 100644 index 0000000000..5d18c244ee --- /dev/null +++ b/test/VFS/Inputs/missing-key.yaml @@ -0,0 +1,4 @@ +{ + 'version': 0, + 'roots': [ { 'name' : 'foo', 'external-contents': 'bar' } ] +} diff --git a/test/VFS/Inputs/public_header.h b/test/VFS/Inputs/public_header.h new file mode 100644 index 0000000000..471107762b --- /dev/null +++ b/test/VFS/Inputs/public_header.h @@ -0,0 +1 @@ +void from_framework(void); diff --git a/test/VFS/Inputs/unknown-key.yaml b/test/VFS/Inputs/unknown-key.yaml new file mode 100644 index 0000000000..ec7d8261d9 --- /dev/null +++ b/test/VFS/Inputs/unknown-key.yaml @@ -0,0 +1,5 @@ +{ + 'version': 0, + 'unknown-key': 'value', + 'roots': [] +} diff --git a/test/VFS/Inputs/unknown-value.yaml b/test/VFS/Inputs/unknown-value.yaml new file mode 100644 index 0000000000..4e90b2134c --- /dev/null +++ b/test/VFS/Inputs/unknown-value.yaml @@ -0,0 +1,5 @@ +{ + 'version': 0, + 'case-sensitive': 'Maybe?', + 'roots': [] +} diff --git a/test/VFS/Inputs/vfsoverlay.yaml b/test/VFS/Inputs/vfsoverlay.yaml new file mode 100644 index 0000000000..331ed33316 --- /dev/null +++ b/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/test/VFS/framework-import.m b/test/VFS/framework-import.m new file mode 100644 index 0000000000..b40bc549c0 --- /dev/null +++ b/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/test/VFS/implicit-include.c b/test/VFS/implicit-include.c new file mode 100644 index 0000000000..acf665bee2 --- /dev/null +++ b/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/test/VFS/include-mixed-real-and-virtual.c b/test/VFS/include-mixed-real-and-virtual.c new file mode 100644 index 0000000000..e1f5f952cd --- /dev/null +++ b/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/test/VFS/include-real-from-virtual.c b/test/VFS/include-real-from-virtual.c new file mode 100644 index 0000000000..65707b5516 --- /dev/null +++ b/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/test/VFS/include-virtual-from-real.c b/test/VFS/include-virtual-from-real.c new file mode 100644 index 0000000000..c8f6059608 --- /dev/null +++ b/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/test/VFS/include.c b/test/VFS/include.c new file mode 100644 index 0000000000..8cd04dd452 --- /dev/null +++ b/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/test/VFS/module-import.m b/test/VFS/module-import.m new file mode 100644 index 0000000000..80f0ea58f1 --- /dev/null +++ b/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/test/VFS/parse-errors.c b/test/VFS/parse-errors.c new file mode 100644 index 0000000000..7194efc65a --- /dev/null +++ b/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 -- 2.40.0