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;
  }
}
예제 #2
0
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;
  }
}