|
|
|
#include "cmConfigure.h" // IWYU pragma: keep
|
|
|
|
|
|
|
|
#include "cmsys/FStream.hxx"
|
|
|
|
#include <iostream>
|
|
|
|
#include <map>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string>
|
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#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
|
|
|
|
{
|
|
|
|
const_iterator i = this->find(k);
|
|
|
|
if (i != this->end()) {
|
|
|
|
return i->second;
|
|
|
|
}
|
|
|
|
static std::string emptyString;
|
|
|
|
return emptyString;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
typedef std::vector<CommandType> TranslationUnitsType;
|
|
|
|
|
|
|
|
CompileCommandParser(std::istream& input)
|
|
|
|
: Input(input)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Parse()
|
|
|
|
{
|
|
|
|
NextNonWhitespace();
|
|
|
|
ParseTranslationUnits();
|
|
|
|
}
|
|
|
|
|
|
|
|
const TranslationUnitsType& GetTranslationUnits()
|
|
|
|
{
|
|
|
|
return this->TranslationUnits;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void ParseTranslationUnits()
|
|
|
|
{
|
|
|
|
this->TranslationUnits = TranslationUnitsType();
|
|
|
|
ExpectOrDie('[', "at start of compile command file\n");
|
|
|
|
do {
|
|
|
|
ParseTranslationUnit();
|
|
|
|
this->TranslationUnits.push_back(this->Command);
|
|
|
|
} while (Expect(','));
|
|
|
|
ExpectOrDie(']', "at end of array");
|
|
|
|
}
|
|
|
|
|
|
|
|
void ParseTranslationUnit()
|
|
|
|
{
|
|
|
|
this->Command = CommandType();
|
|
|
|
if (!Expect('{')) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (Expect('}')) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
do {
|
|
|
|
ParseString();
|
|
|
|
std::string name = this->String;
|
|
|
|
ExpectOrDie(':', "between name and value");
|
|
|
|
ParseString();
|
|
|
|
std::string value = this->String;
|
|
|
|
this->Command[name] = value;
|
|
|
|
} while (Expect(','));
|
|
|
|
ExpectOrDie('}', "at end of object");
|
|
|
|
}
|
|
|
|
|
|
|
|
void ParseString()
|
|
|
|
{
|
|
|
|
this->String = "";
|
|
|
|
if (!Expect('"')) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
while (!Expect('"')) {
|
|
|
|
Expect('\\');
|
|
|
|
this->String.append(1, C);
|
|
|
|
Next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Expect(char c)
|
|
|
|
{
|
|
|
|
if (this->C == c) {
|
|
|
|
NextNonWhitespace();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExpectOrDie(char c, const std::string& message)
|
|
|
|
{
|
|
|
|
if (!Expect(c)) {
|
|
|
|
ErrorExit(std::string("'") + c + "' expected " + message + ".");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NextNonWhitespace()
|
|
|
|
{
|
|
|
|
do {
|
|
|
|
Next();
|
|
|
|
} while (IsWhitespace());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Next()
|
|
|
|
{
|
|
|
|
this->C = char(Input.get());
|
|
|
|
if (this->Input.bad()) {
|
|
|
|
ErrorExit("Unexpected end of file.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ErrorExit(const std::string& message)
|
|
|
|
{
|
|
|
|
std::cout << "ERROR: " << message;
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsWhitespace()
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|