BuildValue ExternalCommand:: getResultForOutput(Node* node, const BuildValue& value) { // If the value was a failed or skipped command, propagate the failure. if (value.isFailedCommand() || value.isSkippedCommand()) return BuildValue::makeFailedInput(); // Otherwise, we should have a successful command -- return the actual // result for the output. assert(value.isSuccessfulCommand()); // If the node is virtual, the output is always a virtual input value. if (static_cast<BuildNode*>(node)->isVirtual()) { return BuildValue::makeVirtualInput(); } // Find the index of the output node. // // FIXME: This is O(N). We don't expect N to be large in practice, but it // could be. auto it = std::find(outputs.begin(), outputs.end(), node); assert(it != outputs.end()); auto idx = it - outputs.begin(); assert(idx < value.getNumOutputs()); auto& info = value.getNthOutputInfo(idx); if (info.isMissing()) return BuildValue::makeMissingOutput(); return BuildValue::makeExistingInput(info); }
void ExternalCommand::provideValue(BuildSystemCommandInterface& bsci, core::Task*, uintptr_t inputID, const BuildValue& value) { // Process the input value to see if we should skip this command. // All direct inputs should be individual node values. assert(!value.hasMultipleOutputs()); assert(value.isExistingInput() || value.isMissingInput() || value.isMissingOutput() || value.isFailedInput() || value.isVirtualInput() || value.isSkippedCommand() || value.isDirectoryTreeSignature() || value.isStaleFileRemoval()); // If the input should cause this command to skip, how should it skip? auto getSkipValueForInput = [&]() -> llvm::Optional<BuildValue> { // If the value is an signature, existing, or virtual input, we are always // good. if (value.isDirectoryTreeSignature() | value.isExistingInput() || value.isVirtualInput() || value.isStaleFileRemoval()) return llvm::None; // We explicitly allow running the command against a missing output, under // the expectation that responsibility for reporting this situation falls to // the command. // // FIXME: Eventually, it might be nice to harden the format so that we know // when an output was actually required versus optional. if (value.isMissingOutput()) return llvm::None; // If the value is a missing input, but those are allowed, it is ok. if (value.isMissingInput()) { if (allowMissingInputs) return llvm::None; else return BuildValue::makePropagatedFailureCommand(); } // Propagate failure. if (value.isFailedInput()) return BuildValue::makePropagatedFailureCommand(); // A skipped dependency doesn't cause this command to skip. if (value.isSkippedCommand()) return llvm::None; llvm_unreachable("unexpected input"); }; // Check if we need to skip the command because of this input. auto skipValueForInput = getSkipValueForInput(); if (skipValueForInput.hasValue()) { skipValue = std::move(skipValueForInput); if (value.isMissingInput()) { hasMissingInput = true; // FIXME: Design the logging and status output APIs. bsci.getDelegate().error( "", {}, (Twine("missing input '") + inputs[inputID]->getName() + "' and no rule to build it")); } } else { // If there is a missing input file (from a successful command), we always // need to run the command. if (value.isMissingOutput()) canUpdateIfNewer = false; } }