joerg created this revision.
joerg added reviewers: klimek, rsmith.
joerg added a subscriber: cfe-commits.
joerg set the repository for this revision to rL LLVM.
joerg added a dependency: D27138: Extend CompilationDatabase by a field for the 
output filename.

When integrating compilation database output into existing build systems, two 
approaches dominate so far. Ad-hoc implementation of the JSON output rules or 
using compiler wrappers. This patch adds a new option "-MJ foo.json" which 
gives a slightly cleaned up compilation record. The output is a fragment, i.e. 
you still need to add the array markers, but it allows multiple files to be 
easy merged. This way the only change in a build system is adding the option 
with potentially a per-target output file and merging the files with something 
like `(echo '['; cat *.o.json; echo ']' > compilation_database.json`.

The current implementation has two issues:

1. It doesn't honor -###. This would be easily fixable though.
2. It opens the output file more than once. That's why it is currently using 
append mode. Fixing this requires either moving it to a different part in the 
processing chain or storing the stream in an appropiate place.

The output record currently depends on https://reviews.llvm.org/D27138, but 
would be easily adjustable if necessary. I'm aware of the missing test cases, 
will provide them once the architectural side is clear.


Repository:
  rL LLVM

https://reviews.llvm.org/D27140

Files:
  include/clang/Driver/Options.td
  lib/Driver/Tools.cpp

Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -266,6 +266,8 @@
     MetaVarName<"<file>">;
 def MG : Flag<["-"], "MG">, Group<M_Group>, Flags<[CC1Option]>,
     HelpText<"Add missing headers to depfile">;
+def MJ : JoinedOrSeparate<["-"], "MJ">, Group<M_Group>,
+    HelpText<"Write a compilation database entry per input">;
 def MP : Flag<["-"], "MP">, Group<M_Group>, Flags<[CC1Option]>,
     HelpText<"Create phony target for each dependency (other than main file)">;
 def MQ : JoinedOrSeparate<["-"], "MQ">, Group<M_Group>, Flags<[CC1Option]>,
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -4002,6 +4002,72 @@
     CmdArgs.push_back("-KPIC");
 }
 
+static void QuoteJSONString(llvm::raw_fd_ostream &Stream, StringRef Str) {
+  Stream << "\"";
+  if (Str.find_first_of("\\\"") == Str.npos) {
+    Stream << Str;
+  } else {
+    for (auto ch: Str) {
+      if (ch == '\\' || ch == '"')
+        Stream << '\\';
+      Stream << ch;
+    }
+  }
+  Stream << "\"";
+}
+
+static void DumpCompilationDatabase(const Driver &D, StringRef Filename, StringRef Target, const InputInfo &Output,
+                                    const InputInfo &Input, const ArgList &Args) {
+  std::error_code EC;
+  llvm::raw_fd_ostream File(Filename, EC, llvm::sys::fs::F_Text | llvm::sys::fs::F_Append);
+  if (EC) {
+    //errs() << "Failed to open " << Filename << ": " << EC.message() << "\n" ;
+    return;
+  }
+  SmallString<128> Buf;
+  if (llvm::sys::fs::current_path(Buf))
+    Buf = ".";
+  File << "{ \"directory\": ";
+  QuoteJSONString(File, Buf);
+  File << ", \"file\": ";
+  QuoteJSONString(File, Input.getFilename());
+  File << ", \"output\": ";
+  QuoteJSONString(File, Output.getFilename());
+
+  File << ", \"arguments\": [";
+  QuoteJSONString(File, D.ClangExecutable);
+  File << ", ";
+  Buf = "-x";
+  Buf += types::getTypeName(Input.getType());
+  QuoteJSONString(File, Buf);
+  File << ", ";
+  QuoteJSONString(File, Input.getFilename());
+  for (auto &A: Args) {
+    auto &O = A->getOption();
+    // Skip language selection, which is positional.
+    if (O.getID() == options::OPT_x)
+      continue;
+    // Skip writing dependency output and the compiliation database itself.
+    if (O.getGroup().isValid() && O.getGroup().getID() == options::OPT_M_Group)
+      continue;
+    // Skip inputs.
+    if (O.getKind() == Option::InputClass)
+      continue;
+    // All other arguments are quoted and appended.
+    ArgStringList ASL;
+    A->render(Args, ASL);
+    for (auto &it: ASL) {
+      File << ", ";
+      QuoteJSONString(File, it);
+    }
+  }
+  File << ", ";
+  Buf = "--target=";
+  Buf += Target;
+  QuoteJSONString(File, Buf);
+  File << "]},\n";
+}
+
 void Clang::ConstructJob(Compilation &C, const JobAction &JA,
                          const InputInfo &Output, const InputInfoList &Inputs,
                          const ArgList &Args, const char *LinkingOutput) const {
@@ -4046,6 +4112,10 @@
   CmdArgs.push_back("-triple");
   CmdArgs.push_back(Args.MakeArgString(TripleStr));
 
+  if (const Arg *MJ = Args.getLastArg(options::OPT_MJ))
+    DumpCompilationDatabase(C.getDriver(), MJ->getValue(), TripleStr, Output, Input, Args);
+  Args.ClaimAllArgs(options::OPT_MJ);
+
   if (IsCuda) {
     // We have to pass the triple of the host if compiling for a CUDA device and
     // vice-versa.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to