use of com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible in project bazel by bazelbuild.
the class CppLinkAction method executeFake.
// Don't forget to update FAKE_LINK_GUID if you modify this method.
@ThreadCompatible
private void executeFake() throws ActionExecutionException {
// The uses of getLinkConfiguration in this method may not be consistent with the computed key.
// I.e., this may be incrementally incorrect.
final Collection<Artifact> linkstampOutputs = getLinkCommandLine().getLinkstamps().values();
// Prefix all fake output files in the command line with $TEST_TMPDIR/.
final String outputPrefix = "$TEST_TMPDIR/";
List<String> escapedLinkArgv = escapeLinkArgv(linkCommandLine.getRawLinkArgv(), linkstampOutputs, outputPrefix);
// Write the commands needed to build the real target to the fake target
// file.
StringBuilder s = new StringBuilder();
Joiner.on('\n').appendTo(s, "# This is a fake target file, automatically generated.", "# Do not edit by hand!", "echo $0 is a fake target file and not meant to be executed.", "exit 0", "EOS", "", "makefile_dir=.", "");
try {
// Concatenate all the (fake) .o files into the result.
for (LinkerInput linkerInput : getLinkCommandLine().getLinkerInputs()) {
Artifact objectFile = linkerInput.getArtifact();
if ((CppFileTypes.OBJECT_FILE.matches(objectFile.getFilename()) || CppFileTypes.PIC_OBJECT_FILE.matches(objectFile.getFilename())) && linkerInput.isFake()) {
// (IOException)
s.append(FileSystemUtils.readContentAsLatin1(objectFile.getPath()));
}
}
s.append(getOutputFile().getBaseName()).append(": ");
for (Artifact linkstamp : linkstampOutputs) {
s.append("mkdir -p " + outputPrefix + linkstamp.getExecPath().getParentDirectory() + " && ");
}
Joiner.on(' ').appendTo(s, ShellEscaper.escapeAll(linkCommandLine.finalizeAlreadyEscapedWithLinkstampCommands(escapedLinkArgv, outputPrefix)));
s.append('\n');
if (getOutputFile().exists()) {
// (IOException)
getOutputFile().setWritable(true);
}
FileSystemUtils.writeContent(getOutputFile(), ISO_8859_1, s.toString());
// (IOException)
getOutputFile().setExecutable(true);
for (Artifact linkstamp : linkstampOutputs) {
FileSystemUtils.touchFile(linkstamp.getPath());
}
} catch (IOException e) {
throw new ActionExecutionException("failed to create fake link command for rule '" + getOwner().getLabel() + ": " + e.getMessage(), this, false);
}
}
use of com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible in project bazel by bazelbuild.
the class CppLinkAction method execute.
@Override
@ThreadCompatible
public void execute(ActionExecutionContext actionExecutionContext) throws ActionExecutionException, InterruptedException {
if (fake) {
executeFake();
} else {
Executor executor = actionExecutionContext.getExecutor();
try {
// Collect input files
List<ActionInput> allInputs = new ArrayList<>();
Artifact.addExpandedArtifacts(getMandatoryInputs(), allInputs, actionExecutionContext.getArtifactExpander());
ImmutableMap<String, String> executionInfo = ImmutableMap.of();
if (needsToRunOnMac()) {
executionInfo = ImmutableMap.of(ExecutionRequirements.REQUIRES_DARWIN, "");
}
Spawn spawn = new SimpleSpawn(this, ImmutableList.copyOf(getCommandLine()), getEnvironment(), executionInfo, ImmutableList.copyOf(allInputs), getOutputs().asList(), estimateResourceConsumptionLocal());
executor.getSpawnActionContext(getMnemonic()).exec(spawn, actionExecutionContext);
} catch (ExecException e) {
throw e.toActionExecutionException("Linking of rule '" + getOwner().getLabel() + "'", executor.getVerboseFailures(), this);
}
}
}
use of com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible in project bazel by bazelbuild.
the class FakeCppCompileAction method execute.
@Override
@ThreadCompatible
public void execute(ActionExecutionContext actionExecutionContext) throws ActionExecutionException, InterruptedException {
setModuleFileFlags();
Executor executor = actionExecutionContext.getExecutor();
// First, do a normal compilation, to generate the ".d" file. The generated object file is built
// to a temporary location (tempOutputFile) and ignored afterwards.
LOG.info("Generating " + getDotdFile());
CppCompileActionContext context = executor.getContext(actionContext);
CppCompileActionContext.Reply reply = null;
try {
// We delegate stdout/stderr to nowhere, i.e. same as redirecting to /dev/null.
reply = context.execWithReply(this, actionExecutionContext.withFileOutErr(new FileOutErr()));
} catch (ExecException e) {
// We ignore failures here (other than capturing the Distributor reply).
// The compilation may well fail (that's the whole point of negative compilation tests).
// We execute it here just for the side effect of generating the ".d" file.
reply = context.getReplyFromException(e, this);
if (reply == null) {
// This can only happen if the ExecException does not come from remote execution.
throw e.toActionExecutionException("Fake C++ Compilation of rule '" + getOwner().getLabel() + "'", executor.getVerboseFailures(), this);
}
}
IncludeScanningContext scanningContext = executor.getContext(IncludeScanningContext.class);
Path execRoot = executor.getExecRoot();
NestedSet<Artifact> discoveredInputs;
if (getDotdFile() == null) {
discoveredInputs = NestedSetBuilder.<Artifact>stableOrder().build();
} else {
HeaderDiscovery.Builder discoveryBuilder = new HeaderDiscovery.Builder().setAction(this).setDotdFile(getDotdFile()).setSourceFile(getSourceFile()).setSpecialInputsHandler(specialInputsHandler).setDependencySet(processDepset(execRoot, reply)).setPermittedSystemIncludePrefixes(getPermittedSystemIncludePrefixes(execRoot)).setAllowedDerivedinputsMap(getAllowedDerivedInputsMap());
if (cppSemantics.needsIncludeValidation()) {
discoveryBuilder.shouldValidateInclusions();
}
discoveredInputs = discoveryBuilder.build().discoverInputsFromDotdFiles(execRoot, scanningContext.getArtifactResolver());
}
// Clear in-memory .d files early.
reply = null;
// depends on.
try {
validateInclusions(discoveredInputs, actionExecutionContext.getArtifactExpander(), executor.getEventHandler());
} catch (ActionExecutionException e) {
// TODO(bazel-team): (2009) make this into an error, once most of the current warnings
// are fixed.
executor.getEventHandler().handle(Event.warn(getOwner().getLocation(), e.getMessage() + ";\n this warning may eventually become an error"));
}
updateActionInputs(discoveredInputs);
// Generate a fake ".o" file containing the command line needed to generate
// the real object file.
LOG.info("Generating " + outputFile);
// A cc_fake_binary rule generates fake .o files and a fake target file,
// which merely contain instructions on building the real target. We need to
// be careful to use a new set of output file names in the instructions, as
// to not overwrite the fake output files when someone tries to follow the
// instructions. As the real compilation is executed by the test from its
// runfiles directory (where writing is forbidden), we patch the command
// line to write to $TEST_TMPDIR instead.
final String outputPrefix = "$TEST_TMPDIR/";
String argv = Joiner.on(' ').join(Iterables.transform(getArgv(outputFile.getExecPath()), new Function<String, String>() {
@Override
public String apply(String input) {
String result = ShellEscaper.escapeString(input);
// -c <tempOutputFile>, but here it has to be outputFile, so we replace it.
if (input.equals(tempOutputFile.getPathString())) {
result = outputPrefix + ShellEscaper.escapeString(outputFile.getExecPathString());
}
if (input.equals(outputFile.getExecPathString()) || input.equals(getDotdFile().getSafeExecPath().getPathString())) {
result = outputPrefix + ShellEscaper.escapeString(input);
}
return result;
}
}));
// the compilation would fail.
try {
// Ensure that the .d file and .o file are siblings, so that the "mkdir" below works for
// both.
Preconditions.checkState(outputFile.getExecPath().getParentDirectory().equals(getDotdFile().getSafeExecPath().getParentDirectory()));
FileSystemUtils.writeContent(outputFile.getPath(), ISO_8859_1, outputFile.getPath().getBaseName() + ": " + "mkdir -p " + outputPrefix + "$(dirname " + outputFile.getExecPath() + ")" + " && " + argv + "\n");
} catch (IOException e) {
throw new ActionExecutionException("failed to create fake compile command for rule '" + getOwner().getLabel() + ": " + e.getMessage(), this, false);
}
}
use of com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible in project bazel by bazelbuild.
the class BuildView method update.
@ThreadCompatible
public AnalysisResult update(LoadingResult loadingResult, BuildConfigurationCollection configurations, List<String> aspects, Options viewOptions, TopLevelArtifactContext topLevelOptions, ExtendedEventHandler eventHandler, EventBus eventBus) throws ViewCreationFailedException, InterruptedException {
LOG.info("Starting analysis");
pollInterruptedStatus();
skyframeBuildView.resetEvaluatedConfiguredTargetKeysSet();
Collection<Target> targets = loadingResult.getTargets();
eventBus.post(new AnalysisPhaseStartedEvent(targets));
skyframeBuildView.setConfigurations(configurations);
// Determine the configurations.
List<TargetAndConfiguration> topLevelTargetsWithConfigs = nodesForTopLevelTargets(configurations, targets, eventHandler);
List<ConfiguredTargetKey> topLevelCtKeys = Lists.transform(topLevelTargetsWithConfigs, new Function<TargetAndConfiguration, ConfiguredTargetKey>() {
@Override
public ConfiguredTargetKey apply(TargetAndConfiguration node) {
return new ConfiguredTargetKey(node.getLabel(), node.getConfiguration());
}
});
List<AspectValueKey> aspectKeys = new ArrayList<>();
for (String aspect : aspects) {
// Syntax: label%aspect
int delimiterPosition = aspect.indexOf('%');
if (delimiterPosition >= 0) {
// TODO(jfield): For consistency with Skylark loads, the aspect should be specified
// as an absolute path. Also, we probably need to do at least basic validation of
// path well-formedness here.
String bzlFileLoadLikeString = aspect.substring(0, delimiterPosition);
if (!bzlFileLoadLikeString.startsWith("//") && !bzlFileLoadLikeString.startsWith("@")) {
// "Legacy" behavior of '--aspects' parameter.
bzlFileLoadLikeString = new PathFragment("/" + bzlFileLoadLikeString).toString();
if (bzlFileLoadLikeString.endsWith(".bzl")) {
bzlFileLoadLikeString = bzlFileLoadLikeString.substring(0, bzlFileLoadLikeString.length() - ".bzl".length());
}
}
SkylarkImport skylarkImport;
try {
skylarkImport = SkylarkImports.create(bzlFileLoadLikeString);
} catch (SkylarkImportSyntaxException e) {
throw new ViewCreationFailedException(String.format("Invalid aspect '%s': %s", aspect, e.getMessage()), e);
}
String skylarkFunctionName = aspect.substring(delimiterPosition + 1);
for (TargetAndConfiguration targetSpec : topLevelTargetsWithConfigs) {
if (!(targetSpec.getTarget() instanceof Rule)) {
continue;
}
aspectKeys.add(AspectValue.createSkylarkAspectKey(targetSpec.getLabel(), // aspect and the base target while the top-level configuration is untrimmed.
targetSpec.getConfiguration(), targetSpec.getConfiguration(), skylarkImport, skylarkFunctionName));
}
} else {
final NativeAspectClass aspectFactoryClass = ruleClassProvider.getNativeAspectClassMap().get(aspect);
if (aspectFactoryClass != null) {
for (TargetAndConfiguration targetSpec : topLevelTargetsWithConfigs) {
if (!(targetSpec.getTarget() instanceof Rule)) {
continue;
}
// For invoking top-level aspects, use the top-level configuration for both the
// aspect and the base target while the top-level configuration is untrimmed.
BuildConfiguration configuration = targetSpec.getConfiguration();
aspectKeys.add(AspectValue.createAspectKey(targetSpec.getLabel(), configuration, new AspectDescriptor(aspectFactoryClass, AspectParameters.EMPTY), configuration));
}
} else {
throw new ViewCreationFailedException("Aspect '" + aspect + "' is unknown");
}
}
}
skyframeExecutor.injectWorkspaceStatusData(loadingResult.getWorkspaceName());
SkyframeAnalysisResult skyframeAnalysisResult;
try {
skyframeAnalysisResult = skyframeBuildView.configureTargets(eventHandler, topLevelCtKeys, aspectKeys, eventBus, viewOptions.keepGoing, viewOptions.loadingPhaseThreads);
setArtifactRoots(skyframeAnalysisResult.getPackageRoots());
} finally {
skyframeBuildView.clearInvalidatedConfiguredTargets();
}
int numTargetsToAnalyze = topLevelTargetsWithConfigs.size();
int numSuccessful = skyframeAnalysisResult.getConfiguredTargets().size();
if (0 < numSuccessful && numSuccessful < numTargetsToAnalyze) {
String msg = String.format("Analysis succeeded for only %d of %d top-level targets", numSuccessful, numTargetsToAnalyze);
eventHandler.handle(Event.info(msg));
LOG.info(msg);
}
AnalysisResult result = createResult(eventHandler, loadingResult, topLevelOptions, viewOptions, skyframeAnalysisResult);
LOG.info("Finished analysis");
return result;
}
use of com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible in project bazel by bazelbuild.
the class CppCompileAction method execute.
@Override
@ThreadCompatible
public void execute(ActionExecutionContext actionExecutionContext) throws ActionExecutionException, InterruptedException {
setModuleFileFlags();
Executor executor = actionExecutionContext.getExecutor();
CppCompileActionContext.Reply reply;
try {
reply = executor.getContext(actionContext).execWithReply(this, actionExecutionContext);
} catch (ExecException e) {
throw e.toActionExecutionException("C++ compilation of rule '" + getOwner().getLabel() + "'", executor.getVerboseFailures(), this);
}
ensureCoverageNotesFilesExist();
// This is the .d file scanning part.
IncludeScanningContext scanningContext = executor.getContext(IncludeScanningContext.class);
Path execRoot = executor.getExecRoot();
NestedSet<Artifact> discoveredInputs = discoverInputsFromDotdFiles(execRoot, scanningContext.getArtifactResolver(), reply);
// Clear in-memory .d files early.
reply = null;
// Post-execute "include scanning", which modifies the action inputs to match what the compile
// action actually used by incorporating the results of .d file parsing.
updateActionInputs(discoveredInputs);
// HeadersCheckingMode.NONE should only be used for ObjC build actions.
if (cppSemantics.needsIncludeValidation()) {
validateInclusions(discoveredInputs, actionExecutionContext.getArtifactExpander(), executor.getEventHandler());
}
}
Aggregations