Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -266,6 +266,8 @@ MetaVarName<"">; def MG : Flag<["-"], "MG">, Group, Flags<[CC1Option]>, HelpText<"Add missing headers to depfile">; +def MJ : JoinedOrSeparate<["-"], "MJ">, Group, + HelpText<"Write a compilation database entry per input">; def MP : Flag<["-"], "MP">, Group, Flags<[CC1Option]>, HelpText<"Create phony target for each dependency (other than main file)">; def MQ : JoinedOrSeparate<["-"], "MQ">, 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.