diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build')
6 files changed, 115 insertions, 9 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java b/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java index 7475baf6f2..fde2683978 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java @@ -175,7 +175,7 @@ abstract class BinaryLinkingTargetFactory implements RuleConfiguredTargetFactory CompilationArtifacts compilationArtifacts = CompilationSupport.compilationArtifacts(ruleContext); - return new ObjcCommon.Builder(ruleContext) + ObjcCommon.Builder builder = new ObjcCommon.Builder(ruleContext) .setCompilationAttributes(new CompilationAttributes(ruleContext)) .setResourceAttributes(new ResourceAttributes(ruleContext)) .setCompilationArtifacts(compilationArtifacts) @@ -188,7 +188,12 @@ abstract class BinaryLinkingTargetFactory implements RuleConfiguredTargetFactory .setIntermediateArtifacts(intermediateArtifacts) .setAlwayslink(false) .addExtraImportLibraries(ObjcRuleClasses.j2ObjcLibraries(ruleContext)) - .setLinkedBinary(intermediateArtifacts.singleArchitectureBinary()) - .build(); + .setLinkedBinary(intermediateArtifacts.singleArchitectureBinary()); + + if (ObjcRuleClasses.objcConfiguration(ruleContext).generateDebugSymbols()) { + builder.setBreakpadFile(intermediateArtifacts.breakpadSym()); + } + + return builder.build(); } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java index ee1a3edf88..9e1372e8d4 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java @@ -258,6 +258,13 @@ final class IntermediateArtifacts { } /** + * Breakpad debug symbol representation for a specific architecture. + */ + public Artifact breakpadSym(String arch) { + return appendExtension(String.format("_%s.breakpad", arch)); + } + + /** * Shell script that launches the binary. */ public Artifact runnerScript() { diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommon.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommon.java index c84c7291d1..775a211555 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommon.java @@ -15,6 +15,7 @@ package com.google.devtools.build.lib.rules.objc; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.ASSET_CATALOG; +import static com.google.devtools.build.lib.rules.objc.ObjcProvider.BREAKPAD_FILE; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.BUNDLE_FILE; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.BUNDLE_IMPORT_DIR; import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DEFINE; @@ -214,6 +215,7 @@ public final class ObjcCommon { private boolean alwayslink; private Iterable<Artifact> extraImportLibraries = ImmutableList.of(); private Optional<Artifact> linkedBinary = Optional.absent(); + private Optional<Artifact> breakpadFile = Optional.absent(); Builder(RuleContext context) { this.context = Preconditions.checkNotNull(context); @@ -322,6 +324,15 @@ public final class ObjcCommon { return this; } + /** + * Sets a breakpad file (used by the breakpad crash reporting system) generated by this rule to + * be propagated to dependers. + */ + Builder setBreakpadFile(Artifact breakpadFile) { + this.breakpadFile = Optional.of(breakpadFile); + return this; + } + ObjcCommon build() { Iterable<BundleableFile> bundleImports = BundleableFile.bundleImportsFromRule(context); @@ -418,7 +429,8 @@ public final class ObjcCommon { } } - objcProvider.addAll(LINKED_BINARY, linkedBinary.asSet()); + objcProvider.addAll(LINKED_BINARY, linkedBinary.asSet()) + .addAll(BREAKPAD_FILE, breakpadFile.asSet()); return new ObjcCommon(context, objcProvider.build(), compilationArtifacts); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java index b9b2d00b4d..81a15e0b5c 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java @@ -275,11 +275,6 @@ public class ObjcConfiguration extends BuildConfiguration.Fragment { @Override public void reportInvalidOptions(EventHandler reporter, BuildOptions buildOptions) { - if (generateDebugSymbols && !iosMultiCpus.isEmpty()) { - reporter.handle(Event.error( - "--objc_generate_debug_symbols is not supported when --ios_multi_cpus is set")); - } - // TODO(bazel-team): Remove this constraint once getBundlingPlatform can return multiple values. Platform platform = null; for (String architecture : iosMultiCpus) { diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java index 12692ba011..ce344cf44b 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProvider.java @@ -164,6 +164,12 @@ public final class ObjcProvider implements TransitiveInfoProvider { public static final Key<Artifact> DEBUG_SYMBOLS = new Key<>(STABLE_ORDER); /** + * Generated breakpad file containing debug information used by the breakpad crash reporting + * system. + */ + public static final Key<Artifact> BREAKPAD_FILE = new Key<>(STABLE_ORDER); + + /** * Artifacts for storyboard sources. */ public static final Key<Artifact> STORYBOARD = new Key<>(STABLE_ORDER); diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java index a51e4b787e..f98185c15e 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ReleaseBundlingSupport.java @@ -21,6 +21,7 @@ import static com.google.devtools.build.lib.rules.objc.TargetDeviceFamily.UI_DEV import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.Artifact; @@ -30,6 +31,7 @@ import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.Runfiles; import com.google.devtools.build.lib.analysis.RunfilesSupport; +import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; import com.google.devtools.build.lib.analysis.actions.BinaryFileWriteAction; import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; import com.google.devtools.build.lib.analysis.actions.SpawnAction; @@ -50,6 +52,7 @@ import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.xcode.xcodegen.proto.XcodeGenProtos.XcodeprojBuildSetting; import java.util.List; +import java.util.Map.Entry; import java.util.Set; import javax.annotation.Nullable; @@ -195,6 +198,7 @@ public final class ReleaseBundlingSupport { bundleSupport.registerActions(objcProvider); registerCombineArchitecturesAction(); + registerTransformAndCopyBreakpadFilesAction(); ObjcConfiguration objcConfiguration = ObjcRuleClasses.objcConfiguration(ruleContext); Artifact ipaOutput = ruleContext.getImplicitOutputArtifact(IPA); @@ -304,6 +308,10 @@ public final class ReleaseBundlingSupport { NestedSetBuilder<Artifact> debugSymbolBuilder = NestedSetBuilder.<Artifact>stableOrder() .addTransitive(objcProvider.get(ObjcProvider.DEBUG_SYMBOLS)); + for (Artifact breakpadFile : getBreakpadFiles().values()) { + filesToBuild.add(breakpadFile); + } + if (linkedBinary == LinkedBinary.LOCAL_AND_DEPENDENCIES && ObjcRuleClasses.objcConfiguration(ruleContext).generateDebugSymbols()) { IntermediateArtifacts intermediateArtifacts = @@ -537,6 +545,59 @@ public final class ReleaseBundlingSupport { .build(ruleContext)); } + /** + * Registers the actions that transform and copy the breakpad files from the CPU-specific binaries + * that are part of this application. There are two steps involved: 1) The breakpad files have to + * be renamed to include their corresponding CPU architecture as a suffix. 2) The first line of + * the breakpad file has to be rewritten, as it has to include the name of the application instead + * of the name of the binary artifact. + * + * <p>Example:<br> + * The ios_application "PrenotCalculator" is specified to use "PrenotCalculatorBinary" as its + * binary. Assuming that the application is built for armv7 and arm64 CPUs, in the build process + * two binaries with a corresponding breakpad file each will be built: + * + * <pre>blaze-out/xyz-crosstool-ios-arm64/.../PrenotCalculatorBinary_bin + * blaze-out/xyz-crosstool-ios-arm64/.../PrenotCalculatorBinary.breakpad + * blaze-out/xyz-crosstool-ios-armv7/.../PrenotCalculatorBinary_bin + * blaze-out/xyz-crosstool-ios-armv7/.../PrenotCalculatorBinary.breakpad</pre> + * + * <p>The first line of the breakpad files will look like this: + * <pre>MODULE mac arm64 8A7A2DDD28E83E27B339E63631ADBEF30 PrenotCalculatorBinary_bin</pre> + * + * <p>For our application, we have to transform & copy these breakpad files like this: + * <pre>$ head -n1 blaze-bin/.../PrenotCalculator_arm64.breakpad + * MODULE mac arm64 8A7A2DDD28E83E27B339E63631ADBEF30 PrenotCalculator</pre> + */ + private void registerTransformAndCopyBreakpadFilesAction() { + for (Entry<Artifact, Artifact> breakpadFiles : getBreakpadFiles().entrySet()) { + ruleContext.registerAction( + new SpawnAction.Builder().setMnemonic("CopyBreakpadFile") + .setShellCommand(String.format( + // This sed command replaces the last word of the first line with the application + // name. + "sed -r \"1 s/^(MODULE \\w* \\w* \\w*).*$/\\1 %s/\" < %s > %s", + ruleContext.getLabel().getName(), breakpadFiles.getKey().getExecPathString(), + breakpadFiles.getValue().getExecPathString())) + .addInput(breakpadFiles.getKey()) + .addOutput(breakpadFiles.getValue()) + .build(ruleContext)); + } + } + + /** + * Returns a map of input breakpad artifacts from the CPU-specific binaries built for this + * ios_application to the new output breakpad artifacts. + */ + private ImmutableMap<Artifact, Artifact> getBreakpadFiles() { + ImmutableMap.Builder<Artifact, Artifact> results = ImmutableMap.builder(); + for (Entry<String, Artifact> breakpadFile : attributes.cpuSpecificBreakpadFiles().entrySet()) { + Artifact destBreakpad = intermediateArtifacts.breakpadSym(breakpadFile.getKey()); + results.put(breakpadFile.getValue(), destBreakpad); + } + return results.build(); + } + private void registerExtractTeamPrefixAction(Artifact teamPrefixFile) { ruleContext.registerAction(ObjcActionsBuilder.spawnOnDarwinActionBuilder() .setMnemonic("ExtractIosTeamPrefix") @@ -724,6 +785,26 @@ public final class ReleaseBundlingSupport { return checkNotNull(stringAttribute("bundle_id")); } + ImmutableMap<String, Artifact> cpuSpecificBreakpadFiles() { + ImmutableMap.Builder<String, Artifact> results = ImmutableMap.builder(); + if (ruleContext.attributes().has("binary", Type.LABEL)) { + for (TransitiveInfoCollection prerequisite + : ruleContext.getPrerequisites("binary", Mode.DONT_CHECK)) { + ObjcProvider prerequisiteProvider = prerequisite.getProvider(ObjcProvider.class); + if (prerequisiteProvider != null) { + Artifact sourceBreakpad = Iterables.getOnlyElement( + prerequisiteProvider.get(ObjcProvider.BREAKPAD_FILE), null); + if (sourceBreakpad != null) { + String cpu = + prerequisite.getConfiguration().getFragment(ObjcConfiguration.class).getIosCpu(); + results.put(cpu, sourceBreakpad); + } + } + } + } + return results.build(); + } + @Nullable private String stringAttribute(String attribute) { String value = ruleContext.attributes().get(attribute, Type.STRING); |