Index: include/clang/Basic/DiagnosticFrontendKinds.td =================================================================== --- include/clang/Basic/DiagnosticFrontendKinds.td +++ include/clang/Basic/DiagnosticFrontendKinds.td @@ -231,6 +231,8 @@ "virtual filesystem overlay file '%0' not found">, DefaultFatal; def err_invalid_vfs_overlay : Error< "invalid virtual filesystem overlay file '%0'">, DefaultFatal; +def err_unable_to_load_vfs_overlay : Error< + "unable to load virtual filesystem overlay '%0': %1">, DefaultFatal; def warn_option_invalid_ocl_version : Warning< "OpenCL version %0 does not support the option '%1'">, InGroup; Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -1828,6 +1828,8 @@ Flags<[CC1Option]>; def ivfsoverlay : JoinedOrSeparate<["-"], "ivfsoverlay">, Group, Flags<[CC1Option]>, HelpText<"Overlay the virtual filesystem described by file over the real file system">; +def ivfsoverlay_lib : JoinedOrSeparate<["-"], "ivfsoverlay-lib">, Group, Flags<[CC1Option]>, + HelpText<"Load the virtual filesystem from shared library">; def imultilib : Separate<["-"], "imultilib">, Group; def keep__private__externs : Flag<["-"], "keep_private_externs">; def l : JoinedOrSeparate<["-"], "l">, Flags<[LinkerInput, RenderJoined]>, Index: include/clang/Lex/HeaderSearchOptions.h =================================================================== --- include/clang/Lex/HeaderSearchOptions.h +++ include/clang/Lex/HeaderSearchOptions.h @@ -173,6 +173,9 @@ /// The set of user-provided virtual filesystem overlay files. std::vector VFSOverlayFiles; + /// The set of libraries with user-provided virtual filesystem. + std::vector VFSOverlayLibs; + /// Include the compiler builtin includes. unsigned UseBuiltinIncludes : 1; @@ -229,6 +232,10 @@ VFSOverlayFiles.push_back(Name); } + void AddVFSOverlayLib(StringRef Name) { + VFSOverlayLibs.push_back(Name); + } + void AddPrebuiltModulePath(StringRef Name) { PrebuiltModulePaths.push_back(Name); } Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -66,6 +66,7 @@ #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" @@ -1841,6 +1842,9 @@ for (const auto *A : Args.filtered(OPT_ivfsoverlay)) Opts.AddVFSOverlayFile(A->getValue()); + + for (const Arg *A : Args.filtered(OPT_ivfsoverlay_lib)) + Opts.AddVFSOverlayLib(A->getValue()); } void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, @@ -3180,11 +3184,14 @@ return createVFSFromCompilerInvocation(CI, Diags, vfs::getRealFileSystem()); } +typedef vfs::FileSystem *(*CreateLibraryFileSystem)(void); + IntrusiveRefCntPtr createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags, IntrusiveRefCntPtr BaseFS) { - if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty()) + if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty() && + CI.getHeaderSearchOpts().VFSOverlayLibs.empty()) return BaseFS; IntrusiveRefCntPtr Overlay( @@ -3205,6 +3212,34 @@ else Diags.Report(diag::err_invalid_vfs_overlay) << File; } + + // Load shared libraries that provide a VFS. + for (const std::string &LibFile : CI.getHeaderSearchOpts().VFSOverlayLibs) { + std::string Error; + auto Lib = llvm::sys::DynamicLibrary::getPermanentLibrary( + LibFile.c_str(), &Error); + if (!Lib.isValid()) { + Diags.Report(diag::err_unable_to_load_vfs_overlay) << LibFile << Error; + continue; + } + + auto *CreateFS = (CreateLibraryFileSystem) (intptr_t) + Lib.getAddressOfSymbol("__clang_create_vfs"); + + if (!CreateFS) { + Diags.Report(diag::err_unable_to_load_vfs_overlay) + << LibFile << "'__clang_create_vfs' function was not found"; + continue; + } + + IntrusiveRefCntPtr FS = CreateFS(); + if (!FS.get()) { + Diags.Report(diag::err_invalid_vfs_overlay) << LibFile; + continue; + } + + Overlay->pushOverlay(FS); + } return Overlay; } Index: unittests/Frontend/CMakeLists.txt =================================================================== --- unittests/Frontend/CMakeLists.txt +++ unittests/Frontend/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_LINK_COMPONENTS Support ) +list(APPEND LLVM_OPTIONAL_SOURCES VfsTestLib.cpp) add_clang_unittest(FrontendTests ASTUnitTest.cpp @@ -21,3 +22,15 @@ clangCodeGen clangFrontendTool ) + +add_library(VfsTestLib SHARED VfsTestLib.cpp) +target_link_libraries(VfsTestLib clangBasic) +set_target_properties(VfsTestLib + PROPERTIES PREFIX "" + SUFFIX ${LTDL_SHLIB_EXT} + ) +set(outdir ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}) +set_output_directory(VfsTestLib BINARY_DIR ${outdir} LIBRARY_DIR ${outdir}) +get_target_property(test_suite_folder FrontendTests FOLDER) +set_property(TARGET VfsTestLib PROPERTY FOLDER "${test_suite_folder}") +add_dependencies(FrontendTests VfsTestLib) Index: unittests/Frontend/CompilerInstanceTest.cpp =================================================================== --- unittests/Frontend/CompilerInstanceTest.cpp +++ unittests/Frontend/CompilerInstanceTest.cpp @@ -9,8 +9,10 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" +#include "llvm/Config/config.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" +#include "llvm/Support/Path.h" #include "llvm/Support/ToolOutputFile.h" #include "gtest/gtest.h" @@ -71,4 +73,37 @@ ASSERT_TRUE(Instance.getFileManager().getFile("vfs-virtual.file")); } +static std::string LibPath(const std::string Name = "VfsTestLib") { + const std::vector &Argvs = + testing::internal::GetArgvs(); + const char *Argv0 = Argvs.size() > 0 ? Argvs[0].c_str() : "FrontendTests"; + llvm::SmallString<256> Buf(llvm::sys::path::parent_path(Argv0)); + llvm::sys::path::append(Buf, (Name + LTDL_SHLIB_EXT).c_str()); + return Buf.str(); +} + +TEST(CompilerInstance, VFSOverlayLibrary) { + // Create a CompilerInvocation that uses this overlay library. + const std::string VFSArg = "-ivfsoverlay-lib" + LibPath(); + const char *Args[] = {"clang", VFSArg.c_str(), "-xc", "-"}; + + IntrusiveRefCntPtr Diags = + CompilerInstance::createDiagnostics(new DiagnosticOptions()); + + std::shared_ptr CInvok = + createInvocationFromCommandLine(Args, Diags); + + if (!CInvok) + FAIL() << "could not create compiler invocation"; + + CompilerInstance Instance; + Instance.setDiagnostics(Diags.get()); + Instance.setInvocation(CInvok); + Instance.createFileManager(); + + // Check if the virtual file exists which means that our VFS is used by the + // CompilerInstance. + ASSERT_TRUE(Instance.getFileManager().getFile("virtual.file")); +} + } // anonymous namespace Index: unittests/Frontend/VfsTestLib.cpp =================================================================== --- /dev/null +++ unittests/Frontend/VfsTestLib.cpp @@ -0,0 +1,30 @@ +//===- unittests/Frontend/VfsTestLib.cpp - CI tests -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/VirtualFileSystem.h" +#include "llvm/ADT/SmallString.h" + +#ifdef _WIN32 +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + +extern "C" EXPORT clang::vfs::FileSystem *__clang_create_vfs() { + auto *FS = new clang::vfs::InMemoryFileSystem(); + + llvm::SmallString<128> FileName("virtual.file"); + std::error_code EC = llvm::sys::fs::make_absolute(FileName); + if (EC) + return nullptr; + + FS->addFile(FileName, (time_t)0, llvm::MemoryBuffer::getMemBuffer("foobar")); + + return FS; +}