Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,17 @@ class DependencyScanningTool {
/// \param LookupModuleOutput This function is called to fill in
/// "-fmodule-file=", "-o" and other output
/// arguments for dependencies.
/// \param TUBuffer Optional memory buffer for translation unit input. If
/// TUBuffer is nullopt, the input should be included in the
/// Commandline already.
/// \param OverlayFS An optional VFS that overlays on top of WorkerFS to
/// provide additional virtual files to the scanning of the
/// translation unit.
///
/// \returns a \c StringError with the diagnostic output if clang errors
/// occurred, \c TranslationUnitDeps otherwise.
llvm::Expected<TranslationUnitDeps> getTranslationUnitDependencies(
const std::vector<std::string> &CommandLine, StringRef CWD,
const llvm::DenseSet<ModuleID> &AlreadySeen,
LookupModuleOutputCallback LookupModuleOutput,
std::optional<llvm::MemoryBufferRef> TUBuffer = std::nullopt);
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS = nullptr);

/// Given a compilation context specified via the Clang driver command-line,
/// gather modular dependencies of module with the given name, and return the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,18 +90,17 @@ class DependencyScanningWorker {
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS);

/// Run the dependency scanning tool for a given clang driver command-line,
/// and report the discovered dependencies to the provided consumer. If
/// TUBuffer is not nullopt, it is used as TU input for the dependency
/// scanning. Otherwise, the input should be included as part of the
/// command-line.
/// and report the discovered dependencies to the provided consumer. An
/// additional OverlayFS can be provided to add additional virtual files to
/// the dependency scanning.
///
/// \returns false if clang errors occurred (with diagnostics reported to
/// \c DiagConsumer), true otherwise.
bool computeDependencies(
StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
DependencyConsumer &DepConsumer, DependencyActionController &Controller,
DiagnosticConsumer &DiagConsumer,
std::optional<llvm::MemoryBufferRef> TUBuffer = std::nullopt);
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS = nullptr);

/// Run the dependency scanning tool for a given clang driver command-line
/// for a specific module.
Expand All @@ -123,7 +122,7 @@ class DependencyScanningWorker {
llvm::Error computeDependencies(
StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
DependencyConsumer &Consumer, DependencyActionController &Controller,
std::optional<llvm::MemoryBufferRef> TUBuffer = std::nullopt);
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS = nullptr);

/// Run the dependency scanning tool for a given clang driver command-line
/// for a specific module.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,11 @@ DependencyScanningTool::getTranslationUnitDependencies(
const std::vector<std::string> &CommandLine, StringRef CWD,
const llvm::DenseSet<ModuleID> &AlreadySeen,
LookupModuleOutputCallback LookupModuleOutput,
std::optional<llvm::MemoryBufferRef> TUBuffer) {
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS) {
FullDependencyConsumer Consumer(AlreadySeen);
CallbackActionController Controller(LookupModuleOutput);
llvm::Error Result = Worker.computeDependencies(CWD, CommandLine, Consumer,
Controller, TUBuffer);
llvm::Error Result = Worker.computeDependencies(
CWD, CommandLine, Consumer, Controller, std::move(OverlayFS));

if (Result)
return std::move(Result);
Expand Down
41 changes: 13 additions & 28 deletions clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ createDiagOptions(const std::vector<std::string> &CommandLine) {
llvm::Error DependencyScanningWorker::computeDependencies(
StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
DependencyConsumer &Consumer, DependencyActionController &Controller,
std::optional<llvm::MemoryBufferRef> TUBuffer) {
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS) {
// Capture the emitted diagnostics and report them to the client
// in the case of a failure.
std::string DiagnosticOutput;
Expand All @@ -636,7 +636,7 @@ llvm::Error DependencyScanningWorker::computeDependencies(
TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, *DiagOpts);

if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
DiagPrinter, TUBuffer))
DiagPrinter, std::move(OverlayFS)))
return llvm::Error::success();
return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(),
llvm::inconvertibleErrorCode());
Expand Down Expand Up @@ -788,41 +788,26 @@ bool DependencyScanningWorker::scanDependencies(
bool DependencyScanningWorker::computeDependencies(
StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
DependencyConsumer &Consumer, DependencyActionController &Controller,
DiagnosticConsumer &DC, std::optional<llvm::MemoryBufferRef> TUBuffer) {
DiagnosticConsumer &DC,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS) {
// Reset what might have been modified in the previous worker invocation.
BaseFS->setCurrentWorkingDirectory(WorkingDirectory);

std::optional<std::vector<std::string>> ModifiedCommandLine;
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> ModifiedFS;

// If we're scanning based on a module name alone, we don't expect the client
// to provide us with an input file. However, the driver really wants to have
// one. Let's just make it up to make the driver happy.
if (TUBuffer) {
auto OverlayFS =
// If an OverlayFS is provided, create a new FS that has the overlay on the
// top layer.
if (OverlayFS) {
auto NewFS =
llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
auto InMemoryFS =
llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
auto InputPath = TUBuffer->getBufferIdentifier();
InMemoryFS->addFile(
InputPath, 0,
llvm::MemoryBuffer::getMemBufferCopy(TUBuffer->getBuffer()));
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay =
InMemoryFS;

OverlayFS->pushOverlay(InMemoryOverlay);
ModifiedFS = OverlayFS;
ModifiedCommandLine = CommandLine;
ModifiedCommandLine->emplace_back(InputPath);
NewFS->pushOverlay(std::move(OverlayFS));
NewFS->setCurrentWorkingDirectory(WorkingDirectory);
ModifiedFS = NewFS;
}

const std::vector<std::string> &FinalCommandLine =
ModifiedCommandLine ? *ModifiedCommandLine : CommandLine;
auto &FinalFS = ModifiedFS ? ModifiedFS : BaseFS;

return scanDependencies(WorkingDirectory, FinalCommandLine, Consumer,
Controller, DC, FinalFS, /*ModuleName=*/std::nullopt);
return scanDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
DC, FinalFS, /*ModuleName=*/std::nullopt);
}

bool DependencyScanningWorker::computeDependencies(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,72 @@ module addition { header "addition.h" }
//--- addition.h
// empty

//--- tu.c
//--- hidden/tu.c
#include "root.h"

//--- hidden/additional.h
#include "addition.h"

//--- root/textual.h
// This is here to verify that the "root" directory doesn't clash with name of
// the "root" module.

//--- cdb.json.template
[{
"file": "",
"file": "DIR/test.c",
"directory": "DIR",
"command": "clang -fmodules -fmodules-cache-path=DIR/cache -I DIR -x c -c"
"command": "clang -fmodules -fmodules-cache-path=DIR/cache -I DIR -x c DIR/test.c -c"
}]

//--- cdb2.json.template
[{
"file": "DIR/test.c",
"directory": "DIR",
"command": "clang -fmodules -fmodules-cache-path=DIR/cache -include DIR/pre.h -I DIR -x c DIR/test.c -c"
}]

//--- vfs.yaml.template
{
'version': 0,
'roots': [
{ 'name': 'DIR', 'type': 'directory',
'contents': [
{ 'name': 'test.c', 'type': 'file',
'use-external-name': false,
'external-contents': 'DIR/hidden/tu.c'
},
{ 'name': 'pre.h', 'type': 'file',
'use-external-name': false,
'external-contents': 'DIR/hidden/additional.h'
},
]
}
]
}

// RUN: sed "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json
// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full -tu-buffer-path %t/tu.c > %t/result.json
// RUN: sed "s|DIR|%/t|g" %t/vfs.yaml.template > %t/vfs.yaml
// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full -vfs-overlay-path %t/vfs.yaml > %t/result.json
// RUN: cat %t/result.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s --check-prefix=CHECK

// RUN: sed "s|DIR|%/t|g" %t/cdb2.json.template > %t/cdb2.json
// RUN: clang-scan-deps -compilation-database %t/cdb2.json -format experimental-full -vfs-overlay-path %t/vfs.yaml > %t/result2.json
// RUN: cat %t/result2.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s --check-prefix=CHECK --check-prefix=ADDITION

// CHECK: {
// CHECK-NEXT: "modules": [
// ADDITION-NEXT: {
// ADDITION-NEXT: "clang-module-deps": [],
// ADDITION-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
// ADDITION-NEXT: "command-line": [
// ADDITION: ],
// ADDITION-NEXT: "context-hash": "{{.*}}",
// ADDITION-NEXT: "file-deps": [
// ADDITION-NEXT: "[[PREFIX]]/module.modulemap"
// ADDITION-NEXT: "[[PREFIX]]/addition.h"
// ADDITION-NEXT: ],
// ADDITION: "name": "addition"
// ADDITION-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: {
Expand Down Expand Up @@ -93,6 +139,10 @@ module addition { header "addition.h" }
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash": "{{.*}}",
// CHECK-NEXT: "clang-module-deps": [
// ADDITION-NEXT: {
// ADDITION-NEXT: "context-hash": "{{.*}}",
// ADDITION-NEXT: "module-name": "addition"
// ADDITION-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "{{.*}}",
// CHECK-NEXT: "module-name": "root"
Expand All @@ -101,9 +151,10 @@ module addition { header "addition.h" }
// CHECK-NEXT: "command-line": [
// CHECK: ],
// CHECK: "file-deps": [
// CHECK-NEXT: [[PREFIX]]/tu.c
// CHECK-NEXT: [[PREFIX]]/test.c
// ADDITION-NEXT: [[PREFIX]]/pre.h
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/tu.c"
// CHECK-NEXT: "input-file": "[[PREFIX]]/test.c"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
Expand Down
29 changes: 14 additions & 15 deletions clang/tools/clang-scan-deps/ClangScanDeps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ static unsigned NumThreads = 0;
static std::string CompilationDB;
static std::optional<std::string> ModuleName;
static std::vector<std::string> ModuleDepTargets;
static std::string TranslationUnitFile;
static std::string VFSOverlayFile;
static bool DeprecatedDriverCommand;
static ResourceDirRecipeKind ResourceDirRecipe;
static bool Verbose;
Expand Down Expand Up @@ -210,8 +210,8 @@ static void ParseArgs(int argc, char **argv) {
for (const llvm::opt::Arg *A : Args.filtered(OPT_dependency_target_EQ))
ModuleDepTargets.emplace_back(A->getValue());

if (const llvm::opt::Arg *A = Args.getLastArg(OPT_tu_buffer_path_EQ))
TranslationUnitFile = A->getValue();
if (const llvm::opt::Arg *A = Args.getLastArg(OPT_vfs_overlay_path_EQ))
VFSOverlayFile = A->getValue();

DeprecatedDriverCommand = Args.hasArg(OPT_deprecated_driver_command);

Expand Down Expand Up @@ -1082,24 +1082,23 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) {
LocalIndex, DependencyOS, Errs))
HadErrors = true;
} else {
std::unique_ptr<llvm::MemoryBuffer> TU;
std::optional<llvm::MemoryBufferRef> TUBuffer;
if (!TranslationUnitFile.empty()) {
auto MaybeTU =
llvm::MemoryBuffer::getFile(TranslationUnitFile, /*IsText=*/true);
if (!MaybeTU) {
llvm::errs() << "cannot open input translation unit: "
<< MaybeTU.getError().message() << "\n";
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> OverlayFS;
if (!VFSOverlayFile.empty()) {
auto YAMLFile =
llvm::MemoryBuffer::getFile(VFSOverlayFile, /*IsText=*/true);
if (!YAMLFile) {
llvm::errs() << "cannot open vfs overlay yaml: "
<< YAMLFile.getError().message() << "\n";
HadErrors = true;
continue;
}
TU = std::move(*MaybeTU);
TUBuffer = TU->getMemBufferRef();
Filename = TU->getBufferIdentifier();
OverlayFS = llvm::vfs::RedirectingFileSystem::create(
std::move(*YAMLFile), nullptr, "", nullptr,
llvm::vfs::getRealFileSystem());
}
auto MaybeTUDeps = WorkerTool.getTranslationUnitDependencies(
Input->CommandLine, CWD, AlreadySeenModules, LookupOutput,
TUBuffer);
OverlayFS);
if (handleTranslationUnitResult(Filename, MaybeTUDeps, *FD, LocalIndex,
DependencyOS, Errs))
HadErrors = true;
Expand Down
2 changes: 1 addition & 1 deletion clang/tools/clang-scan-deps/Opts.td
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ defm compilation_database : Eq<"compilation-database", "Compilation database">;
defm module_name : Eq<"module-name", "the module of which the dependencies are to be computed">;
defm dependency_target : Eq<"dependency-target", "The names of dependency targets for the dependency file">;

defm tu_buffer_path: Eq<"tu-buffer-path", "The path to the translation unit for depscan. Not compatible with -module-name">;
defm vfs_overlay_path: Eq<"vfs-overlay-path", "The path to a VFS overlay file that is used to scan the translation unit. Not compatible with -module-name">;

def deprecated_driver_command : F<"deprecated-driver-command", "use a single driver command to build the tu (deprecated)">;

Expand Down