///
/// \param Compilations The reference to the compilation database that's
/// used by the clang tool.
- DependencyScanningTool(
- DependencyScanningService &Service,
- const clang::tooling::CompilationDatabase &Compilations);
+ DependencyScanningTool(DependencyScanningService &Service);
/// Print out the dependency information into a string using the dependency
/// file format that is specified in the options (-MD is the default) and
///
/// \returns A \c StringError with the diagnostic output if clang errors
/// occurred, dependency file contents otherwise.
- llvm::Expected<std::string> getDependencyFile(const std::string &Input,
- StringRef CWD);
+ llvm::Expected<std::string>
+ getDependencyFile(const tooling::CompilationDatabase &Compilations,
+ StringRef CWD);
private:
const ScanningOutputFormat Format;
DependencyScanningWorker Worker;
- const tooling::CompilationDatabase &Compilations;
};
} // end namespace dependencies
namespace dependencies{
DependencyScanningTool::DependencyScanningTool(
- DependencyScanningService &Service,
- const tooling::CompilationDatabase &Compilations)
- : Format(Service.getFormat()), Worker(Service), Compilations(Compilations) {
+ DependencyScanningService &Service)
+ : Format(Service.getFormat()), Worker(Service) {
}
-llvm::Expected<std::string>
-DependencyScanningTool::getDependencyFile(const std::string &Input,
- StringRef CWD) {
+llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
+ const tooling::CompilationDatabase &Compilations, StringRef CWD) {
/// Prints out all of the gathered dependencies into a string.
class MakeDependencyPrinterConsumer : public DependencyConsumer {
public:
std::string ContextHash;
};
+
+ // We expect a single command here because if a source file occurs multiple
+ // times in the original CDB, then `computeDependencies` would run the
+ // `DependencyScanningAction` once for every time the input occured in the
+ // CDB. Instead we split up the CDB into single command chunks to avoid this
+ // behavior.
+ assert(Compilations.getAllCompileCommands().size() == 1 &&
+ "Expected a compilation database with a single command!");
+ std::string Input = Compilations.getAllCompileCommands().front().Filename;
+
if (Format == ScanningOutputFormat::Make) {
MakeDependencyPrinterConsumer Consumer;
auto Result =
"directory": "DIR",
"command": "clang -E DIR/regular_cdb_input.cpp -IInputs",
"file": "DIR/regular_cdb_input.cpp"
+},
+{
+ "directory": "DIR",
+ "command": "clang -E DIR/regular_cdb_input.cpp -IInputs -o adena.o",
+ "file": "DIR/regular_cdb_input.cpp"
}
]
// CHECK-NEXT: fatal error: 'missing.h' file not found
// CHECK-NEXT: "missing.h"
// CHECK-NEXT: ^
+// CHECK-NEXT: Error while scanning dependencies
+// CHECK-NEXT: fatal error: 'missing.h' file not found
+// CHECK-NEXT: "missing.h"
+// CHECK-NEXT: ^
// CHECK-NEXT: EOF
// RUN: sed -e "s|DIR|%/t.dir|g" %S/Inputs/regular_cdb.json > %t.cdb
//
// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -mode preprocess-minimized-sources | \
-// RUN: FileCheck --check-prefixes=CHECK1,CHECK2,CHECK2NO %s
+// RUN: FileCheck --check-prefixes=CHECK1,CHECK2,CHECK2NO,CHECK3 %s
// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -mode preprocess | \
-// RUN: FileCheck --check-prefixes=CHECK1,CHECK2,CHECK2NO %s
+// RUN: FileCheck --check-prefixes=CHECK1,CHECK2,CHECK2NO,CHECK3 %s
// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -mode preprocess-minimized-sources \
-// RUN: -skip-excluded-pp-ranges=0 | FileCheck --check-prefixes=CHECK1,CHECK2,CHECK2NO %s
+// RUN: -skip-excluded-pp-ranges=0 | FileCheck --check-prefixes=CHECK1,CHECK2,CHECK2NO,CHECK3 %s
//
// Make sure we didn't produce any dependency files!
// RUN: not cat %t.dir/regular_cdb.d
// CHECK1-NEXT: Inputs{{/|\\}}header.h
// CHECK1-NEXT: Inputs{{/|\\}}header2.h
+// CHECK3: regular_cdb_input.o
// CHECK2: regular_cdb_input.cpp
// CHECK2-NEXT: Inputs{{/|\\}}header.h
// CHECK2NO-NOT: header2
+
+// CHECK3: adena.o
return ObjFileName.str();
}
+class SingleCommandCompilationDatabase : public tooling::CompilationDatabase {
+public:
+ SingleCommandCompilationDatabase(tooling::CompileCommand Cmd)
+ : Command(std::move(Cmd)) {}
+
+ virtual std::vector<tooling::CompileCommand>
+ getCompileCommands(StringRef FilePath) const {
+ return {Command};
+ }
+
+ virtual std::vector<tooling::CompileCommand> getAllCompileCommands() const {
+ return {Command};
+ }
+
+private:
+ tooling::CompileCommand Command;
+};
+
/// Takes the result of a dependency scan and prints error / dependency files
/// based on the result.
///
llvm::cl::PrintOptionValues();
- // By default the tool runs on all inputs in the CDB.
- std::vector<std::pair<std::string, std::string>> Inputs;
- for (const auto &Command : Compilations->getAllCompileCommands())
- Inputs.emplace_back(Command.Filename, Command.Directory);
-
// The command options are rewritten to run Clang in preprocessor only mode.
auto AdjustingCompilations =
std::make_unique<tooling::ArgumentsAdjustingCompilations>(
#endif
std::vector<std::unique_ptr<DependencyScanningTool>> WorkerTools;
for (unsigned I = 0; I < NumWorkers; ++I)
- WorkerTools.push_back(std::make_unique<DependencyScanningTool>(
- Service, *AdjustingCompilations));
+ WorkerTools.push_back(std::make_unique<DependencyScanningTool>(Service));
+
+ std::vector<SingleCommandCompilationDatabase> Inputs;
+ for (tooling::CompileCommand Cmd :
+ AdjustingCompilations->getAllCompileCommands())
+ Inputs.emplace_back(Cmd);
std::vector<std::thread> WorkerThreads;
std::atomic<bool> HadErrors(false);
auto Worker = [I, &Lock, &Index, &Inputs, &HadErrors, &WorkerTools,
&DependencyOS, &Errs]() {
while (true) {
- std::string Input;
- StringRef CWD;
+ const SingleCommandCompilationDatabase *Input;
+ std::string Filename;
+ std::string CWD;
// Take the next input.
{
std::unique_lock<std::mutex> LockGuard(Lock);
if (Index >= Inputs.size())
return;
- const auto &Compilation = Inputs[Index++];
- Input = Compilation.first;
- CWD = Compilation.second;
+ Input = &Inputs[Index++];
+ tooling::CompileCommand Cmd = Input->getAllCompileCommands()[0];
+ Filename = std::move(Cmd.Filename);
+ CWD = std::move(Cmd.Directory);
}
// Run the tool on it.
- auto MaybeFile = WorkerTools[I]->getDependencyFile(Input, CWD);
- if (handleDependencyToolResult(Input, MaybeFile, DependencyOS, Errs))
+ auto MaybeFile = WorkerTools[I]->getDependencyFile(*Input, CWD);
+ if (handleDependencyToolResult(Filename, MaybeFile, DependencyOS, Errs))
HadErrors = true;
}
};