Skip to content

Commit

Permalink
[clang-scan-deps] reuse the file manager across invocations of
Browse files Browse the repository at this point in the history
the dependency scanner on a single worker thread

This behavior can be controlled using the new `-reuse-filemanager` clang-scan-deps
option. By default the file manager is reused.

The added test/ClangScanDeps/symlink.cpp is able to pass with
the reused filemanager after the related FileEntryRef changes
landed earlier. The test test/ClangScanDeps/subframework_header_dir_symlink.m
still fails when the file manager is reused (I run the FileCheck with not to
make it PASS). I will address this in a follow-up patch that improves
the DirectoryEntry name modelling in the FileManager.

llvm-svn: 370420
  • Loading branch information
hyp committed Aug 29, 2019
1 parent cd839cc commit 3944c96
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 8 deletions.
Expand Up @@ -34,16 +34,19 @@ enum class ScanningMode {
/// the invidual dependency scanning workers.
class DependencyScanningService {
public:
DependencyScanningService(ScanningMode Mode);
DependencyScanningService(ScanningMode Mode, bool ReuseFileManager = true);

ScanningMode getMode() const { return Mode; }

bool canReuseFileManager() const { return ReuseFileManager; }

DependencyScanningFilesystemSharedCache &getSharedCache() {
return SharedCache;
}

private:
const ScanningMode Mode;
const bool ReuseFileManager;
/// The global file system cache.
DependencyScanningFilesystemSharedCache SharedCache;
};
Expand Down
Expand Up @@ -54,6 +54,9 @@ class DependencyScanningWorker {
/// dependencies. This filesystem persists accross multiple compiler
/// invocations.
llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS;
/// The file manager that is reused accross multiple invocations by this
/// worker. If null, the file manager will not be reused.
llvm::IntrusiveRefCntPtr<FileManager> Files;
};

} // end namespace dependencies
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/Tooling/Tooling.h
Expand Up @@ -349,12 +349,15 @@ class ClangTool {
/// clang modules.
/// \param BaseFS VFS used for all underlying file accesses when running the
/// tool.
/// \param Files The file manager to use for underlying file operations when
/// running the tool.
ClangTool(const CompilationDatabase &Compilations,
ArrayRef<std::string> SourcePaths,
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
std::make_shared<PCHContainerOperations>(),
IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS =
llvm::vfs::getRealFileSystem());
llvm::vfs::getRealFileSystem(),
IntrusiveRefCntPtr<FileManager> Files = nullptr);

~ClangTool();

Expand Down
Expand Up @@ -12,5 +12,6 @@ using namespace clang;
using namespace tooling;
using namespace dependencies;

DependencyScanningService::DependencyScanningService(ScanningMode Mode)
: Mode(Mode) {}
DependencyScanningService::DependencyScanningService(ScanningMode Mode,
bool ReuseFileManager)
: Mode(Mode), ReuseFileManager(ReuseFileManager) {}
Expand Up @@ -148,6 +148,8 @@ DependencyScanningWorker::DependencyScanningWorker(
if (Service.getMode() == ScanningMode::MinimizedSourcePreprocessing)
DepFS = new DependencyScanningWorkerFilesystem(Service.getSharedCache(),
RealFS);
if (Service.canReuseFileManager())
Files = new FileManager(FileSystemOptions(), RealFS);
}

llvm::Expected<std::string>
Expand All @@ -164,7 +166,7 @@ DependencyScanningWorker::getDependencyFile(const std::string &Input,
/// Create the tool that uses the underlying file system to ensure that any
/// file system requests that are made by the driver do not go through the
/// dependency scanning filesystem.
tooling::ClangTool Tool(CDB, Input, PCHContainerOps, RealFS);
tooling::ClangTool Tool(CDB, Input, PCHContainerOps, RealFS, Files);
Tool.clearArgumentsAdjusters();
Tool.setRestoreWorkingDir(false);
Tool.setPrintErrorMessage(false);
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/Tooling/Tooling.cpp
Expand Up @@ -378,16 +378,20 @@ bool FrontendActionFactory::runInvocation(
ClangTool::ClangTool(const CompilationDatabase &Compilations,
ArrayRef<std::string> SourcePaths,
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS)
IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
IntrusiveRefCntPtr<FileManager> Files)
: Compilations(Compilations), SourcePaths(SourcePaths),
PCHContainerOps(std::move(PCHContainerOps)),
OverlayFileSystem(new llvm::vfs::OverlayFileSystem(std::move(BaseFS))),
InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
Files(new FileManager(FileSystemOptions(), OverlayFileSystem)) {
Files(Files ? Files
: new FileManager(FileSystemOptions(), OverlayFileSystem)) {
OverlayFileSystem->pushOverlay(InMemoryFileSystem);
appendArgumentsAdjuster(getClangStripOutputAdjuster());
appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster());
appendArgumentsAdjuster(getClangStripDependencyFileAdjuster());
if (Files)
Files->setVirtualFileSystem(OverlayFileSystem);
}

ClangTool::~ClangTool() = default;
Expand Down
@@ -0,0 +1,12 @@
[
{
"directory": "DIR",
"command": "clang -E DIR/subframework_header_dir_symlink.m -D EMPTY -iframework Inputs/frameworks",
"file": "DIR/subframework_header_dir_symlink.m"
},
{
"directory": "DIR",
"command": "clang -E DIR/subframework_header_dir_symlink2.m -FInputs/frameworks_symlink -iframework Inputs/frameworks",
"file": "DIR/subframework_header_dir_symlink2.m"
}
]
12 changes: 12 additions & 0 deletions clang/test/ClangScanDeps/Inputs/symlink_cdb.json
@@ -0,0 +1,12 @@
[
{
"directory": "DIR",
"command": "clang -E DIR/symlink.cpp -IInputs",
"file": "DIR/symlink.cpp"
},
{
"directory": "DIR",
"command": "clang -E DIR/symlink2.cpp -IInputs",
"file": "DIR/symlink2.cpp"
}
]
25 changes: 25 additions & 0 deletions clang/test/ClangScanDeps/subframework_header_dir_symlink.m
@@ -0,0 +1,25 @@
// REQUIRES: shell
// RUN: rm -rf %t.dir
// RUN: rm -rf %t.cdb
// RUN: mkdir -p %t.dir
// RUN: cp %s %t.dir/subframework_header_dir_symlink.m
// RUN: cp %s %t.dir/subframework_header_dir_symlink2.m
// RUN: mkdir %t.dir/Inputs
// RUN: cp -R %S/Inputs/frameworks %t.dir/Inputs/frameworks
// RUN: ln -s %t.dir/Inputs/frameworks %t.dir/Inputs/frameworks_symlink
// RUN: sed -e "s|DIR|%/t.dir|g" %S/Inputs/subframework_header_dir_symlink_cdb.json > %t.cdb
// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -reuse-filemanager=0 | \
// RUN: FileCheck %s
// FIXME: Make this work when the filemanager is reused:
// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -reuse-filemanager=1 | \
// RUN: not FileCheck %s

#ifndef EMPTY
#include "Framework/Framework.h"
#endif

// CHECK: clang-scan-deps dependency
// CHECK-NEXT: subframework_header_dir_symlink.m
// CHECK: clang-scan-deps dependency
// CHECK-NEXT: subframework_header_dir_symlink.m
// CHECK-NEXT: Inputs{{/|\\}}frameworks_symlink{{/|\\}}Framework.framework{{/|\\}}Headers{{/|\\}}Framework.h
23 changes: 23 additions & 0 deletions clang/test/ClangScanDeps/symlink.cpp
@@ -0,0 +1,23 @@
// REQUIRES: shell
// RUN: rm -rf %t.dir
// RUN: rm -rf %t.cdb
// RUN: mkdir -p %t.dir
// RUN: cp %s %t.dir/symlink.cpp
// RUN: cp %s %t.dir/symlink2.cpp
// RUN: mkdir %t.dir/Inputs
// RUN: cp %S/Inputs/header.h %t.dir/Inputs/header.h
// RUN: ln -s %t.dir/Inputs/header.h %t.dir/Inputs/symlink.h
// RUN: sed -e "s|DIR|%/t.dir|g" %S/Inputs/symlink_cdb.json > %t.cdb
// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -reuse-filemanager=0 | FileCheck %s
// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -reuse-filemanager=1 | FileCheck %s

#include "symlink.h"
#include "header.h"

// CHECK: symlink.cpp
// CHECK-NEXT: Inputs{{/|\\}}symlink.h
// CHECK-NEXT: Inputs{{/|\\}}header.h

// CHECK: symlink2.cpp
// CHECK-NEXT: Inputs{{/|\\}}symlink.h
// CHECK-NEXT: Inputs{{/|\\}}header.h
7 changes: 6 additions & 1 deletion clang/tools/clang-scan-deps/ClangScanDeps.cpp
Expand Up @@ -107,6 +107,11 @@ llvm::cl::opt<std::string>
llvm::cl::desc("Compilation database"), llvm::cl::Required,
llvm::cl::cat(DependencyScannerCategory));

llvm::cl::opt<bool> ReuseFileManager(
"reuse-filemanager",
llvm::cl::desc("Reuse the file manager and its cache between invocations."),
llvm::cl::init(true), llvm::cl::cat(DependencyScannerCategory));

} // end anonymous namespace

int main(int argc, const char **argv) {
Expand Down Expand Up @@ -153,7 +158,7 @@ int main(int argc, const char **argv) {
// Print out the dependency results to STDOUT by default.
SharedStream DependencyOS(llvm::outs());

DependencyScanningService Service(ScanMode);
DependencyScanningService Service(ScanMode, ReuseFileManager);
#if LLVM_ENABLE_THREADS
unsigned NumWorkers =
NumThreads == 0 ? llvm::hardware_concurrency() : NumThreads;
Expand Down

0 comments on commit 3944c96

Please sign in to comment.