#include "cmConfigure.h" // IWYU pragma: keep #include #include #include #include #include #include #include "cmsys/FStream.hxx" #include "cmSystemTools.h" class CompileCommandParser { public: class CommandType : public std::map { public: std::string const& at(std::string const& k) const { auto i = this->find(k); if (i != this->end()) { return i->second; } static std::string emptyString; return emptyString; } }; using TranslationUnitsType = std::vector; CompileCommandParser(std::istream& input) : Input(input) { } void Parse() { this->NextNonWhitespace(); this->ParseTranslationUnits(); } const TranslationUnitsType& GetTranslationUnits() { return this->TranslationUnits; } private: void ParseTranslationUnits() { this->TranslationUnits = TranslationUnitsType(); this->ExpectOrDie('[', "at start of compile command file\n"); do { this->ParseTranslationUnit(); this->TranslationUnits.push_back(this->Command); } while (this->Expect(',')); this->ExpectOrDie(']', "at end of array"); } void ParseTranslationUnit() { this->Command = CommandType(); if (!this->Expect('{')) { return; } if (this->Expect('}')) { return; } do { this->ParseString(); std::string name = this->String; this->ExpectOrDie(':', "between name and value"); this->ParseString(); std::string value = this->String; this->Command[name] = value; } while (this->Expect(',')); this->ExpectOrDie('}', "at end of object"); } void ParseString() { this->String = ""; if (!this->Expect('"')) { return; } while (!this->Expect('"')) { this->Expect('\\'); this->String.append(1, this->C); this->Next(); } } bool Expect(char c) { if (this->C == c) { this->NextNonWhitespace(); return true; } return false; } void ExpectOrDie(char c, const std::string& message) { if (!this->Expect(c)) { this->ErrorExit(std::string("'") + c + "' expected " + message + "."); } } void NextNonWhitespace() { do { this->Next(); } while (this->IsWhitespace()); } void Next() { this->C = char(this->Input.get()); if (this->Input.bad()) { this->ErrorExit("Unexpected end of file."); } } void ErrorExit(const std::string& message) { std::cout << "ERROR: " << message; exit(1); } bool IsWhitespace() const { return (this->C == ' ' || this->C == '\t' || this->C == '\n' || this->C == '\r'); } char C; TranslationUnitsType TranslationUnits; CommandType Command; std::string String; std::istream& Input; }; int main() { cmsys::ifstream file("compile_commands.json"); CompileCommandParser parser(file); parser.Parse(); for (auto const& tu : parser.GetTranslationUnits()) { std::vector command; cmSystemTools::ParseUnixCommandLine(tu.at("command").c_str(), command); if (!cmSystemTools::RunSingleCommand(command, nullptr, nullptr, nullptr, tu.at("directory").c_str())) { std::cout << "ERROR: Failed to run command \"" << command[0] << "\"" << std::endl; exit(1); } } return 0; }