summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Driver/Options.td2
-rw-r--r--lib/Driver/ToolChains/Clang.cpp50
-rw-r--r--lib/Driver/ToolChains/Clang.h4
-rw-r--r--test/Driver/gen-cdb-fragment.c37
4 files changed, 89 insertions, 4 deletions
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index a50f881ee0..7cc0038488 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -280,6 +280,8 @@ def arcmt_migrate_emit_arc_errors : Flag<["-"], "arcmt-migrate-emit-errors">,
Flags<[CC1Option]>;
def gen_reproducer: Flag<["-"], "gen-reproducer">, InternalDebugOpt,
HelpText<"Auto-generates preprocessed source files and a reproduction script">;
+def gen_cdb_fragment_path: Separate<["-"], "gen-cdb-fragment-path">, InternalDebugOpt,
+ HelpText<"Emit a compilation database fragment to the specified directory">;
def _migrate : Flag<["--"], "migrate">, Flags<[DriverOption]>,
HelpText<"Run the migrator">;
diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp
index 4f475b121f..49178b33b5 100644
--- a/lib/Driver/ToolChains/Clang.cpp
+++ b/lib/Driver/ToolChains/Clang.cpp
@@ -2013,13 +2013,14 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename,
CompilationDatabase = std::move(File);
}
auto &CDB = *CompilationDatabase;
- SmallString<128> Buf;
- if (llvm::sys::fs::current_path(Buf))
- Buf = ".";
- CDB << "{ \"directory\": \"" << escape(Buf) << "\"";
+ auto CWD = D.getVFS().getCurrentWorkingDirectory();
+ if (!CWD)
+ CWD = ".";
+ CDB << "{ \"directory\": \"" << escape(*CWD) << "\"";
CDB << ", \"file\": \"" << escape(Input.getFilename()) << "\"";
CDB << ", \"output\": \"" << escape(Output.getFilename()) << "\"";
CDB << ", \"arguments\": [\"" << escape(D.ClangExecutable) << "\"";
+ SmallString<128> Buf;
Buf = "-x";
Buf += types::getTypeName(Input.getType());
CDB << ", \"" << escape(Buf) << "\"";
@@ -2037,6 +2038,8 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename,
// Skip writing dependency output and the compilation database itself.
if (O.getGroup().isValid() && O.getGroup().getID() == options::OPT_M_Group)
continue;
+ if (O.getID() == options::OPT_gen_cdb_fragment_path)
+ continue;
// Skip inputs.
if (O.getKind() == Option::InputClass)
continue;
@@ -2051,6 +2054,40 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename,
CDB << ", \"" << escape(Buf) << "\"]},\n";
}
+void Clang::DumpCompilationDatabaseFragmentToDir(
+ StringRef Dir, Compilation &C, StringRef Target, const InputInfo &Output,
+ const InputInfo &Input, const llvm::opt::ArgList &Args) const {
+ // If this is a dry run, do not create the compilation database file.
+ if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH))
+ return;
+
+ if (CompilationDatabase)
+ DumpCompilationDatabase(C, "", Target, Output, Input, Args);
+
+ SmallString<256> Path = Dir;
+ const auto &Driver = C.getDriver();
+ Driver.getVFS().makeAbsolute(Path);
+ auto Err = llvm::sys::fs::create_directory(Path, /*IgnoreExisting=*/true);
+ if (Err) {
+ Driver.Diag(diag::err_drv_compilationdatabase) << Dir << Err.message();
+ return;
+ }
+
+ llvm::sys::path::append(
+ Path,
+ Twine(llvm::sys::path::filename(Input.getFilename())) + ".%%%%.json");
+ int FD;
+ SmallString<256> TempPath;
+ Err = llvm::sys::fs::createUniqueFile(Path, FD, TempPath);
+ if (Err) {
+ Driver.Diag(diag::err_drv_compilationdatabase) << Path << Err.message();
+ return;
+ }
+ CompilationDatabase =
+ std::make_unique<llvm::raw_fd_ostream>(FD, /*shouldClose=*/true);
+ DumpCompilationDatabase(C, "", Target, Output, Input, Args);
+}
+
static void CollectArgsForIntegratedAssembler(Compilation &C,
const ArgList &Args,
ArgStringList &CmdArgs,
@@ -3495,6 +3532,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (const Arg *MJ = Args.getLastArg(options::OPT_MJ)) {
DumpCompilationDatabase(C, MJ->getValue(), TripleStr, Output, Input, Args);
Args.ClaimAllArgs(options::OPT_MJ);
+ } else if (const Arg *GenCDBFragment =
+ Args.getLastArg(options::OPT_gen_cdb_fragment_path)) {
+ DumpCompilationDatabaseFragmentToDir(GenCDBFragment->getValue(), C,
+ TripleStr, Output, Input, Args);
+ Args.ClaimAllArgs(options::OPT_gen_cdb_fragment_path);
}
if (IsCuda || IsHIP) {
diff --git a/lib/Driver/ToolChains/Clang.h b/lib/Driver/ToolChains/Clang.h
index fc4f5ecdd2..8b6ac43ebd 100644
--- a/lib/Driver/ToolChains/Clang.h
+++ b/lib/Driver/ToolChains/Clang.h
@@ -95,6 +95,10 @@ private:
const InputInfo &Output, const InputInfo &Input,
const llvm::opt::ArgList &Args) const;
+ void DumpCompilationDatabaseFragmentToDir(
+ StringRef Dir, Compilation &C, StringRef Target, const InputInfo &Output,
+ const InputInfo &Input, const llvm::opt::ArgList &Args) const;
+
public:
Clang(const ToolChain &TC);
~Clang() override;
diff --git a/test/Driver/gen-cdb-fragment.c b/test/Driver/gen-cdb-fragment.c
new file mode 100644
index 0000000000..553c349afc
--- /dev/null
+++ b/test/Driver/gen-cdb-fragment.c
@@ -0,0 +1,37 @@
+// REQUIRES: x86-registered-target
+// RUN: rm -rf %t.cdb
+// RUN: %clang -target x86_64-apple-macos10.15 -c %s -o - -gen-cdb-fragment-path %t.cdb
+// RUN: ls %t.cdb | FileCheck --check-prefix=CHECK-LS %s
+// CHECK-LS: gen-cdb-fragment.c.{{.*}}.json
+
+// RUN: cat %t.cdb/*.json | FileCheck --check-prefix=CHECK %s
+// CHECK: { "directory": "{{.*}}", "file": "{{.*}}gen-cdb-fragment.c", "output": "-", "arguments": [{{.*}}, "--target=x86_64-apple-macos10.15"{{.*}}]},
+// RUN: cat %t.cdb/*.json | FileCheck --check-prefix=CHECK-FLAG %s
+// CHECK-FLAG-NOT: -gen-cdb-fragment-path
+
+// RUN: rm -rf %t.cdb
+// RUN: mkdir %t.cdb
+// RUN: ls %t.cdb | not FileCheck --check-prefix=CHECK-LS %s
+// RUN: %clang -target x86_64-apple-macos10.15 -S %s -o - -gen-cdb-fragment-path %t.cdb
+// RUN: ls %t.cdb | FileCheck --check-prefix=CHECK-LS %s
+
+// Empty path is equivalent to '.'
+// RUN: rm -rf %t.cdb
+// RUN: mkdir %t.cdb
+// RUN: %clang -target x86_64-apple-macos10.15 -working-directory %t.cdb -c %s -o - -gen-cdb-fragment-path ""
+// RUN: ls %t.cdb | FileCheck --check-prefix=CHECK-LS %s
+// RUN: cat %t.cdb/*.json | FileCheck --check-prefix=CHECK-CWD %s
+// CHECK-CWD: "directory": "{{.*}}.cdb"
+
+// -### does not emit the CDB fragment
+// RUN: rm -rf %t.cdb
+// RUN: mkdir %t.cdb
+// RUN: %clang -target x86_64-apple-macos10.15 -S %s -o - -gen-cdb-fragment-path %t.cdb -###
+// RUN: ls %t.cdb | not FileCheck --check-prefix=CHECK-LS %s
+
+// -MJ is preferred over -gen-cdb-fragment-path
+// RUN: rm -rf %t.cdb
+// RUN: mkdir %t.cdb
+// RUN: %clang -target x86_64-apple-macos10.15 -S %s -o - -gen-cdb-fragment-path %t.cdb -MJ %t.out
+// RUN: ls %t.cdb | not FileCheck --check-prefix=CHECK-LS %s
+// RUN: FileCheck %s < %t.out