in lib/BuildSystem/BuildSystem.cpp [1504:1813]
std::unique_ptr<Rule> BuildSystemEngineDelegate::lookupRule(const KeyType& keyData) {
// Decode the key.
auto key = BuildKey::fromData(keyData);
switch (key.getKind()) {
case BuildKey::Kind::Unknown:
break;
case BuildKey::Kind::Command: {
// Find the comand.
auto it = getBuildDescription().getCommands().find(key.getCommandName());
if (it == getBuildDescription().getCommands().end()) {
// If there is no such command, produce an error task.
return std::unique_ptr<Rule>(new BuildSystemRule(
keyData,
/*signature=*/{},
/*Action=*/ [](BuildEngine& engine) -> Task* {
return new MissingCommandTask();
},
/*IsValid=*/ [](BuildEngine&, const Rule&, const ValueType&) -> bool {
// The cached result for a missing command is never valid.
return false;
}
));
}
// Create the rule for the command.
Command* command = it->second.get();
return std::unique_ptr<Rule>(new BuildSystemRule(
keyData,
command->getSignature(),
/*Action=*/ [command](BuildEngine& engine) -> Task* {
return new CommandTask(*command);
},
/*IsValid=*/ [command](BuildEngine& engine, const Rule& rule,
const ValueType& value) -> bool {
return CommandTask::isResultValid(
engine, *command, BuildValue::fromData(value));
},
/*UpdateStatus=*/ [command](BuildEngine& engine,
core::Rule::StatusKind status) {
return ::getBuildSystem(engine).getDelegate().commandStatusChanged(
command, convertStatusKind(status));
}
));
}
case BuildKey::Kind::CustomTask: {
// Search for a tool which knows how to create the given custom task.
//
// FIXME: We should most likely have some kind of registration process so we
// can do an efficient query here, but exactly how this should look isn't
// clear yet.
for (const auto& it: getBuildDescription().getTools()) {
auto result = it.second->createCustomCommand(key);
if (!result) continue;
// Save the custom command.
customTasks.emplace_back(std::move(result));
Command *command = customTasks.back().get();
return std::unique_ptr<Rule>(new BuildSystemRule(
keyData,
command->getSignature(),
/*Action=*/ [command](BuildEngine& engine) -> Task* {
return new CommandTask(*command);
},
/*IsValid=*/ [command](BuildEngine& engine, const Rule& rule,
const ValueType& value) -> bool {
return CommandTask::isResultValid(
engine, *command, BuildValue::fromData(value));
},
/*UpdateStatus=*/ [command](BuildEngine& engine,
core::Rule::StatusKind status) {
return ::getBuildSystem(engine).getDelegate().commandStatusChanged(
command, convertStatusKind(status));
}
));
}
// We were unable to create an appropriate custom command, produce an error
// task.
return std::unique_ptr<Rule>(new BuildSystemRule(
keyData,
/*signature=*/{},
/*Action=*/ [](BuildEngine& engine) -> Task* {
return new MissingCommandTask();
},
/*IsValid=*/ [](BuildEngine&, const Rule&, const ValueType&) -> bool {
// The cached result for a missing command is never valid.
return false;
}
));
}
case BuildKey::Kind::DirectoryContents: {
std::string path = key.getDirectoryPath();
return std::unique_ptr<Rule>(new BuildSystemRule(
keyData,
/*signature=*/{},
/*Action=*/ [path](BuildEngine& engine) -> Task* {
return new DirectoryContentsTask(path);
},
/*IsValid=*/ [path](BuildEngine& engine, const Rule& rule,
const ValueType& value) mutable -> bool {
return DirectoryContentsTask::isResultValid(
engine, path, BuildValue::fromData(value));
}
));
}
case BuildKey::Kind::FilteredDirectoryContents: {
std::string path = key.getFilteredDirectoryPath();
std::string patterns = key.getContentExclusionPatterns();
return std::unique_ptr<Rule>(new BuildSystemRule(
keyData,
/*signature=*/{},
/*Action=*/ [path, patterns](BuildEngine& engine) -> Task* {
BinaryDecoder decoder(patterns);
return new FilteredDirectoryContentsTask(path, StringList(decoder));
},
/*IsValid=*/ nullptr
));
}
case BuildKey::Kind::DirectoryTreeSignature: {
std::string path = key.getDirectoryTreeSignaturePath();
std::string filters = key.getContentExclusionPatterns();
return std::unique_ptr<Rule>(new BuildSystemRule(
keyData,
/*signature=*/{},
/*Action=*/ [path, filters](
BuildEngine& engine) mutable -> Task* {
BinaryDecoder decoder(filters);
return new DirectoryTreeSignatureTask(path, StringList(decoder));
},
// Directory signatures don't require any validation outside of their
// concrete dependencies.
/*IsValid=*/ nullptr
));
}
case BuildKey::Kind::DirectoryTreeStructureSignature: {
std::string path = key.getDirectoryPath();
return std::unique_ptr<Rule>(new BuildSystemRule(
keyData,
/*signature=*/{},
/*Action=*/ [path](
BuildEngine& engine) mutable -> Task* {
return new DirectoryTreeStructureSignatureTask(path);
},
// Directory signatures don't require any validation outside of their
// concrete dependencies.
/*IsValid=*/ nullptr
));
}
case BuildKey::Kind::Node: {
// Find the node.
auto it = getBuildDescription().getNodes().find(key.getNodeName());
BuildNode* node;
if (it != getBuildDescription().getNodes().end()) {
node = static_cast<BuildNode*>(it->second.get());
} else {
auto it = dynamicNodes.find(key.getNodeName());
if (it != dynamicNodes.end()) {
node = it->second.get();
} else {
// Create nodes on the fly for any unknown ones.
auto nodeOwner = system.lookupNode(
key.getNodeName(), /*isImplicit=*/true);
node = nodeOwner.get();
dynamicNodes[key.getNodeName()] = std::move(nodeOwner);
}
}
// Create the rule used to construct this node.
//
// We could bypass this level and directly return the rule to run the
// command, which would reduce the number of tasks in the system. For now we
// do the uniform thing, but do differentiate between input and command
// nodes.
// Create an input node if there are no producers.
if (node->getProducers().empty()) {
if (node->isVirtual()) {
return std::unique_ptr<Rule>(new BuildSystemRule(
keyData,
node->getSignature(),
/*Action=*/ [](BuildEngine& engine) -> Task* {
return new VirtualInputNodeTask();
},
/*IsValid=*/ [node](BuildEngine& engine, const Rule& rule,
const ValueType& value) -> bool {
return VirtualInputNodeTask::isResultValid(
engine, *node, BuildValue::fromData(value));
}
));
}
if (node->isDirectory()) {
return std::unique_ptr<Rule>(new BuildSystemRule(
keyData,
node->getSignature(),
/*Action=*/ [node](BuildEngine& engine) -> Task* {
return new DirectoryInputNodeTask(*node);
},
// Directory nodes don't require any validation outside of their
// concrete dependencies.
/*IsValid=*/ nullptr
));
}
if (node->isDirectoryStructure()) {
return std::unique_ptr<Rule>(new BuildSystemRule(
keyData,
node->getSignature(),
/*Action=*/ [node](BuildEngine& engine) -> Task* {
return new DirectoryStructureInputNodeTask(*node);
},
// Directory nodes don't require any validation outside of their
// concrete dependencies.
/*IsValid=*/ nullptr
));
}
return std::unique_ptr<Rule>(new BuildSystemRule(
keyData,
node->getSignature(),
/*Action=*/ [node](BuildEngine& engine) -> Task* {
return new FileInputNodeTask(*node);
},
/*IsValid=*/ [node](BuildEngine& engine, const Rule& rule,
const ValueType& value) -> bool {
return FileInputNodeTask::isResultValid(
engine, *node, BuildValue::fromData(value));
}
));
}
// Otherwise, create a task for a produced node.
return std::unique_ptr<Rule>(new BuildSystemRule(
keyData,
node->getSignature(),
/*Action=*/ [node](BuildEngine& engine) -> Task* {
return new ProducedNodeTask(*node);
},
/*IsValid=*/ [node](BuildEngine& engine, const Rule& rule,
const ValueType& value) -> bool {
return ProducedNodeTask::isResultValid(
engine, *node, BuildValue::fromData(value));
}
));
}
case BuildKey::Kind::Stat: {
StatNode* statnode;
auto it = dynamicStatNodes.find(key.getStatName());
if (it != dynamicStatNodes.end()) {
statnode = it->second.get();
} else {
// Create nodes on the fly for any unknown ones.
auto statOwner = llvm::make_unique<StatNode>(key.getStatName());
statnode = statOwner.get();
dynamicStatNodes[key.getStatName()] = std::move(statOwner);
}
// Create the rule to construct this target.
return std::unique_ptr<Rule>(new BuildSystemRule(
keyData,
/*signature=*/{},
/*Action=*/ [statnode](BuildEngine& engine) -> Task* {
return new StatTask(*statnode);
},
/*IsValid=*/ [statnode](BuildEngine& engine, const Rule& rule,
const ValueType& value) -> bool {
return StatTask::isResultValid(
engine, *statnode, BuildValue::fromData(value));
}
));
}
case BuildKey::Kind::Target: {
// Find the target.
auto it = getBuildDescription().getTargets().find(key.getTargetName());
if (it == getBuildDescription().getTargets().end()) {
// FIXME: Invalid target name, produce an error.
assert(0 && "FIXME: invalid target");
abort();
}
// Create the rule to construct this target.
Target* target = it->second.get();
return std::unique_ptr<Rule>(new BuildSystemRule(
keyData,
/*signature=*/{},
/*Action=*/ [target](BuildEngine& engine) -> Task* {
return new TargetTask(*target);
},
/*IsValid=*/ [target](BuildEngine& engine, const Rule& rule,
const ValueType& value) -> bool {
return TargetTask::isResultValid(
engine, *target, BuildValue::fromData(value));
}
));
}
}
assert(0 && "invalid key type");
abort();
}