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()); // Predicate for whether the input should cause the command to skip. auto shouldSkipForInput = [&] { // If the value is an existing or virtual input, we are always good. if (value.isExistingInput() || value.isVirtualInput()) return false; // 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 false; // If the value is a missing input, but those are allowed, it is ok. if (allowMissingInputs && value.isMissingInput()) return false; // For anything else, this is an error and the command should be skipped. return true; }; // Check if we need to skip the command because of this input. if (shouldSkipForInput()) { shouldSkip = true; 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; } }
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; } }