diff --git a/clang/include/clang/Basic/MakeSupport.h b/clang/include/clang/Basic/MakeSupport.h new file mode 100644 --- /dev/null +++ b/clang/include/clang/Basic/MakeSupport.h @@ -0,0 +1,23 @@ +//===- 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 &Res); + +} // namespace clang + +#endif // LLVM_CLANG_BASIC_MAKESUPPORT_H diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h --- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h +++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h @@ -72,7 +72,7 @@ /// 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, diff --git a/clang/lib/Basic/CMakeLists.txt b/clang/lib/Basic/CMakeLists.txt --- a/clang/lib/Basic/CMakeLists.txt +++ b/clang/lib/Basic/CMakeLists.txt @@ -54,6 +54,7 @@ IdentifierTable.cpp LangOptions.cpp LangStandards.cpp + MakeSupport.cpp Module.cpp ObjCRuntime.cpp OpenCLOptions.cpp diff --git a/clang/lib/Basic/MakeSupport.cpp b/clang/lib/Basic/MakeSupport.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/Basic/MakeSupport.cpp @@ -0,0 +1,35 @@ +//===-- 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 &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 diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -27,6 +27,7 @@ #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" @@ -97,34 +98,6 @@ } } -// Quote target names for inclusion in GNU Make dependency files. -// Only the characters '$', '#', ' ', '\t' are quoted. -static void QuoteTarget(StringRef Target, SmallVectorImpl &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 @@ -1249,7 +1222,7 @@ } else { CmdArgs.push_back("-MT"); SmallString<128> Quoted; - QuoteTarget(A->getValue(), Quoted); + quoteMakeTarget(A->getValue(), Quoted); CmdArgs.push_back(Args.MakeArgString(Quoted)); } } @@ -1274,7 +1247,7 @@ CmdArgs.push_back("-MT"); SmallString<128> Quoted; - QuoteTarget(DepTarget, Quoted); + quoteMakeTarget(DepTarget, Quoted); CmdArgs.push_back(Args.MakeArgString(Quoted)); } diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -8,6 +8,7 @@ #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" @@ -112,7 +113,7 @@ static std::vector splitString(std::string S, char Separator) { SmallVector Segments; - StringRef(S).split(Segments, Separator); + StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, /*KeepEmpty=*/false); std::vector Result; Result.reserve(Segments.size()); for (StringRef Segment : Segments) @@ -135,10 +136,17 @@ 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) diff --git a/clang/test/ClangScanDeps/generate-modules-path-args.c b/clang/test/ClangScanDeps/generate-modules-path-args.c --- a/clang/test/ClangScanDeps/generate-modules-path-args.c +++ b/clang/test/ClangScanDeps/generate-modules-path-args.c @@ -5,6 +5,12 @@ // 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 @@ -16,10 +22,20 @@ // 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: { @@ -27,6 +43,7 @@ // WITHOUT-NEXT: "-cc1" // WITHOUT-NOT: "-serialize-diagnostic-file" // WITHOUT-NOT: "-dependency-file" +// WITHOUT-NOT: "-MT" // WITHOUT: ], //--- cdb.json.template diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -196,6 +196,12 @@ llvm::cl::desc("the module of which the dependencies are to be computed"), llvm::cl::cat(DependencyScannerCategory)); +llvm::cl::list 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, @@ -367,7 +373,8 @@ 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"; }