]> granicus.if.org Git - clang/commitdiff
[driver] add a new option `-gen-cdb-fragment-path` to emit
authorAlex Lorenz <arphaman@gmail.com>
Mon, 26 Aug 2019 17:59:41 +0000 (17:59 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Mon, 26 Aug 2019 17:59:41 +0000 (17:59 +0000)
a fragment of a compilation database for each compilation

This patch adds a new option called -gen-cdb-fragment-path to the driver,
which can be used to specify a directory path to which clang can emit a fragment
of a CDB for each compilation it needs to invoke.

This option emits the same CDB contents as -MJ, and will be ignored if -MJ is specified.

Differential Revision: https://reviews.llvm.org/D66555

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@369938 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Driver/Options.td
lib/Driver/ToolChains/Clang.cpp
lib/Driver/ToolChains/Clang.h
test/Driver/gen-cdb-fragment.c [new file with mode: 0644]

index a50f881ee05fb3d47493bc3ad4c5fb169d827a5f..7cc00384882ed47e460c1574fd29d5a05c07d12b 100644 (file)
@@ -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">;
index 4f475b121f62e080ab2211190f4bba865f9e60fc..49178b33b5105bb80db42b8bb814f3c2a70a3295 100644 (file)
@@ -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) {
index fc4f5ecdd28a4f2249d03f8ec78433faa4e5bc4a..8b6ac43ebd55620ad020f21f62b5a6e7d9511993 100644 (file)
@@ -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 (file)
index 0000000..553c349
--- /dev/null
@@ -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