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)); }
/** {@link CppModuleMap} that provides the clang module map for this target. */ public CppModuleMap moduleMap() { String moduleName = ruleContext.getLabel().toString().replace("//", "").replace("/", "_").replace(":", "_"); // To get Swift to pick up module maps, we need to name them "module.modulemap" and have their // parent directory in the module map search paths. return new CppModuleMap(appendExtensionInGenfiles(".modulemaps/module.modulemap"), moduleName); }
/** * 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; }
/** * Creates a middleman for the compilation prerequisites. * * @return the middleman or null if there are no prerequisites */ private Artifact createMiddleman(ActionOwner owner, MiddlemanFactory middlemanFactory) { if (compilationPrerequisites.isEmpty()) { return null; } // Compilation prerequisites gathered in the compilationPrerequisites // must be generated prior to executing C++ compilation step that depends // on them (since these prerequisites include all potential header files, etc // that could be referenced during compilation). So there is a definite need // to ensure scheduling edge dependency. However, those prerequisites should // have no effect on the decision whether C++ compilation should happen in // the first place - only CppCompileAction outputs (*.o and *.d files) and // all files referenced by the *.d file should be used to make that decision. // If this action was never executed, then *.d file would be missing, forcing // compilation to occur. If *.d file is present and has not changed then the // only reason that would force us to re-compile would be change in one of // the files referenced by the *.d file, since no other files participated // in the compilation. We also need to propagate errors through this // dependency link. So we use an error propagating middleman. // Such middleman will be ignored by the dependency checker yet will still // represent an edge in the action dependency graph - forcing proper execution // order and error propagation. return middlemanFactory.createErrorPropagatingMiddleman( owner, ruleContext.getLabel().toString(), purpose, ImmutableList.copyOf(compilationPrerequisites), ruleContext .getConfiguration() .getMiddlemanDirectory(ruleContext.getRule().getRepository())); }
private Artifact inUniqueObjsDir(Artifact source, String extension) { PathFragment uniqueDir = new PathFragment("_objs").getRelative(ruleContext.getLabel().getName()); PathFragment sourceFile = uniqueDir.getRelative(source.getRootRelativePath()); PathFragment scopeRelativePath = FileSystemUtils.replaceExtension(sourceFile, extension); return scopedArtifact(scopeRelativePath); }
private static PathFragment getOutputFilePath( ConfiguredTarget base, RuleContext ruleContext, String suffix) { PathFragment packagePathFragment = ruleContext.getLabel().getPackageIdentifier().getPathFragment(); String name = base.getLabel().getName(); return new PathFragment(packagePathFragment, new PathFragment(name + suffix)); }
/** * Create a Rule Configured Target from the ruleContext and the ruleImplementation. The * registeredProviderTypes map indicates which keys in structs returned by skylark rules should be * interpreted as native TransitiveInfoProvider instances of type (map value). */ public static ConfiguredTarget buildRule( RuleContext ruleContext, BaseFunction ruleImplementation, Map<String, Class<? extends TransitiveInfoProvider>> registeredProviderTypes) throws InterruptedException { String expectFailure = ruleContext.attributes().get("expect_failure", Type.STRING); try (Mutability mutability = Mutability.create("configured target")) { SkylarkRuleContext skylarkRuleContext = new SkylarkRuleContext(ruleContext, Kind.RULE); Environment env = Environment.builder(mutability) .setSkylark() .setCallerLabel(ruleContext.getLabel()) .setGlobals( ruleContext .getRule() .getRuleClassObject() .getRuleDefinitionEnvironment() .getGlobals()) .setEventHandler(ruleContext.getAnalysisEnvironment().getEventHandler()) .build(); // NB: loading phase functions are not available: this is analysis already, // so we do *not* setLoadingPhase(). Object target = ruleImplementation.call( ImmutableList.<Object>of(skylarkRuleContext), ImmutableMap.<String, Object>of(), /*ast=*/ null, env); if (ruleContext.hasErrors()) { return null; } else if (!(target instanceof SkylarkClassObject) && target != Runtime.NONE && !(target instanceof Iterable)) { ruleContext.ruleError( String.format( "Rule should return a return a struct or a list, but got %s", SkylarkType.typeOf(target))); return null; } else if (!expectFailure.isEmpty()) { ruleContext.ruleError("Expected failure not found: " + expectFailure); return null; } ConfiguredTarget configuredTarget = createTarget(ruleContext, target, registeredProviderTypes); SkylarkProviderValidationUtil.checkOrphanArtifacts(ruleContext); return configuredTarget; } catch (EvalException e) { addRuleToStackTrace(e, ruleContext.getRule(), ruleImplementation); // If the error was expected, return an empty target. if (!expectFailure.isEmpty() && getMessageWithoutStackTrace(e).matches(expectFailure)) { return new com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder(ruleContext) .add(RunfilesProvider.class, RunfilesProvider.EMPTY) .build(); } ruleContext.ruleError("\n" + e.print()); return null; } }
public RuleConfiguredTargetBuilder addTransitiveInfoProviders( RuleConfiguredTargetBuilder builder, AndroidSemantics androidSemantics, ResourceApk resourceApk, Artifact zipAlignedApk, Iterable<Artifact> apksUnderTest) { javaCommon.addTransitiveInfoProviders(builder, filesToBuild, classJar, ANDROID_COLLECTION_SPEC); javaCommon.addGenJarsProvider(builder, genClassJar, genSourceJar); idlHelper.addTransitiveInfoProviders(builder, classJar, manifestProtoOutput); JavaRuleOutputJarsProvider.Builder outputJarsBuilder = JavaRuleOutputJarsProvider.builder() .addOutputJar(classJar, iJar, srcJar) .setJdeps(outputDepsProto); OutputJar resourceJar = null; if (resourceClassJar != null && resourceIJar != null && resourceSourceJar != null) { resourceJar = new OutputJar(resourceClassJar, resourceIJar, resourceSourceJar); outputJarsBuilder.addOutputJar(resourceJar); } return builder .setFilesToBuild(filesToBuild) .add(JavaRuleOutputJarsProvider.class, outputJarsBuilder.build()) .add( JavaRuntimeJarProvider.class, new JavaRuntimeJarProvider(javaCommon.getJavaCompilationArtifacts().getRuntimeJars())) .add(RunfilesProvider.class, RunfilesProvider.simple(getRunfiles())) .add(AndroidResourcesProvider.class, resourceApk.toResourceProvider(ruleContext.getLabel())) .add( AndroidIdeInfoProvider.class, createAndroidIdeInfoProvider( ruleContext, androidSemantics, idlHelper, resourceJar, resourceApk, zipAlignedApk, apksUnderTest)) .add( JavaCompilationArgsProvider.class, new JavaCompilationArgsProvider( javaCompilationArgs, recursiveJavaCompilationArgs, compileTimeDependencyArtifacts, NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER))) .add( JackLibraryProvider.class, asNeverLink ? jackCompilationHelper.compileAsNeverlinkLibrary() : jackCompilationHelper.compileAsLibrary()) .addSkylarkTransitiveInfo(AndroidSkylarkApiProvider.NAME, new AndroidSkylarkApiProvider()) .addOutputGroup( OutputGroupProvider.HIDDEN_TOP_LEVEL, collectHiddenTopLevelArtifacts(ruleContext)) .addOutputGroup(JavaSemantics.SOURCE_JARS_OUTPUT_GROUP, transitiveSourceJars); }
/** * Adds the given targets as dependencies - this can include explicit dependencies on other rules * (like from a "deps" attribute) and also implicit dependencies on runtime libraries. */ public CcLibraryHelper addDeps(Iterable<? extends TransitiveInfoCollection> deps) { for (TransitiveInfoCollection dep : deps) { Preconditions.checkArgument( dep.getConfiguration() == null || configuration.equalsOrIsSupersetOf(dep.getConfiguration()), "dep " + dep.getLabel() + " has a different config than " + ruleContext.getLabel()); this.deps.add(dep); } return this; }
/** * Returns the same set of artifacts as createMiddleman() would, but without actually creating * middlemen. */ private Artifact getMiddlemanArtifact(MiddlemanFactory middlemanFactory) { if (compilationPrerequisites.isEmpty()) { return null; } return middlemanFactory.getErrorPropagatingMiddlemanArtifact( ruleContext.getLabel().toString(), purpose, ruleContext .getConfiguration() .getMiddlemanDirectory(ruleContext.getRule().getRepository())); }
@Override public ConfiguredAspect create( ConfiguredTarget base, RuleContext ruleContext, AspectParameters parameters) { String information = parameters.isEmpty() ? "" : " data " + Iterables.getFirst(parameters.getAttribute("baz"), null); return new ConfiguredAspect.Builder(getClass().getName(), ruleContext) .addProvider( AspectInfo.class, new AspectInfo( collectAspectData("aspect " + ruleContext.getLabel() + information, ruleContext))) .build(); }
/** * Creates a new application support within the given rule context. * * <p>{@code bundleName} defaults to label name * * @param ruleContext context for the application-generating rule * @param objcProvider provider containing all dependencies' information as well as some of this * rule's * @param linkedBinary whether to look for a linked binary from this rule and dependencies or just * the latter * @param bundleDirFormat format string representing the bundle's directory with a single * placeholder for the target name (e.g. {@code "Payload/%s.app"}) * @param bundleMinimumOsVersion the minimum OS version this bundle's plist should be generated * for (<b>not</b> the minimum OS version its binary is compiled with, that needs to be set * through the configuration) */ ReleaseBundlingSupport( RuleContext ruleContext, ObjcProvider objcProvider, LinkedBinary linkedBinary, String bundleDirFormat, String bundleMinimumOsVersion) { this( ruleContext, objcProvider, linkedBinary, bundleDirFormat, ruleContext.getLabel().getName(), bundleMinimumOsVersion); }
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; }
/** * Adds common xcode settings to the given provider builder, explicitly specifying architecture to * use. * * @param objcProvider provider containing all dependencies' information as well as some of this * rule's * @param productType type of this rule's Xcode target * @param architecture architecture to filter all dependencies with (only matching ones will be * included in the final targets generated) * @param configurationDistinguisher distinguisher that will cause this target's xcode provider to * discard any dependencies from sources that are tagged with a different distinguisher * @return this xcode support */ XcodeSupport addXcodeSettings( Builder xcodeProviderBuilder, ObjcProvider objcProvider, XcodeProductType productType, String architecture, ConfigurationDistinguisher configurationDistinguisher) { xcodeProviderBuilder .setLabel(ruleContext.getLabel()) .setArchitecture(architecture) .setConfigurationDistinguisher(configurationDistinguisher) .setObjcProvider(objcProvider) .setProductType(productType) .addXcodeprojBuildSettings(XcodeSupport.defaultXcodeSettings()); return this; }
private void createFakeSourceAction( String outputName, CcCompilationOutputs.Builder result, AnalysisEnvironment env, CppCompileActionBuilder builder, ArtifactCategory outputCategory, boolean addObject, PathFragment ccRelativeName, PathFragment execPath, boolean usePic, boolean generateDotd) { String outputNameBase = getOutputNameBaseWith(outputName, usePic); String tempOutputName = ruleContext .getConfiguration() .getBinFragment() .getRelative(CppHelper.getObjDirectory(ruleContext.getLabel())) .getRelative( CppHelper.getCompileArtifactName( ruleContext, outputCategory, getOutputNameBaseWith(outputName + ".temp", usePic))) .getPathString(); builder .setPicMode(usePic) .setOutputs(outputCategory, outputNameBase, generateDotd) .setTempOutputFile(new PathFragment(tempOutputName)); setupCompileBuildVariables( builder, usePic, ccRelativeName, execPath, /*gcnoFile=*/ null, /*dwoFile=*/ null, ImmutableMap.<String, String>of()); semantics.finalizeCompileActionBuilder(ruleContext, builder); CppCompileAction action = builder.build(); env.registerAction(action); if (addObject) { if (usePic) { result.addPicObjectFile(action.getOutputFile()); } else { result.addObjectFile(action.getOutputFile()); } } }
private JavaCompilationHelper initAttributes( JavaTargetAttributes.Builder attributes, JavaSemantics semantics) { JavaCompilationHelper helper = new JavaCompilationHelper(ruleContext, semantics, javaCommon.getJavacOpts(), attributes); helper.addLibrariesToAttributes(javaCommon.targetsTreatedAsDeps(ClasspathType.COMPILE_ONLY)); helper.addProvidersToAttributes( JavaCommon.compilationArgsFromSources(ruleContext), asNeverLink); attributes.setStrictJavaDeps(getStrictAndroidDeps()); attributes.setRuleKind(ruleContext.getRule().getRuleClass()); attributes.setTargetLabel(ruleContext.getLabel()); JavaCommon.validateConstraint( ruleContext, "android", javaCommon.targetsTreatedAsDeps(ClasspathType.BOTH)); ruleContext.checkSrcsSamePackage(true); return helper; }
/** Returns the include paths for the generated protos. */ public ImmutableSet<PathFragment> getUserHeaderSearchPaths() { PathFragment workspaceRelativeOutputDir = getWorkspaceRelativeOutputDir(); ImmutableSet.Builder<PathFragment> searchPathEntriesBuilder = new ImmutableSet.Builder<PathFragment>().add(workspaceRelativeOutputDir); if (attributes.needsPerProtoIncludes()) { PathFragment generatedProtoDir = new PathFragment(workspaceRelativeOutputDir, ruleContext.getLabel().getPackageFragment()); searchPathEntriesBuilder .add(generatedProtoDir) .addAll(Iterables.transform(getGeneratedHeaders(), PARENT_PATHFRAGMENT)); } return searchPathEntriesBuilder.build(); }
@Override public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException { RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(ruleContext) .addProvider( RuleInfo.class, new RuleInfo(collectAspectData("rule " + ruleContext.getLabel(), ruleContext))) .setFilesToBuild(NestedSetBuilder.<Artifact>create(Order.STABLE_ORDER)) .setRunfilesSupport(null, null) .add(RunfilesProvider.class, RunfilesProvider.simple(Runfiles.EMPTY)); if (ruleContext.getRule().getRuleClassObject().getName().equals("honest")) { builder.addProvider(RequiredProvider.class, new RequiredProvider()); } return builder.build(); }
/** * 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 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); } }
@Override public ConfiguredAspect create( ConfiguredTarget base, RuleContext ruleContext, AspectParameters parameters) { StringBuilder information = new StringBuilder("aspect " + ruleContext.getLabel()); if (!parameters.isEmpty()) { information.append(" data " + Iterables.getFirst(parameters.getAttribute("baz"), null)); information.append(" "); } List<? extends TransitiveInfoCollection> deps = ruleContext.getPrerequisites("$dep", Mode.TARGET); information.append("$dep:["); for (TransitiveInfoCollection dep : deps) { information.append(" "); information.append(dep.getLabel()); } information.append("]"); return new ConfiguredAspect.Builder(getClass().getName(), ruleContext) .addProvider( AspectInfo.class, new AspectInfo(collectAspectData(information.toString(), ruleContext))) .build(); }
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; }
/** * Add the corresponding files as source files. These may also be header files, in which case they * will not be compiled, but also not made visible as includes to dependent rules. */ public CcLibraryHelper addSources(Collection<Artifact> sources) { for (Artifact source : sources) { addSource(source, ruleContext.getLabel()); } return this; }
/** Debug symbol file generated for a linked binary, for a specific architecture. */ public Artifact dsymSymbol(DsymOutputType dsymOutputType, String suffix) { return appendExtension( String.format( "%s/Contents/Resources/DWARF/%s_%s", dsymOutputType.getSuffix(), ruleContext.getLabel().getName(), suffix)); }
/** @return the pic header module artifact for the current target. */ public Artifact getPicHeaderModule(Artifact moduleMapArtifact) { PathFragment objectDir = CppHelper.getObjDirectory(ruleContext.getLabel()); PathFragment outputName = objectDir.getRelative(semantics.getEffectiveSourcePath(moduleMapArtifact)); return ruleContext.getRelatedArtifact(outputName, ".pic.pcm"); }
/** 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(); }
/** The {@code .a} file which contains all the compiled sources for a rule. */ public Artifact archive() { // The path will be RULE_PACKAGE/libRULEBASENAME.a String basename = new PathFragment(ruleContext.getLabel().getName()).getBaseName(); return scopedArtifact( new PathFragment(String.format("lib%s%s.a", basename, archiveFileNameSuffix))); }
@Override public ConfiguredTarget create(RuleContext ruleContext) throws RuleErrorException, InterruptedException { TransitiveInfoCollection lipoContextCollector = ruleContext.getPrerequisite(":lipo_context_collector", Mode.DONT_CHECK); if (lipoContextCollector != null && lipoContextCollector.getProvider(LipoContextProvider.class) == null) { ruleContext.ruleError("--lipo_context must point to a cc_binary or a cc_test rule"); return null; } CppConfiguration cppConfiguration = Preconditions.checkNotNull(ruleContext.getFragment(CppConfiguration.class)); Path fdoZip = ruleContext.getConfiguration().getCompilationMode() == CompilationMode.OPT ? cppConfiguration.getFdoZip() : null; SkyKey fdoKey = FdoSupportValue.key( cppConfiguration.getLipoMode(), fdoZip, cppConfiguration.getFdoInstrument()); SkyFunction.Environment skyframeEnv = ruleContext.getAnalysisEnvironment().getSkyframeEnv(); FdoSupportValue fdoSupport; try { fdoSupport = (FdoSupportValue) skyframeEnv.getValueOrThrow(fdoKey, FdoException.class, IOException.class); } catch (FdoException | IOException e) { ruleContext.ruleError("cannot initialize FDO: " + e.getMessage()); return null; } if (skyframeEnv.valuesMissing()) { return null; } final Label label = ruleContext.getLabel(); final NestedSet<Artifact> crosstool = ruleContext .getPrerequisite("all_files", Mode.HOST) .getProvider(FileProvider.class) .getFilesToBuild(); final NestedSet<Artifact> crosstoolMiddleman = getFiles(ruleContext, "all_files"); final NestedSet<Artifact> compile = getFiles(ruleContext, "compiler_files"); final NestedSet<Artifact> strip = getFiles(ruleContext, "strip_files"); final NestedSet<Artifact> objcopy = getFiles(ruleContext, "objcopy_files"); final NestedSet<Artifact> link = getFiles(ruleContext, "linker_files"); final NestedSet<Artifact> dwp = getFiles(ruleContext, "dwp_files"); final NestedSet<Artifact> libcLink = inputsForLibc(ruleContext); String purposePrefix = Actions.escapeLabel(label) + "_"; String runtimeSolibDirBase = "_solib_" + "_" + Actions.escapeLabel(label); final PathFragment runtimeSolibDir = ruleContext.getConfiguration().getBinFragment().getRelative(runtimeSolibDirBase); // Static runtime inputs. TransitiveInfoCollection staticRuntimeLibDep = selectDep(ruleContext, "static_runtime_libs", cppConfiguration.getStaticRuntimeLibsLabel()); final NestedSet<Artifact> staticRuntimeLinkInputs; final Artifact staticRuntimeLinkMiddleman; if (cppConfiguration.supportsEmbeddedRuntimes()) { staticRuntimeLinkInputs = staticRuntimeLibDep.getProvider(FileProvider.class).getFilesToBuild(); } else { staticRuntimeLinkInputs = NestedSetBuilder.emptySet(Order.STABLE_ORDER); } if (!staticRuntimeLinkInputs.isEmpty()) { NestedSet<Artifact> staticRuntimeLinkMiddlemanSet = CompilationHelper.getAggregatingMiddleman( ruleContext, purposePrefix + "static_runtime_link", staticRuntimeLibDep); staticRuntimeLinkMiddleman = staticRuntimeLinkMiddlemanSet.isEmpty() ? null : Iterables.getOnlyElement(staticRuntimeLinkMiddlemanSet); } else { staticRuntimeLinkMiddleman = null; } Preconditions.checkState( (staticRuntimeLinkMiddleman == null) == staticRuntimeLinkInputs.isEmpty()); // Dynamic runtime inputs. TransitiveInfoCollection dynamicRuntimeLibDep = selectDep( ruleContext, "dynamic_runtime_libs", cppConfiguration.getDynamicRuntimeLibsLabel()); final NestedSet<Artifact> dynamicRuntimeLinkInputs; final Artifact dynamicRuntimeLinkMiddleman; if (cppConfiguration.supportsEmbeddedRuntimes()) { NestedSetBuilder<Artifact> dynamicRuntimeLinkInputsBuilder = NestedSetBuilder.stableOrder(); for (Artifact artifact : dynamicRuntimeLibDep.getProvider(FileProvider.class).getFilesToBuild()) { if (CppHelper.SHARED_LIBRARY_FILETYPES.matches(artifact.getFilename())) { dynamicRuntimeLinkInputsBuilder.add( SolibSymlinkAction.getCppRuntimeSymlink( ruleContext, artifact, runtimeSolibDirBase, ruleContext.getConfiguration())); } else { dynamicRuntimeLinkInputsBuilder.add(artifact); } } dynamicRuntimeLinkInputs = dynamicRuntimeLinkInputsBuilder.build(); } else { dynamicRuntimeLinkInputs = NestedSetBuilder.emptySet(Order.STABLE_ORDER); } if (!dynamicRuntimeLinkInputs.isEmpty()) { List<Artifact> dynamicRuntimeLinkMiddlemanSet = CppHelper.getAggregatingMiddlemanForCppRuntimes( ruleContext, purposePrefix + "dynamic_runtime_link", dynamicRuntimeLibDep, runtimeSolibDirBase, ruleContext.getConfiguration()); dynamicRuntimeLinkMiddleman = dynamicRuntimeLinkMiddlemanSet.isEmpty() ? null : Iterables.getOnlyElement(dynamicRuntimeLinkMiddlemanSet); } else { dynamicRuntimeLinkMiddleman = null; } Preconditions.checkState( (dynamicRuntimeLinkMiddleman == null) == dynamicRuntimeLinkInputs.isEmpty()); CppCompilationContext.Builder contextBuilder = new CppCompilationContext.Builder(ruleContext); CppModuleMap moduleMap = createCrosstoolModuleMap(ruleContext); if (moduleMap != null) { contextBuilder.setCppModuleMap(moduleMap); } final CppCompilationContext context = contextBuilder.build(); boolean supportsParamFiles = ruleContext.attributes().get("supports_param_files", BOOLEAN); boolean supportsHeaderParsing = ruleContext.attributes().get("supports_header_parsing", BOOLEAN); NestedSetBuilder<Pair<String, String>> coverageEnvironment = NestedSetBuilder.compileOrder(); coverageEnvironment.add( Pair.of("COVERAGE_GCOV_PATH", cppConfiguration.getGcovExecutable().getPathString())); if (cppConfiguration.getFdoInstrument() != null) { coverageEnvironment.add( Pair.of("FDO_DIR", cppConfiguration.getFdoInstrument().getPathString())); } CcToolchainProvider provider = new CcToolchainProvider( cppConfiguration, crosstool, fullInputsForCrosstool(ruleContext, crosstoolMiddleman), compile, strip, objcopy, fullInputsForLink(ruleContext, link), dwp, libcLink, staticRuntimeLinkInputs, staticRuntimeLinkMiddleman, dynamicRuntimeLinkInputs, dynamicRuntimeLinkMiddleman, runtimeSolibDir, context, supportsParamFiles, supportsHeaderParsing, getBuildVariables(ruleContext), getBuiltinIncludes(ruleContext), coverageEnvironment.build()); RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(ruleContext) .add(CcToolchainProvider.class, provider) .add(FdoSupportProvider.class, new FdoSupportProvider(fdoSupport.getFdoSupport())) .setFilesToBuild(new NestedSetBuilder<Artifact>(Order.STABLE_ORDER).build()) .add(RunfilesProvider.class, RunfilesProvider.simple(Runfiles.EMPTY)); // If output_license is specified on the cc_toolchain rule, override the transitive licenses // with that one. This is necessary because cc_toolchain is used in the target configuration, // but it is sort-of-kind-of a tool, but various parts of it are linked into the output... // ...so we trust the judgment of the author of the cc_toolchain rule to figure out what // licenses should be propagated to C++ targets. License outputLicense = ruleContext.getRule().getToolOutputLicense(ruleContext.attributes()); if (outputLicense != null && outputLicense != License.NO_LICENSE) { final NestedSet<TargetLicense> license = NestedSetBuilder.create( Order.STABLE_ORDER, new TargetLicense(ruleContext.getLabel(), outputLicense)); LicensesProvider licensesProvider = new LicensesProvider() { @Override public NestedSet<TargetLicense> getTransitiveLicenses() { return license; } }; builder.add(LicensesProvider.class, licensesProvider); } return builder.build(); }
/** * Adds {@code headers} as public header files. These files will be made visible to dependent * rules. They may be parsed/preprocessed or compiled into a header module depending on the * configuration. */ public CcLibraryHelper addPublicHeaders(Collection<Artifact> headers) { for (Artifact header : headers) { addHeader(header, ruleContext.getLabel()); } return this; }