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