@Override public void registerActions(RuleContext ruleContext, AndroidSemantics semantics) { Preconditions.checkNotNull( apkName, "APK name must be set to create progress messages for APK actions."); if (signedApk != null) { Artifact intermediateUnsignedApk = unsignedApk; if (intermediateUnsignedApk == null) { // If the caller did not request an unsigned APK, we still need to construct one so that // we can sign it. So we make up an intermediate artifact. intermediateUnsignedApk = AndroidBinary.getDxArtifact(ruleContext, "unsigned_" + signedApk.getFilename()); } ruleContext.registerAction( buildApk(ruleContext, intermediateUnsignedApk, null, "Generating unsigned " + apkName)); Artifact apkToSign = intermediateUnsignedApk; if (zipalignApk) { apkToSign = AndroidBinary.getDxArtifact(ruleContext, "zipaligned_" + signedApk.getFilename()); ruleContext.registerAction(zipalignApk(ruleContext, intermediateUnsignedApk, apkToSign)); } ruleContext.registerAction( signApk( ruleContext, semantics.getApkDebugSigningKey(ruleContext), apkToSign, signedApk)); } else if (unsignedApk != null) { ruleContext.registerAction( buildApk(ruleContext, unsignedApk, null, "Generating unsigned " + apkName)); } }
@Override public void registerActions(RuleContext ruleContext, AndroidSemantics semantics) { Preconditions.checkNotNull( apkName, "APK name must be set to create progress messages for APK actions."); if (unsignedApk != null) { ruleContext.registerAction( buildApk(ruleContext, unsignedApk, null, "Generating unsigned " + apkName)); } if (signedApk != null) { // Legacy signing destroys zip aligning, so if zip aligning is requested we build an // intermediate APK that is signed but not zip aligned then zip align it. If zip aligning // is not requested then the output of the buildApk step is the final apk. Artifact intermediateSignedApk; if (zipalignApk) { intermediateSignedApk = AndroidBinary.getDxArtifact(ruleContext, "signed_" + signedApk.getFilename()); } else { intermediateSignedApk = signedApk; } ruleContext.registerAction( buildApk( ruleContext, intermediateSignedApk, semantics.getApkDebugSigningKey(ruleContext), "Generating signed " + apkName)); if (zipalignApk) { ruleContext.registerAction(zipalignApk(ruleContext, intermediateSignedApk, signedApk)); } } }
private void registerBundleMergeActions( Artifact ipaUnsigned, NestedSet<Artifact> bundleContentArtifacts, BundleMergeControlBytes controlBytes) { Artifact bundleMergeControlArtifact = ObjcRuleClasses.artifactByAppendingToBaseName(ruleContext, ".ipa-control"); ruleContext.registerAction( new BinaryFileWriteAction( ruleContext.getActionOwner(), bundleMergeControlArtifact, controlBytes, /*makeExecutable=*/ false)); ruleContext.registerAction( new SpawnAction.Builder() .setMnemonic("IosBundle") .setProgressMessage("Bundling iOS application: " + ruleContext.getLabel()) .setExecutable(attributes.bundleMergeExecutable()) .addInputArgument(bundleMergeControlArtifact) .addTransitiveInputs(bundleContentArtifacts) .addOutput(ipaUnsigned) .setVerboseFailuresAndSubcommandsInEnv() .build(ruleContext)); }
/** Create the actions for "--save_temps". */ private ImmutableList<Artifact> createTempsActions( Artifact source, String outputName, CppCompileActionBuilder builder, boolean usePic, boolean generateDotd, PathFragment ccRelativeName) { if (!cppConfiguration.getSaveTemps()) { return ImmutableList.of(); } String path = source.getFilename(); boolean isCFile = CppFileTypes.C_SOURCE.matches(path); boolean isCppFile = CppFileTypes.CPP_SOURCE.matches(path); if (!isCFile && !isCppFile) { return ImmutableList.of(); } ArtifactCategory category = isCFile ? ArtifactCategory.PREPROCESSED_C_SOURCE : ArtifactCategory.PREPROCESSED_CPP_SOURCE; String outputArtifactNameBase = getOutputNameBaseWith(outputName, usePic); CppCompileActionBuilder dBuilder = new CppCompileActionBuilder(builder); dBuilder.setOutputs(category, outputArtifactNameBase, generateDotd); setupCompileBuildVariables( dBuilder, usePic, ccRelativeName, source.getExecPath(), null, null, ImmutableMap.<String, String>of()); semantics.finalizeCompileActionBuilder(ruleContext, dBuilder); CppCompileAction dAction = dBuilder.build(); ruleContext.registerAction(dAction); CppCompileActionBuilder sdBuilder = new CppCompileActionBuilder(builder); sdBuilder.setOutputs(ArtifactCategory.GENERATED_ASSEMBLY, outputArtifactNameBase, generateDotd); setupCompileBuildVariables( sdBuilder, usePic, ccRelativeName, source.getExecPath(), null, null, ImmutableMap.<String, String>of()); semantics.finalizeCompileActionBuilder(ruleContext, sdBuilder); CppCompileAction sdAction = sdBuilder.build(); ruleContext.registerAction(sdAction); return ImmutableList.of(dAction.getOutputFile(), sdAction.getOutputFile()); }
/** Registers an action to copy Swift standard library dylibs into app bundle. */ private void registerSwiftStdlibActionsIfNecessary() { if (!objcProvider.is(USES_SWIFT)) { return; } ObjcConfiguration objcConfiguration = ObjcRuleClasses.objcConfiguration(ruleContext); CustomCommandLine.Builder commandLine = CustomCommandLine.builder() .addPath(intermediateArtifacts.swiftFrameworksFileZip().getExecPath()) .add("--platform") .add(IosSdkCommands.swiftPlatform(objcConfiguration)) .addExecPath("--scan-executable", intermediateArtifacts.combinedArchitectureBinary()); ruleContext.registerAction( ObjcRuleClasses.spawnOnDarwinActionBuilder(ruleContext) .setMnemonic("SwiftStdlibCopy") .setExecutable(attributes.swiftStdlibToolWrapper()) .setCommandLine(commandLine.build()) .addOutput(intermediateArtifacts.swiftFrameworksFileZip()) .addInput(intermediateArtifacts.combinedArchitectureBinary()) // TODO(dmaclach): Adding realpath and xcrunwrapper should not be required once // https://github.com/google/bazel/issues/285 is fixed. .addInput(attributes.realpath()) .addInput(CompilationSupport.xcrunwrapper(ruleContext).getExecutable()) .build(ruleContext)); }
private void registerEntitlementsVariableSubstitutionAction( Artifact in, Artifact out, Artifact prefix) { String escapedBundleId = ShellUtils.shellEscape(attributes.bundleId()); String shellCommand = "set -e && " + "PREFIX=\"$(cat " + prefix.getShellEscapedExecPathString() + ")\" && " + "sed " // Replace .* from default entitlements file with bundle ID where suitable. + "-e \"s#${PREFIX}\\.\\*#${PREFIX}." + escapedBundleId + "#g\" " // Replace some variables that people put in their own entitlements files + "-e \"s#\\$(AppIdentifierPrefix)#${PREFIX}.#g\" " + "-e \"s#\\$(CFBundleIdentifier)#" + escapedBundleId + "#g\" " + in.getShellEscapedExecPathString() + " " + "> " + out.getShellEscapedExecPathString(); ruleContext.registerAction( new SpawnAction.Builder() .setMnemonic("SubstituteIosEntitlements") .setShellCommand(shellCommand) .addInput(in) .addInput(prefix) .addOutput(out) .build(ruleContext)); }
/** * Returns the linked artifact resulting from a linking of the given type. Consults the feature * configuration to obtain an action_config that provides the artifact. If the feature * configuration provides no artifact, uses a default. * * <p>We cannot assume that the feature configuration contains an action_config for the link * action, because the linux link action depends on hardcoded values in * LinkCommandLine.getRawLinkArgv(), which are applied on the condition that an action_config is * not present. TODO(b/30393154): Assert that the given link action has an action_config. * * @throws RuleErrorException */ private Artifact getLinkedArtifact(LinkTargetType linkTargetType) throws RuleErrorException { Artifact result = null; Artifact linuxDefault = CppHelper.getLinuxLinkedArtifact(ruleContext, linkTargetType); try { String templatedName = features.getArtifactNameForCategory( linkTargetType.getLinkerOutput(), ruleContext, ImmutableMap.<String, String>of()); PathFragment artifactFragment = new PathFragment(ruleContext.getLabel().getName()) .getParentDirectory() .getRelative(templatedName); result = ruleContext.getPackageRelativeArtifact( artifactFragment, ruleContext.getConfiguration().getBinDirectory()); } catch (ExpansionException e) { ruleContext.throwWithRuleError(e.getMessage()); } // If the linked artifact is not the linux default, then a FailAction is generated for the // linux default to satisfy the requirement of the implicit output. // TODO(b/30132703): Remove the implicit outputs of cc_library. if (!result.equals(linuxDefault)) { ruleContext.registerAction( new FailAction( ruleContext.getActionOwner(), ImmutableList.of(linuxDefault), String.format( "the given toolchain supports creation of %s instead of %s", linuxDefault.getExecPathString(), result.getExecPathString()))); } return result; }
/** Registers an action to generate a runner script based on a template. */ ReleaseBundlingSupport registerGenerateRunnerScriptAction( Artifact runnerScript, Artifact ipaInput) { ObjcConfiguration objcConfiguration = ObjcRuleClasses.objcConfiguration(ruleContext); String escapedSimDevice = ShellUtils.shellEscape(objcConfiguration.getIosSimulatorDevice()); String escapedSdkVersion = ShellUtils.shellEscape(objcConfiguration.getIosSimulatorVersion()); ImmutableList<Substitution> substitutions = ImmutableList.of( Substitution.of("%app_name%", ruleContext.getLabel().getName()), Substitution.of("%ipa_file%", ipaInput.getRootRelativePath().getPathString()), Substitution.of("%sim_device%", escapedSimDevice), Substitution.of("%sdk_version%", escapedSdkVersion), Substitution.of("%iossim%", attributes.iossim().getRootRelativePath().getPathString()), Substitution.of( "%std_redirect_dylib_path%", attributes.stdRedirectDylib().getRootRelativePath().getPathString())); ruleContext.registerAction( new TemplateExpansionAction( ruleContext.getActionOwner(), attributes.runnerScriptTemplate(), runnerScript, substitutions, true)); return this; }
public ApplicationManifest createSplitManifest( RuleContext ruleContext, String splitName, boolean hasCode) { // aapt insists that manifests be called AndroidManifest.xml, even though they have to be // explicitly designated as manifests on the command line Artifact result = AndroidBinary.getDxArtifact(ruleContext, "split_" + splitName + "/AndroidManifest.xml"); SpawnAction.Builder builder = new SpawnAction.Builder() .setExecutable( ruleContext.getExecutablePrerequisite("$build_split_manifest", Mode.HOST)) .setProgressMessage("Creating manifest for split " + splitName) .setMnemonic("AndroidBuildSplitManifest") .addArgument("--main_manifest") .addInputArgument(manifest) .addArgument("--split_manifest") .addOutputArgument(result) .addArgument("--split") .addArgument(splitName) .addArgument(hasCode ? "--hascode" : "--nohascode"); String overridePackage = getOverridePackage(ruleContext); if (overridePackage != null) { builder.addArgument("--override_package").addArgument(overridePackage); } ruleContext.registerAction(builder.build(ruleContext)); return new ApplicationManifest(result); }
public ApplicationManifest addStubApplication(RuleContext ruleContext) { Artifact stubManifest = ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.STUB_APPLICATON_MANIFEST); SpawnAction.Builder builder = new SpawnAction.Builder() .setExecutable(ruleContext.getExecutablePrerequisite("$stubify_manifest", Mode.HOST)) .setProgressMessage("Injecting stub application") .setMnemonic("InjectStubApplication") .addArgument("--input_manifest") .addInputArgument(manifest) .addArgument("--output_manifest") .addOutputArgument(stubManifest) .addArgument("--output_datafile") .addOutputArgument( ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.STUB_APPLICATION_DATA)); String overridePackage = getOverridePackage(ruleContext); if (overridePackage != null) { builder.addArgument("--override_package"); builder.addArgument(overridePackage); } ruleContext.registerAction(builder.build(ruleContext)); return new ApplicationManifest(stubManifest); }
private void registerProtoInputListFileAction() { ruleContext.registerAction( new FileWriteAction( ruleContext.getActionOwner(), getProtoInputListFile(), getProtoInputListFileContents(), false)); }
private void registerAutomaticPlistAction() { ruleContext.registerAction( new FileWriteAction( ruleContext.getActionOwner(), getGeneratedAutomaticPlist(), automaticEntries().toASCIIPropertyList(), /*makeExecutable=*/ false)); }
private void registerGenerateProtoFilesAction() { ruleContext.registerAction( ObjcRuleClasses.spawnOnDarwinActionBuilder() .setMnemonic("GenObjcProtos") .addInputs(getGenerateActionInputs()) .addOutputs(getGenerateActionOutputs()) .setExecutable(new PathFragment("/usr/bin/python")) .setCommandLine(getGenerateCommandLine()) .build(ruleContext)); }
private void createJarJarActions( JavaTargetAttributes.Builder attributes, ImmutableList.Builder<Artifact> jarsProducedForRuntime, Iterable<ResourceContainer> resourceContainers, String originalPackage, Artifact binaryResourcesJar) { // Now use jarjar for the rest of the resources. We need to make a copy // of the final generated resources for each of the targets included in // the transitive closure of this binary. for (ResourceContainer otherContainer : resourceContainers) { if (otherContainer.getLabel().equals(ruleContext.getLabel())) { continue; } Artifact resourcesJar = createResourceJarArtifact(ruleContext, otherContainer, ".jar"); // combined resource constants copy needs to come before library classes that may contain // their local resource constants attributes.addRuntimeClassPathEntry(resourcesJar); Artifact jarJarRuleFile = createResourceJarArtifact(ruleContext, otherContainer, ".jar_jarjar_rules.txt"); String jarJarRule = String.format("rule %s.* %s.@1", originalPackage, otherContainer.getJavaPackage()); ruleContext.registerAction( new FileWriteAction(ruleContext.getActionOwner(), jarJarRuleFile, jarJarRule, false)); FilesToRunProvider jarjar = ruleContext.getExecutablePrerequisite("$jarjar_bin", Mode.HOST); ruleContext.registerAction( new SpawnAction.Builder() .setExecutable(jarjar) .addArgument("process") .addInputArgument(jarJarRuleFile) .addInputArgument(binaryResourcesJar) .addOutputArgument(resourcesJar) .setProgressMessage("Repackaging jar") .setMnemonic("AndroidRepackageJar") .build(ruleContext)); jarsProducedForRuntime.add(resourcesJar); } }
private void registerXcodegenActions(XcodeProvider.Project project) { Artifact controlFile = ObjcRuleClasses.intermediateArtifacts(ruleContext).pbxprojControlArtifact(); ruleContext.registerAction( new BinaryFileWriteAction( ruleContext.getActionOwner(), controlFile, xcodegenControlFileBytes(project), /*makeExecutable=*/ false)); ruleContext.registerAction( new SpawnAction.Builder() .setMnemonic("GenerateXcodeproj") .setExecutable(ruleContext.getExecutablePrerequisite("$xcodegen", Mode.HOST)) .addArgument("--control") .addInputArgument(controlFile) .addOutput(ruleContext.getImplicitOutputArtifact(XcodeSupport.PBXPROJ)) .addTransitiveInputs(project.getInputsToXcodegen()) .build(ruleContext)); }
private void registerTestScriptSubstitutionAction() throws InterruptedException { // testIpa is the app actually containing the tests Artifact testIpa = testIpa(); String runMemleaks = ruleContext.getFragment(ObjcConfiguration.class).runMemleaks() ? "true" : "false"; Map<String, String> testEnv = ruleContext.getConfiguration().getTestEnv(); // The substitutions below are common for simulator and lab device. ImmutableList.Builder<Substitution> substitutions = new ImmutableList.Builder<Substitution>() .add(Substitution.of("%(memleaks)s", runMemleaks)) .add(Substitution.of("%(test_app_ipa)s", testIpa.getRootRelativePathString())) .add(Substitution.of("%(test_app_name)s", baseNameWithoutIpa(testIpa))) .add( Substitution.of("%(plugin_jars)s", Artifact.joinRootRelativePaths(":", plugins()))); substitutions.add(Substitution.ofSpaceSeparatedMap("%(test_env)s", testEnv)); // xctestIpa is the app bundle being tested Optional<Artifact> xctestIpa = xctestIpa(); if (xctestIpa.isPresent()) { substitutions .add(Substitution.of("%(xctest_app_ipa)s", xctestIpa.get().getRootRelativePathString())) .add(Substitution.of("%(xctest_app_name)s", baseNameWithoutIpa(xctestIpa.get()))); } else { substitutions .add(Substitution.of("%(xctest_app_ipa)s", "")) .add(Substitution.of("%(xctest_app_name)s", "")); } Artifact template; if (!runWithLabDevice()) { substitutions.addAll(substitutionsForSimulator()); template = ruleContext.getPrerequisiteArtifact("$test_template", Mode.TARGET); } else { substitutions.addAll(substitutionsForLabDevice()); template = testTemplateForLabDevice(); } ruleContext.registerAction( new TemplateExpansionAction( ruleContext.getActionOwner(), template, generatedTestScript(), substitutions.build(), /*executable=*/ true)); }
private ReleaseBundlingSupport registerSignBundleAction( Artifact entitlements, Artifact ipaOutput, Artifact ipaUnsigned) { // TODO(bazel-team): Support variable substitution ImmutableList.Builder<String> dirsToSign = new ImmutableList.Builder<>(); // Explicitly sign Swift dylibs. Unfortunately --deep option on codesign doesn't do this // automatically. // The order here is important. The innermost code must singed first. String bundleDir = ShellUtils.shellEscape(bundling.getBundleDir()); if (objcProvider.is(USES_SWIFT)) { dirsToSign.add(bundleDir + "/Frameworks/*"); } dirsToSign.add(bundleDir); StringBuilder codesignCommandLineBuilder = new StringBuilder(); for (String dir : dirsToSign.build()) { codesignCommandLineBuilder .append(codesignCommand(entitlements, "${t}/" + dir)) .append(" && "); } // TODO(bazel-team): Support nested code signing. String shellCommand = "set -e && " + "t=$(mktemp -d -t signing_intermediate) && " + "trap \"rm -rf ${t}\" EXIT && " // Get an absolute path since we need to cd into the temp directory for zip. + "signed_ipa=${PWD}/" + ipaOutput.getShellEscapedExecPathString() + " && " + "/usr/bin/unzip -qq " + ipaUnsigned.getShellEscapedExecPathString() + " -d ${t} && " + codesignCommandLineBuilder.toString() // Using zip since we need to preserve permissions + "cd ${t} && /usr/bin/zip -q -r \"${signed_ipa}\" ."; ruleContext.registerAction( ObjcRuleClasses.spawnBashOnDarwinActionBuilder(ruleContext, shellCommand) .setMnemonic("IosSignBundle") .setProgressMessage("Signing iOS bundle: " + ruleContext.getLabel()) .addInput(ipaUnsigned) .addInput(attributes.provisioningProfile()) .addInput(entitlements) .addOutput(ipaOutput) .build(ruleContext)); return this; }
/** * Creates an action that converts {@code jarToDex} to a dex file. The output will be stored in * the {@link com.google.devtools.build.lib.actions.Artifact} {@code dxJar}. */ public static void createDexAction( RuleContext ruleContext, Artifact jarToDex, Artifact classesDex, List<String> dexOptions, boolean multidex, Artifact mainDexList) { List<String> args = new ArrayList<>(); args.add("--dex"); // Add --no-locals to coverage builds. Older coverage tools don't correctly preserve local // variable information in stack frame maps that are required since Java 7, so to avoid runtime // errors we just don't add local variable info in the first place. This may no longer be // necessary, however, as long as we use a coverage tool that generates stack frame maps. if (ruleContext.getConfiguration().isCodeCoverageEnabled()) { args.add("--no-locals"); // TODO(bazel-team): Is this still needed? } // Multithreaded dex does not work when using --multi-dex. if (!multidex) { // Multithreaded dex tends to run faster, but only up to about 5 threads (at which point the // law of diminishing returns kicks in). This was determined experimentally, with 5-thread dex // performing about 25% faster than 1-thread dex. args.add("--num-threads=5"); } args.addAll(dexOptions); if (multidex) { args.add("--multi-dex"); if (mainDexList != null) { args.add("--main-dex-list=" + mainDexList.getExecPathString()); } } args.add("--output=" + classesDex.getExecPathString()); args.add(jarToDex.getExecPathString()); SpawnAction.Builder builder = new SpawnAction.Builder() .setExecutable(AndroidSdkProvider.fromRuleContext(ruleContext).getDx()) .addInput(jarToDex) .addOutput(classesDex) .addArguments(args) .setProgressMessage("Converting " + jarToDex.getExecPathString() + " to dex format") .setMnemonic("AndroidDexer") .setResources(ResourceSet.createWithRamCpuIo(4096.0, 5.0, 0.0)); if (mainDexList != null) { builder.addInput(mainDexList); } ruleContext.registerAction(builder.build(ruleContext)); }
private void registerExtractTeamPrefixAction(Artifact teamPrefixFile) { String shellCommand = "set -e && " + "PLIST=$(mktemp -t teamprefix.plist) && trap \"rm ${PLIST}\" EXIT && " + extractPlistCommand(attributes.provisioningProfile()) + " > ${PLIST} && " + "/usr/libexec/PlistBuddy -c 'Print ApplicationIdentifierPrefix:0' ${PLIST} > " + teamPrefixFile.getShellEscapedExecPathString(); ruleContext.registerAction( ObjcRuleClasses.spawnBashOnDarwinActionBuilder(ruleContext, shellCommand) .setMnemonic("ExtractIosTeamPrefix") .addInput(attributes.provisioningProfile()) .addOutput(teamPrefixFile) .build(ruleContext)); }
private void registerEmbedLabelPlistAction() { Artifact buildInfo = Iterables.getOnlyElement(ruleContext.getBuildInfo(ObjcBuildInfoFactory.KEY)); String generatedVersionPlistPath = getGeneratedVersionPlist().getShellEscapedExecPathString(); String shellCommand = "VERSION=\"$(" + "grep \"^" + BuildInfo.BUILD_EMBED_LABEL + "\" " + buildInfo.getShellEscapedExecPathString() + " | cut -d' ' -f2- | sed -e '" + EXTRACT_VERSION_NUMBER_SED_COMMAND + "' | " + "sed -e 's#\"#\\\"#g')\" && " + "cat >" + generatedVersionPlistPath + " <<EOF\n" + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" " + "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" + "<plist version=\"1.0\">\n" + "<dict>\n" + "EOF\n" + "if [[ -n \"${VERSION}\" ]]; then\n" + " for KEY in CFBundleVersion CFBundleShortVersionString; do\n" + " echo \" <key>${KEY}</key>\n\" >> " + generatedVersionPlistPath + "\n" + " echo \" <string>${VERSION}</string>\n\" >> " + generatedVersionPlistPath + "\n" + " done\n" + "fi\n" + "cat >>" + generatedVersionPlistPath + " <<EOF\n" + "</dict>\n" + "</plist>\n" + "EOF\n"; ruleContext.registerAction( new SpawnAction.Builder() .setMnemonic("ObjcVersionPlist") .setShellCommand(shellCommand) .addInput(buildInfo) .addOutput(getGeneratedVersionPlist()) .build(ruleContext)); }
private void registerCombineArchitecturesAction() { Artifact resultingLinkedBinary = intermediateArtifacts.combinedArchitectureBinary(); NestedSet<Artifact> linkedBinaries = linkedBinaries(); ruleContext.registerAction( ObjcRuleClasses.spawnOnDarwinActionBuilder(ruleContext) .setMnemonic("ObjcCombiningArchitectures") .addTransitiveInputs(linkedBinaries) .addOutput(resultingLinkedBinary) .setExecutable(CompilationSupport.xcrunwrapper(ruleContext)) .setCommandLine( CustomCommandLine.builder() .add(ObjcRuleClasses.LIPO) .addExecPaths("-create", linkedBinaries) .addExecPath("-o", resultingLinkedBinary) .build()) .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 \"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)); } }
private void registerLaunchStoryboardPlistAction() { String launchStoryboard = attributes.launchStoryboard().getFilename(); String launchStoryboardName = launchStoryboard.substring(0, launchStoryboard.lastIndexOf('.')); String contents = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" " + "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" + "<plist version=\"1.0\">\n" + "<dict>\n" + " <key>UILaunchStoryboardName</key>\n" + " <string>" + launchStoryboardName + "</string>\n" + "</dict>\n" + "</plist>\n"; ruleContext.registerAction( new FileWriteAction( ruleContext.getActionOwner(), getLaunchStoryboardPlist(), contents, false)); }
protected void createActions( ConfiguredTarget base, RuleContext ruleContext, Iterable<Artifact> protoSources, NestedSet<Artifact> transitiveProtoSources, Iterable<Artifact> headerMappingFiles, Iterable<Artifact> classMappingFiles, J2ObjcSource j2ObjcSource) { String genDir = ruleContext.getConfiguration().getGenfilesDirectory().getExecPathString(); Artifact compiler = ruleContext.getPrerequisiteArtifact("$protoc_darwin", Mode.HOST); Artifact j2objcPlugin = ruleContext.getPrerequisiteArtifact("$j2objc_plugin", Mode.HOST); ruleContext.registerAction( new SpawnAction.Builder() .setMnemonic("TranslatingJ2ObjcProtos") .addInput(compiler) .addInput(j2objcPlugin) .addInputs( ruleContext.getPrerequisiteArtifacts("$protoc_support_darwin", Mode.HOST).list()) .addInputs(protoSources) .addTransitiveInputs(transitiveProtoSources) .addOutputs(j2ObjcSource.getObjcSrcs()) .addOutputs(j2ObjcSource.getObjcHdrs()) .addOutputs(headerMappingFiles) .addOutputs(classMappingFiles) .setExecutable(new PathFragment("/usr/bin/python")) .setCommandLine( new CustomCommandLine.Builder() .add(compiler.getPath().toString()) .add("-w") .add(compiler.getRoot().getPath().toString()) .add("--generate-j2objc") .add("--generator-param=file_dir_mapping") .add("--generator-param=generate_class_mappings") .add("--j2objc-plugin=" + j2objcPlugin.getExecPathString()) .add("--output-dir=" + genDir) .addExecPaths(protoSources) .build()) .setExecutionInfo(ImmutableMap.of(ExecutionRequirements.REQUIRES_DARWIN, "")) .build(ruleContext)); }
private void registerEnvironmentPlistAction() { ObjcConfiguration configuration = ObjcRuleClasses.objcConfiguration(ruleContext); // Generates a .plist that contains environment values (such as the SDK used to build, the Xcode // version, etc), which are parsed from various .plist files of the OS, namely Xcodes' and // Platforms' plists. // The resulting file is meant to be merged with the final bundle. String platformWithVersion = String.format( "%s%s", configuration.getBundlingPlatform().getLowerCaseNameInPlist(), Strings.nullToEmpty(configuration.getIosSdkVersion())); ruleContext.registerAction( ObjcRuleClasses.spawnOnDarwinActionBuilder(ruleContext) .setMnemonic("EnvironmentPlist") .addInput(attributes.environmentPlistScript()) .setExecutable(attributes.environmentPlistScript()) .addArguments("--platform", platformWithVersion) .addArguments("--output", getGeneratedEnvironmentPlist().getExecPathString()) .addOutput(getGeneratedEnvironmentPlist()) .build(ruleContext)); }
private ReleaseBundlingSupport registerExtractEntitlementsAction(Artifact entitlements) { // See Apple Glossary (http://goo.gl/EkhXOb) // An Application Identifier is constructed as: TeamID.BundleID // TeamID is extracted from the provisioning profile. // BundleID consists of a reverse-DNS string to identify the app, where the last component // is the application name, and is specified as an attribute. String shellCommand = "set -e && " + "PLIST=$(mktemp -t entitlements.plist) && trap \"rm ${PLIST}\" EXIT && " + extractPlistCommand(attributes.provisioningProfile()) + " > ${PLIST} && " + "/usr/libexec/PlistBuddy -x -c 'Print Entitlements' ${PLIST} > " + entitlements.getShellEscapedExecPathString(); ruleContext.registerAction( ObjcRuleClasses.spawnBashOnDarwinActionBuilder(ruleContext, shellCommand) .setMnemonic("ExtractIosEntitlements") .setProgressMessage("Extracting entitlements: " + ruleContext.getLabel()) .addInput(attributes.provisioningProfile()) .addOutput(entitlements) .build(ruleContext)); return this; }
private AndroidStudioInfoFilesProvider createIdeBuildArtifact( ConfiguredTarget base, RuleContext ruleContext, Kind ruleKind, DependenciesResult dependenciesResult, AndroidStudioInfoFilesProvider.Builder providerBuilder) { Artifact ideInfoFile = derivedArtifact(base, ruleContext, ASWB_BUILD_SUFFIX); Artifact ideInfoTextFile = derivedArtifact(base, ruleContext, ASWB_BUILD_TEXT_SUFFIX); providerBuilder.ideInfoFilesBuilder().add(ideInfoFile); providerBuilder.ideInfoTextFilesBuilder().add(ideInfoTextFile); NestedSetBuilder<Artifact> ideResolveArtifacts = providerBuilder.ideResolveFilesBuilder(); RuleIdeInfo.Builder outputBuilder = RuleIdeInfo.newBuilder(); outputBuilder.setLabel(base.getLabel().toString()); outputBuilder.setBuildFile( ruleContext.getRule().getPackage().getBuildFile().getPath().toString()); outputBuilder.setBuildFileArtifactLocation( makeArtifactLocation(ruleContext.getRule().getPackage())); if (ruleKind != Kind.UNRECOGNIZED) { outputBuilder.setKind(ruleKind); } outputBuilder.setKindString(ruleContext.getRule().getRuleClass()); // Java rules JavaRuleOutputJarsProvider outputJarsProvider = base.getProvider(JavaRuleOutputJarsProvider.class); if (outputJarsProvider != null) { Artifact packageManifest = createPackageManifest(base, ruleContext); if (packageManifest != null) { providerBuilder.ideInfoFilesBuilder().add(packageManifest); ruleContext.registerAction( makePackageManifestAction(ruleContext, packageManifest, getJavaSources(ruleContext))); } JavaRuleIdeInfo javaRuleIdeInfo = makeJavaRuleIdeInfo( base, ruleContext, outputJarsProvider, ideResolveArtifacts, packageManifest); outputBuilder.setJavaRuleIdeInfo(javaRuleIdeInfo); } // C rules CppCompilationContext cppCompilationContext = base.getProvider(CppCompilationContext.class); if (cppCompilationContext != null) { CRuleIdeInfo cRuleIdeInfo = makeCRuleIdeInfo(base, ruleContext, cppCompilationContext); outputBuilder.setCRuleIdeInfo(cRuleIdeInfo); } // CCToolchain rule CppConfiguration cppConfiguration = getCppConfiguration(base); if (cppConfiguration != null) { CToolchainIdeInfo cToolchainIdeInfo = makeCToolchainIdeInfo(ruleContext, cppConfiguration); if (cToolchainIdeInfo != null) { outputBuilder.setCToolchainIdeInfo(cToolchainIdeInfo); } } // Android rules AndroidIdeInfoProvider androidIdeInfoProvider = base.getProvider(AndroidIdeInfoProvider.class); if (androidIdeInfoProvider != null) { outputBuilder.setAndroidRuleIdeInfo( makeAndroidRuleIdeInfo( base, androidIdeInfoProvider, dependenciesResult, ideResolveArtifacts)); } AndroidStudioInfoFilesProvider provider = providerBuilder.build(); outputBuilder.addAllDependencies(transform(dependenciesResult.deps, LABEL_TO_STRING)); outputBuilder.addAllRuntimeDeps(transform(dependenciesResult.runtimeDeps, LABEL_TO_STRING)); outputBuilder.addAllTags(base.getTarget().getAssociatedRule().getRuleTags()); final RuleIdeInfo ruleIdeInfo = outputBuilder.build(); ruleContext.registerAction( makeProtoWriteAction(ruleContext.getActionOwner(), ruleIdeInfo, ideInfoFile)); ruleContext.registerAction( makeProtoTextWriteAction(ruleContext.getActionOwner(), ruleIdeInfo, ideInfoTextFile)); return provider; }
/** Builds the action as configured. */ public void build() throws InterruptedException { ImmutableList<Artifact> classpathResources = attributes.getClassPathResources(); Set<String> classPathResourceNames = new HashSet<>(); for (Artifact artifact : classpathResources) { String name = artifact.getExecPath().getBaseName(); if (!classPathResourceNames.add(name)) { ruleContext.attributeError( "classpath_resources", "entries must have different file names (duplicate: " + name + ")"); return; } } IterablesChain<Artifact> runtimeJars = runtimeJarsBuilder.build(); // TODO(kmb): Consider not using getArchiveInputs, specifically because we don't want/need to // transform anything but the runtimeClasspath and b/c we currently do it twice here and below IterablesChain.Builder<Artifact> inputs = IterablesChain.builder(); inputs.add(getArchiveInputs(attributes, derivedJars)); inputs.add(ImmutableList.copyOf(Iterables.transform(runtimeJars, derivedJars))); if (runfilesMiddleman != null) { inputs.addElement(runfilesMiddleman); } ImmutableList<Artifact> buildInfoArtifacts = ruleContext.getBuildInfo(JavaBuildInfoFactory.KEY); inputs.add(buildInfoArtifacts); Iterable<Artifact> runtimeClasspath = Iterables.transform( Iterables.concat(runtimeJars, attributes.getRuntimeClassPathForArchive()), derivedJars); if (launcher != null) { inputs.addElement(launcher); } CommandLine commandLine = semantics.buildSingleJarCommandLine( ruleContext.getConfiguration(), outputJar, javaStartClass, deployManifestLines, buildInfoArtifacts, classpathResources, runtimeClasspath, includeBuildData, compression, launcher); List<String> jvmArgs = ImmutableList.of("-client", SINGLEJAR_MAX_MEMORY); ResourceSet resourceSet = ResourceSet.createWithRamCpuIo(/*memoryMb = */ 200.0, /*cpuUsage = */ .2, /*ioUsage=*/ .2); // If singlejar's name ends with .jar, it is Java application, otherwise it is native. // TODO(asmundak): once b/28640279 is fixed (that is, the native singlejar is released), // eliminate this check, allowing only native singlejar. Artifact singlejar = getSingleJar(ruleContext); if (singlejar.getFilename().endsWith(".jar")) { ruleContext.registerAction( new SpawnAction.Builder() .addInputs(inputs.build()) .addTransitiveInputs(JavaHelper.getHostJavabaseInputs(ruleContext)) .addOutput(outputJar) .setResources(resourceSet) .setJarExecutable( ruleContext.getHostConfiguration().getFragment(Jvm.class).getJavaExecutable(), singlejar, jvmArgs) .setCommandLine(commandLine) .alwaysUseParameterFile(ParameterFileType.SHELL_QUOTED) .setProgressMessage("Building deploy jar " + outputJar.prettyPrint()) .setMnemonic("JavaDeployJar") .setExecutionInfo(ImmutableMap.of("supports-workers", "1")) .build(ruleContext)); } else { ruleContext.registerAction( new SpawnAction.Builder() .addInputs(inputs.build()) .addTransitiveInputs(JavaHelper.getHostJavabaseInputs(ruleContext)) .addOutput(outputJar) .setResources(resourceSet) .setExecutable(singlejar) .setCommandLine(commandLine) .alwaysUseParameterFile(ParameterFileType.SHELL_QUOTED) .setProgressMessage("Building deploy jar " + outputJar.prettyPrint()) .setMnemonic("JavaDeployJar") .build(ruleContext)); } }
/** Create context for cc compile action from generated inputs. */ private CppCompilationContext initializeCppCompilationContext(CppModel model) { CppCompilationContext.Builder contextBuilder = new CppCompilationContext.Builder(ruleContext); // Setup the include path; local include directories come before those inherited from deps or // from the toolchain; in case of aliasing (same include file found on different entries), // prefer the local include rather than the inherited one. // Add in the roots for well-formed include names for source files and // generated files. It is important that the execRoot (EMPTY_FRAGMENT) comes // before the genfilesFragment to preferably pick up source files. Otherwise // we might pick up stale generated files. PathFragment repositoryPath = ruleContext.getLabel().getPackageIdentifier().getRepository().getPathFragment(); contextBuilder.addQuoteIncludeDir(repositoryPath); contextBuilder.addQuoteIncludeDir( ruleContext.getConfiguration().getGenfilesFragment().getRelative(repositoryPath)); for (PathFragment systemIncludeDir : systemIncludeDirs) { contextBuilder.addSystemIncludeDir(systemIncludeDir); } for (PathFragment includeDir : includeDirs) { contextBuilder.addIncludeDir(includeDir); } contextBuilder.mergeDependentContexts( AnalysisUtils.getProviders(deps, CppCompilationContext.class)); CppHelper.mergeToolchainDependentContext(ruleContext, contextBuilder); // But defines come after those inherited from deps. contextBuilder.addDefines(defines); // There are no ordering constraints for declared include dirs/srcs, or the pregrepped headers. contextBuilder.addDeclaredIncludeSrcs(publicHeaders); contextBuilder.addDeclaredIncludeSrcs(publicTextualHeaders); contextBuilder.addDeclaredIncludeSrcs(privateHeaders); contextBuilder.addPregreppedHeaderMap( CppHelper.createExtractInclusions(ruleContext, semantics, publicHeaders)); contextBuilder.addPregreppedHeaderMap( CppHelper.createExtractInclusions(ruleContext, semantics, publicTextualHeaders)); contextBuilder.addPregreppedHeaderMap( CppHelper.createExtractInclusions(ruleContext, semantics, privateHeaders)); contextBuilder.addCompilationPrerequisites(prerequisites); // Add this package's dir to declaredIncludeDirs, & this rule's headers to declaredIncludeSrcs // Note: no include dir for STRICT mode. if (headersCheckingMode == HeadersCheckingMode.WARN) { contextBuilder.addDeclaredIncludeWarnDir(ruleContext.getLabel().getPackageFragment()); for (PathFragment looseIncludeDir : looseIncludeDirs) { contextBuilder.addDeclaredIncludeWarnDir(looseIncludeDir); } } else if (headersCheckingMode == HeadersCheckingMode.LOOSE) { contextBuilder.addDeclaredIncludeDir(ruleContext.getLabel().getPackageFragment()); for (PathFragment looseIncludeDir : looseIncludeDirs) { contextBuilder.addDeclaredIncludeDir(looseIncludeDir); } } if (featureConfiguration.isEnabled(CppRuleClasses.MODULE_MAPS)) { CppModuleMap cppModuleMap = CppHelper.addCppModuleMapToContext(ruleContext, contextBuilder); // TODO(bazel-team): addCppModuleMapToContext second-guesses whether module maps should // actually be enabled, so we need to double-check here. Who would write code like this? if (cppModuleMap != null) { CppModuleMapAction action = new CppModuleMapAction( ruleContext.getActionOwner(), cppModuleMap, privateHeaders, publicHeaders, collectModuleMaps(), additionalExportedHeaders, featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULES), featureConfiguration.isEnabled(CppRuleClasses.MODULE_MAP_HOME_CWD), featureConfiguration.isEnabled(CppRuleClasses.GENERATE_SUBMODULES), !featureConfiguration.isEnabled(CppRuleClasses.MODULE_MAP_WITHOUT_EXTERN_MODULE)); ruleContext.registerAction(action); } if (model.getGeneratesPicHeaderModule()) { contextBuilder.setPicHeaderModule(model.getPicHeaderModule(cppModuleMap.getArtifact())); } if (model.getGeneratesNoPicHeaderModule()) { contextBuilder.setHeaderModule(model.getHeaderModule(cppModuleMap.getArtifact())); } if (featureConfiguration.isEnabled(CppRuleClasses.USE_HEADER_MODULES) && featureConfiguration.isEnabled(CppRuleClasses.TRANSITIVE_MODULE_MAPS)) { contextBuilder.setProvideTransitiveModuleMaps(true); } } semantics.setupCompilationContext(ruleContext, contextBuilder); return contextBuilder.build(); }