diff options
Diffstat (limited to 'Tests/CMakeLib/run_compile_commands.cxx')
-rw-r--r-- | Tests/CMakeLib/run_compile_commands.cxx | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/Tests/CMakeLib/run_compile_commands.cxx b/Tests/CMakeLib/run_compile_commands.cxx new file mode 100644 index 0000000..0ebe00e --- /dev/null +++ b/Tests/CMakeLib/run_compile_commands.cxx @@ -0,0 +1,159 @@ +#include "cmConfigure.h" // IWYU pragma: keep + +#include <cstdlib> +#include <iostream> +#include <map> +#include <string> +#include <utility> +#include <vector> + +#include "cmsys/FStream.hxx" + +#include "cmSystemTools.h" + +class CompileCommandParser +{ +public: + class CommandType : public std::map<std::string, std::string> + { + 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<CommandType>; + + 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<std::string> 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; +} |