--- /dev/null
+//===- MakeSupport.h - Make Utilities ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_MAKESUPPORT_H
+#define LLVM_CLANG_BASIC_MAKESUPPORT_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+
+/// Quote target names for inclusion in GNU Make dependency files.
+/// Only the characters '$', '#', ' ', '\t' are quoted.
+void quoteMakeTarget(StringRef Target, SmallVectorImpl<char> &Res);
+
+} // namespace clang
+
+#endif // LLVM_CLANG_BASIC_MAKESUPPORT_H
/// The path of the dependency file (.d), if any.
DependencyFile,
/// The null-separated list of names to use as the targets in the dependency
- /// file, if any.
+ /// file, if any. Defaults to the value of \c ModuleFile, as in the driver.
DependencyTargets,
/// The path of the serialized diagnostic file (.dia), if any.
DiagnosticSerializationFile,
IdentifierTable.cpp
LangOptions.cpp
LangStandards.cpp
+ MakeSupport.cpp
Module.cpp
ObjCRuntime.cpp
OpenCLOptions.cpp
--- /dev/null
+//===-- MakeSuport.cpp --------------------------------------------------*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/MakeSupport.h"
+
+void clang::quoteMakeTarget(StringRef Target, SmallVectorImpl<char> &Res) {
+ for (unsigned i = 0, e = Target.size(); i != e; ++i) {
+ switch (Target[i]) {
+ case ' ':
+ case '\t':
+ // Escape the preceding backslashes
+ for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j)
+ Res.push_back('\\');
+
+ // Escape the space/tab
+ Res.push_back('\\');
+ break;
+ case '$':
+ Res.push_back('$');
+ break;
+ case '#':
+ Res.push_back('\\');
+ break;
+ default:
+ break;
+ }
+
+ Res.push_back(Target[i]);
+ }
+}
\ No newline at end of file
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/MakeSupport.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/Version.h"
#include "clang/Config/config.h"
}
}
-// Quote target names for inclusion in GNU Make dependency files.
-// Only the characters '$', '#', ' ', '\t' are quoted.
-static void QuoteTarget(StringRef Target, SmallVectorImpl<char> &Res) {
- for (unsigned i = 0, e = Target.size(); i != e; ++i) {
- switch (Target[i]) {
- case ' ':
- case '\t':
- // Escape the preceding backslashes
- for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j)
- Res.push_back('\\');
-
- // Escape the space/tab
- Res.push_back('\\');
- break;
- case '$':
- Res.push_back('$');
- break;
- case '#':
- Res.push_back('\\');
- break;
- default:
- break;
- }
-
- Res.push_back(Target[i]);
- }
-}
-
/// Apply \a Work on the current tool chain \a RegularToolChain and any other
/// offloading tool chain that is associated with the current action \a JA.
static void
} else {
CmdArgs.push_back("-MT");
SmallString<128> Quoted;
- QuoteTarget(A->getValue(), Quoted);
+ quoteMakeTarget(A->getValue(), Quoted);
CmdArgs.push_back(Args.MakeArgString(Quoted));
}
}
CmdArgs.push_back("-MT");
SmallString<128> Quoted;
- QuoteTarget(DepTarget, Quoted);
+ quoteMakeTarget(DepTarget, Quoted);
CmdArgs.push_back(Args.MakeArgString(Quoted));
}
#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
+#include "clang/Basic/MakeSupport.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
static std::vector<std::string> splitString(std::string S, char Separator) {
SmallVector<StringRef> Segments;
- StringRef(S).split(Segments, Separator);
+ StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, /*KeepEmpty=*/false);
std::vector<std::string> Result;
Result.reserve(Segments.size());
for (StringRef Segment : Segments)
CI.getDiagnosticOpts().DiagnosticSerializationFile =
LookupModuleOutput(ID, ModuleOutputKind::DiagnosticSerializationFile);
if (HadDependencyFile) {
- CI.getDependencyOutputOpts().OutputFile =
+ DependencyOutputOptions &DepOpts = CI.getDependencyOutputOpts();
+ DepOpts.OutputFile =
LookupModuleOutput(ID, ModuleOutputKind::DependencyFile);
- CI.getDependencyOutputOpts().Targets = splitString(
+ DepOpts.Targets = splitString(
LookupModuleOutput(ID, ModuleOutputKind::DependencyTargets), '\0');
+ if (!DepOpts.OutputFile.empty() && DepOpts.Targets.empty()) {
+ // Fallback to -o as dependency target, as in the driver.
+ SmallString<128> Target;
+ quoteMakeTarget(FrontendOpts.OutputFile, Target);
+ DepOpts.Targets.push_back(std::string(Target));
+ }
}
for (ModuleID MID : ClangModuleDeps)
// RUN: clang-scan-deps -compilation-database %t/cdb.json \
// RUN: -format experimental-full -generate-modules-path-args > %t/deps.json
// RUN: cat %t/deps.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s
+// RUN: clang-scan-deps -compilation-database %t/cdb.json \
+// RUN: -format experimental-full -generate-modules-path-args -dependency-target foo > %t/deps_mt1.json
+// RUN: cat %t/deps_mt1.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s -check-prefix=DEPS_MT1
+// RUN: clang-scan-deps -compilation-database %t/cdb.json \
+// RUN: -format experimental-full -generate-modules-path-args -dependency-target foo -dependency-target bar > %t/deps_mt2.json
+// RUN: cat %t/deps_mt2.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s -check-prefix=DEPS_MT2
// RUN: clang-scan-deps -compilation-database %t/cdb_without.json \
// RUN: -format experimental-full -generate-modules-path-args > %t/deps_without.json
// RUN: cat %t/deps_without.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t -check-prefix=WITHOUT %s
// CHECK-NEXT: "-cc1"
// CHECK: "-serialize-diagnostic-file"
// CHECK-NEXT: "[[PREFIX]]{{.*}}Mod{{.*}}.diag"
+// CHECK: "-MT"
+// CHECK-NEXT: "[[PREFIX]]{{.*}}Mod{{.*}}.pcm"
// CHECK: "-dependency-file"
// CHECK-NEXT: "[[PREFIX]]{{.*}}Mod{{.*}}.d"
// CHECK: ],
+// DEPS_MT1: "-MT"
+// DEPS_MT1-NEXT: "foo"
+
+// DEPS_MT2: "-MT"
+// DEPS_MT2-NEXT: "foo"
+// DEPS_MT2-NEXT: "-MT"
+// DEPS_MT2-NEXT: "bar"
+
// WITHOUT: {
// WITHOUT-NEXT: "modules": [
// WITHOUT-NEXT: {
// WITHOUT-NEXT: "-cc1"
// WITHOUT-NOT: "-serialize-diagnostic-file"
// WITHOUT-NOT: "-dependency-file"
+// WITHOUT-NOT: "-MT"
// WITHOUT: ],
//--- cdb.json.template
llvm::cl::desc("the module of which the dependencies are to be computed"),
llvm::cl::cat(DependencyScannerCategory));
+llvm::cl::list<std::string> ModuleDepTargets(
+ "dependency-target",
+ llvm::cl::desc("With '-generate-modules-path-args', the names of "
+ "dependency targets for the dependency file"),
+ llvm::cl::cat(DependencyScannerCategory));
+
enum ResourceDirRecipeKind {
RDRK_ModifyCompilerPath,
RDRK_InvokeCompiler,
case ModuleOutputKind::DependencyFile:
return PCMPath.first->second + ".d";
case ModuleOutputKind::DependencyTargets:
- return ""; // Will get the default target name.
+ // Null-separate the list of targets.
+ return join(ModuleDepTargets, StringRef("\0", 1));
case ModuleOutputKind::DiagnosticSerializationFile:
return PCMPath.first->second + ".diag";
}