in lib/Commands/NinjaCommand.cpp [606:777]
static void dumpNinjaManifestJSON(StringRef file, ninja::Manifest* manifest) {
std::cout << "{\n";
std::cout << " \"filename\": \"" << escapeForJSON(file) << "\",\n";
// Dump the top-level bindings.
assert(manifest->getRootScope().getParent() == nullptr);
std::vector<std::pair<std::string, std::string>> bindings;
for (const auto& entry: manifest->getRootScope().getBindings()) {
bindings.push_back({ entry.getKey(), entry.getValue() });
}
std::sort(bindings.begin(), bindings.end());
std::cout << " \"bindings\": {\n";
for (auto it = bindings.begin(), ie = bindings.end(); it != ie; ++it) {
if (it != bindings.begin()) std::cout << ",\n";
std::cout << " \"" << escapeForJSON(it->first) << "\": \""
<< escapeForJSON(it->second) << "\"";
}
std::cout << "\n },\n";
// Dump the pools, if present.
if (!manifest->getPools().empty()) {
std::vector<ninja::Pool*> pools;
for (const auto& entry: manifest->getPools()) {
pools.push_back(entry.getValue());
}
std::sort(pools.begin(), pools.end(), [] (ninja::Pool* a, ninja::Pool* b) {
return a->getName() < b->getName();
});
std::cout << " \"pools\": {\n";
for (auto it = pools.begin(), ie = pools.end(); it != ie; ++it) {
auto pool = *it;
if (it != pools.begin()) std::cout << ",\n";
std::cout << " \"" << escapeForJSON(pool->getName()) << "\": {";
if (uint32_t depth = pool->getDepth()) {
std::cout << "\n \"depth\": " << depth;
}
std::cout << "\n }";
}
std::cout << "\n },\n";
}
// Dump the rules.
std::vector<ninja::Rule*> rules;
for (const auto& entry: manifest->getRootScope().getRules()) {
rules.push_back(entry.getValue());
}
std::sort(rules.begin(), rules.end(), [] (ninja::Rule* a, ninja::Rule* b) {
return a->getName() < b->getName();
});
std::cout << " \"rules\": {\n";
for (auto it = rules.begin(), ie = rules.end(); it != ie; ++it) {
auto rule = *it;
if (it != rules.begin()) std::cout << ",\n";
std::cout << " \"" << escapeForJSON(rule->getName()) << "\": {\n";
std::vector<std::pair<std::string, std::string>> parameters;
for (const auto& entry: rule->getParameters()) {
parameters.push_back({ entry.getKey(), entry.getValue() });
}
std::sort(parameters.begin(), parameters.end());
for (auto pit = parameters.begin(),
pie = parameters.end(); pit != pie; ++pit) {
if (pit != parameters.begin()) std::cout << ",\n";
std::cout << " \"" << escapeForJSON(pit->first) << "\": \""
<< escapeForJSON(pit->second) << "\"";
}
std::cout << "\n }";
}
std::cout << "\n },\n";
// Dump the default targets, if specified.
if (!manifest->getDefaultTargets().empty()) {
std::vector<ninja::Node*> defaultTargets = manifest->getDefaultTargets();
std::sort(defaultTargets.begin(), defaultTargets.end(),
[] (ninja::Node* a, ninja::Node* b) {
return a->getScreenPath() < b->getScreenPath();
});
std::cout << " \"default_targets\": [";
for (auto it = defaultTargets.begin(),
ie = defaultTargets.end(); it != ie; ++it) {
if (it != defaultTargets.begin()) std::cout << ", ";
std::cout << "\"" << escapeForJSON((*it)->getScreenPath()) << "\"";
}
std::cout << "],\n";
}
// Dump the commands.
std::vector<ninja::Command*> commands(manifest->getCommands());
std::sort(commands.begin(), commands.end(),
[] (ninja::Command* a, ninja::Command* b) {
// Commands can not have duplicate outputs, so comparing based
// only on the first still provides a total ordering.
return a->getOutputs()[0]->getScreenPath() <
b->getOutputs()[0]->getScreenPath();
});
std::cout << " \"commands\": [\n";
for (auto it = commands.begin(), ie = commands.end(); it != ie; ++it) {
auto command = *it;
if (it != commands.begin()) std::cout << ",\n";
std::cout << " {\n";
std::cout << " \"outputs\": [";
for (auto it = command->getOutputs().begin(),
ie = command->getOutputs().end(); it != ie; ++it) {
if (it != command->getOutputs().begin()) std::cout << ", ";
std::cout << "\"" << escapeForJSON((*it)->getScreenPath()) << "\"";
}
std::cout << "],\n";
std::cout << " \"rule\": \""
<< command->getRule()->getName() << "\",\n";
std::cout << " \"inputs\": [";
for (auto it = command->explicitInputs_begin(),
ie = command->explicitInputs_end(); it != ie; ++it) {
if (it != command->explicitInputs_begin()) std::cout << ", ";
std::cout << "\"" << escapeForJSON((*it)->getScreenPath()) << "\"";
}
std::cout << "],\n";
if (command->getNumImplicitInputs()) {
std::cout << " \"implicit_inputs\": [";
for (auto it = command->implicitInputs_begin(),
ie = command->implicitInputs_end(); it != ie; ++it) {
if (it != command->implicitInputs_begin()) std::cout << ", ";
std::cout << "\"" << escapeForJSON((*it)->getScreenPath()) << "\"";
}
std::cout << "],\n";
}
if (command->getNumOrderOnlyInputs()) {
std::cout << " \"order_only_inputs\": [";
for (auto it = command->orderOnlyInputs_begin(),
ie = command->orderOnlyInputs_end(); it != ie; ++it) {
if (it != command->orderOnlyInputs_begin()) std::cout << ", ";
std::cout << "\"" << escapeForJSON((*it)->getScreenPath()) << "\"";
}
std::cout << "],\n";
}
// Write out optional things.
if (command->hasGeneratorFlag())
std::cout << " \"generator\": true,\n";
if (command->hasRestatFlag())
std::cout << " \"restat\": true,\n";
if (const ninja::Pool* executionPool = command->getExecutionPool()) {
std::cout << " \"pool\": \""
<< escapeForJSON(executionPool->getName()) << "\",\n";
}
switch (command->getDepsStyle()) {
case ninja::Command::DepsStyleKind::None:
break;
case ninja::Command::DepsStyleKind::GCC:
std::cout << " \"deps\": \"gcc\",\n";
std::cout << " \"depfile\": \""
<< escapeForJSON(command->getDepsFile()) << "\",\n";
break;
case ninja::Command::DepsStyleKind::MSVC:
std::cout << " \"deps\": \"msvc\",\n";
break;
}
// Finally, write out the attributes.
std::cout << " \"command\": \""
<< escapeForJSON(command->getCommandString()) << "\",\n";
std::cout << " \"description\": \""
<< escapeForJSON(command->getDescription()) << "\"\n";
std::cout << " }";
}
std::cout << "\n ]\n";
std::cout << "}\n";
}