cmake/Tests/CMakeLib/run_compile_commands.cxx

160 lines
3.4 KiB
C++
Raw Normal View History

2018-01-26 17:06:56 +01:00
#include "cmConfigure.h" // IWYU pragma: keep
2011-06-19 15:41:06 +03:00
2020-02-01 23:06:01 +01:00
#include <cstdlib>
2016-10-30 18:24:19 +01:00
#include <iostream>
#include <map>
#include <string>
#include <utility>
#include <vector>
2020-02-01 23:06:01 +01:00
#include "cmsys/FStream.hxx"
2017-04-14 19:02:05 +02:00
#include "cmSystemTools.h"
2016-07-09 11:21:54 +02:00
class CompileCommandParser
{
2011-06-19 15:41:06 +03:00
public:
2016-07-09 11:21:54 +02:00
class CommandType : public std::map<std::string, std::string>
2011-06-19 15:41:06 +03:00
{
public:
2015-04-27 22:25:09 +02:00
std::string const& at(std::string const& k) const
2016-07-09 11:21:54 +02:00
{
2020-02-01 23:06:01 +01:00
auto i = this->find(k);
2016-07-09 11:21:54 +02:00
if (i != this->end()) {
return i->second;
}
2015-04-27 22:25:09 +02:00
static std::string emptyString;
2011-06-19 15:41:06 +03:00
return emptyString;
2016-07-09 11:21:54 +02:00
}
2011-06-19 15:41:06 +03:00
};
2020-02-01 23:06:01 +01:00
using TranslationUnitsType = std::vector<CommandType>;
2011-06-19 15:41:06 +03:00
2016-10-30 18:24:19 +01:00
CompileCommandParser(std::istream& input)
: Input(input)
{
}
2011-06-19 15:41:06 +03:00
void Parse()
{
2021-09-14 00:13:48 +02:00
this->NextNonWhitespace();
this->ParseTranslationUnits();
2011-06-19 15:41:06 +03:00
}
const TranslationUnitsType& GetTranslationUnits()
{
return this->TranslationUnits;
}
private:
void ParseTranslationUnits()
{
this->TranslationUnits = TranslationUnitsType();
2021-09-14 00:13:48 +02:00
this->ExpectOrDie('[', "at start of compile command file\n");
2016-07-09 11:21:54 +02:00
do {
2021-09-14 00:13:48 +02:00
this->ParseTranslationUnit();
2011-06-19 15:41:06 +03:00
this->TranslationUnits.push_back(this->Command);
2021-09-14 00:13:48 +02:00
} while (this->Expect(','));
this->ExpectOrDie(']', "at end of array");
2011-06-19 15:41:06 +03:00
}
void ParseTranslationUnit()
{
this->Command = CommandType();
2021-09-14 00:13:48 +02:00
if (!this->Expect('{')) {
2016-07-09 11:21:54 +02:00
return;
2016-10-30 18:24:19 +01:00
}
2021-09-14 00:13:48 +02:00
if (this->Expect('}')) {
2016-07-09 11:21:54 +02:00
return;
2016-10-30 18:24:19 +01:00
}
2016-07-09 11:21:54 +02:00
do {
2021-09-14 00:13:48 +02:00
this->ParseString();
2011-06-19 15:41:06 +03:00
std::string name = this->String;
2021-09-14 00:13:48 +02:00
this->ExpectOrDie(':', "between name and value");
this->ParseString();
2011-06-19 15:41:06 +03:00
std::string value = this->String;
this->Command[name] = value;
2021-09-14 00:13:48 +02:00
} while (this->Expect(','));
this->ExpectOrDie('}', "at end of object");
2011-06-19 15:41:06 +03:00
}
void ParseString()
{
2012-06-27 20:52:58 +03:00
this->String = "";
2021-09-14 00:13:48 +02:00
if (!this->Expect('"')) {
2016-07-09 11:21:54 +02:00
return;
2016-10-30 18:24:19 +01:00
}
2021-09-14 00:13:48 +02:00
while (!this->Expect('"')) {
this->Expect('\\');
this->String.append(1, this->C);
this->Next();
2016-07-09 11:21:54 +02:00
}
2011-06-19 15:41:06 +03:00
}
bool Expect(char c)
{
2016-07-09 11:21:54 +02:00
if (this->C == c) {
2021-09-14 00:13:48 +02:00
this->NextNonWhitespace();
2011-06-19 15:41:06 +03:00
return true;
2016-07-09 11:21:54 +02:00
}
2011-06-19 15:41:06 +03:00
return false;
}
2016-07-09 11:21:54 +02:00
void ExpectOrDie(char c, const std::string& message)
2011-06-19 15:41:06 +03:00
{
2021-09-14 00:13:48 +02:00
if (!this->Expect(c)) {
this->ErrorExit(std::string("'") + c + "' expected " + message + ".");
2016-10-30 18:24:19 +01:00
}
2011-06-19 15:41:06 +03:00
}
void NextNonWhitespace()
{
2016-07-09 11:21:54 +02:00
do {
2021-09-14 00:13:48 +02:00
this->Next();
} while (this->IsWhitespace());
2011-06-19 15:41:06 +03:00
}
void Next()
{
2021-09-14 00:13:48 +02:00
this->C = char(this->Input.get());
2016-10-30 18:24:19 +01:00
if (this->Input.bad()) {
2021-09-14 00:13:48 +02:00
this->ErrorExit("Unexpected end of file.");
2016-10-30 18:24:19 +01:00
}
2011-06-19 15:41:06 +03:00
}
2016-07-09 11:21:54 +02:00
void ErrorExit(const std::string& message)
{
2011-06-19 15:41:06 +03:00
std::cout << "ERROR: " << message;
exit(1);
}
2021-09-14 00:13:48 +02:00
bool IsWhitespace() const
2011-06-19 15:41:06 +03:00
{
2016-07-09 11:21:54 +02:00
return (this->C == ' ' || this->C == '\t' || this->C == '\n' ||
this->C == '\r');
2011-06-19 15:41:06 +03:00
}
char C;
TranslationUnitsType TranslationUnits;
CommandType Command;
std::string String;
2016-10-30 18:24:19 +01:00
std::istream& Input;
2011-06-19 15:41:06 +03:00
};
2016-07-09 11:21:54 +02:00
int main()
2011-06-19 15:41:06 +03:00
{
2016-10-30 18:24:19 +01:00
cmsys::ifstream file("compile_commands.json");
CompileCommandParser parser(file);
2011-06-19 15:41:06 +03:00
parser.Parse();
2018-01-26 17:06:56 +01:00
for (auto const& tu : parser.GetTranslationUnits()) {
2015-04-27 22:25:09 +02:00
std::vector<std::string> command;
2018-01-26 17:06:56 +01:00
cmSystemTools::ParseUnixCommandLine(tu.at("command").c_str(), command);
if (!cmSystemTools::RunSingleCommand(command, nullptr, nullptr, nullptr,
tu.at("directory").c_str())) {
2016-07-09 11:21:54 +02:00
std::cout << "ERROR: Failed to run command \"" << command[0] << "\""
<< std::endl;
2011-06-19 15:41:06 +03:00
exit(1);
}
2016-07-09 11:21:54 +02:00
}
2011-06-19 15:41:06 +03:00
return 0;
}