summaryrefslogtreecommitdiffstats
path: root/Tests/CMakeLib/run_compile_commands.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Tests/CMakeLib/run_compile_commands.cxx')
-rw-r--r--Tests/CMakeLib/run_compile_commands.cxx159
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;
+}