/** * Registers actions required to build an application. This includes any {@link * BundleSupport#registerActions(ObjcProvider) bundle} and bundle merge actions, signing this * application if appropriate and combining several single-architecture binaries into one * multi-architecture binary. * * @return this application support * @throws InterruptedException */ ReleaseBundlingSupport registerActions() throws InterruptedException { bundleSupport.registerActions(objcProvider); registerCombineArchitecturesAction(); registerTransformAndCopyBreakpadFilesAction(); registerSwiftStdlibActionsIfNecessary(); AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class); Artifact ipaOutput = ruleContext.getImplicitOutputArtifact(IPA); Artifact maybeSignedIpa; if (appleConfiguration.getBundlingPlatform() == Platform.IOS_SIMULATOR) { maybeSignedIpa = ipaOutput; } else if (attributes.provisioningProfile() == null) { throw new IllegalStateException(DEVICE_NO_PROVISIONING_PROFILE); } else { maybeSignedIpa = registerBundleSigningActions(ipaOutput); } registerEmbedLabelPlistAction(); registerEnvironmentPlistAction(); registerAutomaticPlistAction(); if (ObjcRuleClasses.useLaunchStoryboard(ruleContext)) { registerLaunchStoryboardPlistAction(); } BundleMergeControlBytes bundleMergeControlBytes = new BundleMergeControlBytes( bundling, maybeSignedIpa, appleConfiguration, bundleSupport.targetDeviceFamilies()); registerBundleMergeActions( maybeSignedIpa, bundling.getBundleContentArtifacts(), bundleMergeControlBytes); return this; }
private Bundling bundling( RuleContext ruleContext, ObjcProvider objcProvider, String bundleDirFormat, String bundleName, DottedVersion minimumOsVersion) { ImmutableList<BundleableFile> extraBundleFiles; AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class); if (appleConfiguration.getBundlingPlatform() == Platform.IOS_DEVICE) { extraBundleFiles = ImmutableList.of( new BundleableFile( new Attributes(ruleContext).provisioningProfile(), PROVISIONING_PROFILE_BUNDLE_FILE)); } else { extraBundleFiles = ImmutableList.of(); } String primaryBundleId = null; String fallbackBundleId = null; if (ruleContext.attributes().isAttributeValueExplicitlySpecified("bundle_id")) { primaryBundleId = ruleContext.attributes().get("bundle_id", Type.STRING); } else { fallbackBundleId = ruleContext.attributes().get("bundle_id", Type.STRING); } Bundling.Builder bundling = new Builder() .setName(bundleName) // Architecture that determines which nested bundles are kept. .setArchitecture(appleConfiguration.getDependencySingleArchitecture()) .setBundleDirFormat(bundleDirFormat) .addExtraBundleFiles(extraBundleFiles) .setObjcProvider(objcProvider) .addInfoplistInputFromRule(ruleContext) .addInfoplistInput(getGeneratedVersionPlist()) .addInfoplistInput(getGeneratedEnvironmentPlist()) .setAutomaticEntriesInfoplistInput(getGeneratedAutomaticPlist()) .setIntermediateArtifacts(ObjcRuleClasses.intermediateArtifacts(ruleContext)) .setPrimaryBundleId(primaryBundleId) .setFallbackBundleId(fallbackBundleId) .setMinimumOsVersion(minimumOsVersion); if (ObjcRuleClasses.useLaunchStoryboard(ruleContext)) { bundling.addInfoplistInput(getLaunchStoryboardPlist()); } return bundling.build(); }
/** * Returns any additional providers that need to be exported to the rule context to the passed * builder. */ public Map<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider> getExtraProviders() { AppleConfiguration configuration = ruleContext.getFragment(AppleConfiguration.class); ImmutableMap.Builder<String, String> envBuilder = ImmutableMap.builder(); envBuilder.putAll(configuration.getEnvironmentForIosAction()); if (ruleContext.getConfiguration().isCodeCoverageEnabled()) { envBuilder.put( "COVERAGE_GCOV_PATH", ruleContext.getHostPrerequisiteArtifact(":gcov").getExecPathString()); } return ImmutableMap.<Class<? extends TransitiveInfoProvider>, TransitiveInfoProvider>of( TestEnvironmentProvider.class, new TestEnvironmentProvider(envBuilder.build())); }
/** * Returns a map containing entries that should be added to the merged plist. These are usually * generated by Xcode automatically during the build process. */ private NSDictionary automaticEntries() { List<Integer> uiDeviceFamily = TargetDeviceFamily.UI_DEVICE_FAMILY_VALUES.get(bundleSupport.targetDeviceFamilies()); AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class); Platform platform = appleConfiguration.getBundlingPlatform(); ObjcConfiguration objcConfiguration = ObjcRuleClasses.objcConfiguration(ruleContext); NSDictionary result = new NSDictionary(); if (uiDeviceFamily != null) { result.put("UIDeviceFamily", NSObject.wrap(uiDeviceFamily.toArray())); } result.put("DTPlatformName", NSObject.wrap(platform.getLowerCaseNameInPlist())); result.put( "DTSDKName", NSObject.wrap(platform.getLowerCaseNameInPlist() + appleConfiguration.getIosSdkVersion())); result.put("CFBundleSupportedPlatforms", new NSArray(NSObject.wrap(platform.getNameInPlist()))); result.put("MinimumOSVersion", NSObject.wrap(objcConfiguration.getMinimumOs().toString())); return result; }
private void registerEnvironmentPlistAction() { AppleConfiguration configuration = ruleContext.getFragment(AppleConfiguration.class); // 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(), configuration.getIosSdkVersion()); ruleContext.registerAction( ObjcRuleClasses.spawnOnDarwinActionBuilder() .setMnemonic("EnvironmentPlist") .addInput(attributes.environmentPlistScript()) .setExecutable(attributes.environmentPlistScript()) .addArguments("--platform", platformWithVersion) .addArguments("--output", getGeneratedEnvironmentPlist().getExecPathString()) .addOutput(getGeneratedEnvironmentPlist()) .build(ruleContext)); }
/** * {@inheritDoc} * * <p>Creates a target, including registering actions, just as {@link #create(RuleContext)} does. * The difference between {@link #create(RuleContext)} and this method is that this method does * only what is needed to support tests on the environment besides generate the Xcodeproj file and * build the app and test {@code .ipa}s. The {@link #create(RuleContext)} method delegates to this * method. */ @Override public final ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException, RuleErrorException { ProtobufSupport protoSupport = new ProtobufSupport(ruleContext).registerGenerationActions().registerCompilationActions(); Optional<ObjcProvider> protosObjcProvider = protoSupport.getObjcProvider(); Optional<XcodeProvider> protosXcodeProvider = protoSupport.getXcodeProvider(); ObjcCommon common = common(ruleContext, protosObjcProvider); if (!common.getCompilationArtifacts().get().getArchive().isPresent()) { ruleContext.ruleError(REQUIRES_SOURCE_ERROR); } if (!ruleContext.getFragment(AppleConfiguration.class).getIosMultiCpus().isEmpty()) { ruleContext.ruleError(NO_MULTI_CPUS_ERROR); } XcodeProvider.Builder xcodeProviderBuilder = new XcodeProvider.Builder().addPropagatedDependencies(protosXcodeProvider.asSet()); NestedSetBuilder<Artifact> filesToBuild = NestedSetBuilder.stableOrder(); addResourceFilesToBuild(ruleContext, common.getObjcProvider(), filesToBuild); XcodeProductType productType = getProductType(ruleContext); ExtraLinkArgs extraLinkArgs; Iterable<Artifact> extraLinkInputs; String bundleFormat; if (!isXcTest(ruleContext)) { extraLinkArgs = new ExtraLinkArgs(); extraLinkInputs = ImmutableList.of(); bundleFormat = ReleaseBundlingSupport.APP_BUNDLE_DIR_FORMAT; } else { XcodeProvider appIpaXcodeProvider = ruleContext.getPrerequisite(XCTEST_APP_ATTR, Mode.TARGET, XcodeProvider.class); xcodeProviderBuilder.setTestHost(appIpaXcodeProvider).setProductType(productType); XcTestAppProvider testApp = xcTestAppProvider(ruleContext); Artifact bundleLoader = testApp.getBundleLoader(); // -bundle causes this binary to be linked as a bundle and not require an entry point // (i.e. main()) // -bundle_loader causes the code in this test to have access to the symbols in the test rig, // or more specifically, the flag causes ld to consider the given binary when checking for // missing symbols. // -rpath @loader_path/Frameworks allows test bundles to load dylibs from the app's // Frameworks directory. extraLinkArgs = new ExtraLinkArgs( "-bundle", "-bundle_loader", bundleLoader.getExecPathString(), "-Xlinker", "-rpath", "-Xlinker", "@loader_path/Frameworks"); extraLinkInputs = ImmutableList.of(bundleLoader); bundleFormat = ReleaseBundlingSupport.XCTEST_BUNDLE_DIR_FORMAT; filesToBuild.add(testApp.getIpa()); } J2ObjcMappingFileProvider j2ObjcMappingFileProvider = J2ObjcMappingFileProvider.union( ruleContext.getPrerequisites("deps", Mode.TARGET, J2ObjcMappingFileProvider.class)); J2ObjcEntryClassProvider j2ObjcEntryClassProvider = new J2ObjcEntryClassProvider.Builder() .addTransitive( ruleContext.getPrerequisites("deps", Mode.TARGET, J2ObjcEntryClassProvider.class)) .build(); new CompilationSupport(ruleContext) .registerLinkActions( common.getObjcProvider(), j2ObjcMappingFileProvider, j2ObjcEntryClassProvider, extraLinkArgs, extraLinkInputs, DsymOutputType.TEST) .registerCompileAndArchiveActions(common) .registerFullyLinkAction( common.getObjcProvider(), ruleContext.getImplicitOutputArtifact(CompilationSupport.FULLY_LINKED_LIB)) .addXcodeSettings(xcodeProviderBuilder, common) .validateAttributes(); AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class); new ReleaseBundlingSupport( ruleContext, common.getObjcProvider(), LinkedBinary.LOCAL_AND_DEPENDENCIES, bundleFormat, appleConfiguration.getMinimumOsForPlatformType(PlatformType.IOS), appleConfiguration.getMultiArchPlatform(PlatformType.IOS)) .registerActions(DsymOutputType.TEST) .addXcodeSettings(xcodeProviderBuilder) .addFilesToBuild(filesToBuild, Optional.of(DsymOutputType.TEST)) .validateResources() .validateAttributes(); new ResourceSupport(ruleContext).validateAttributes().addXcodeSettings(xcodeProviderBuilder); new XcodeSupport(ruleContext) .addXcodeSettings(xcodeProviderBuilder, common.getObjcProvider(), productType) .addDependencies(xcodeProviderBuilder, new Attribute("bundles", Mode.TARGET)) .addDependencies(xcodeProviderBuilder, new Attribute("deps", Mode.TARGET)) .addNonPropagatedDependencies( xcodeProviderBuilder, new Attribute("non_propagated_deps", Mode.TARGET)) .addFilesToBuild(filesToBuild) .registerActions(xcodeProviderBuilder.build()); XcodeProvider xcodeProvider = xcodeProviderBuilder.build(); NestedSet<Artifact> filesToBuildSet = filesToBuild.build(); Runfiles.Builder runfilesBuilder = new Runfiles.Builder( ruleContext.getWorkspaceName(), ruleContext.getConfiguration().legacyExternalRunfiles()) .addRunfiles(ruleContext, RunfilesProvider.DEFAULT_RUNFILES); NestedSetBuilder<Artifact> filesToBuildBuilder = NestedSetBuilder.<Artifact>stableOrder().addTransitive(filesToBuildSet); InstrumentedFilesProvider instrumentedFilesProvider = new CompilationSupport(ruleContext).getInstrumentedFilesProvider(common); TestSupport testSupport = new TestSupport(ruleContext) .registerTestRunnerActions() .addRunfiles(runfilesBuilder, instrumentedFilesProvider) .addFilesToBuild(filesToBuildBuilder); Artifact executable = testSupport.generatedTestScript(); Runfiles runfiles = runfilesBuilder.build(); RunfilesSupport runfilesSupport = RunfilesSupport.withExecutable(ruleContext, runfiles, executable); ImmutableMap.Builder<String, String> execInfoMapBuilder = new ImmutableMap.Builder<>(); execInfoMapBuilder.put(ExecutionRequirements.REQUIRES_DARWIN, ""); if (ruleContext.getFragment(ObjcConfiguration.class).runMemleaks()) { execInfoMapBuilder.put("nosandbox", ""); } return new RuleConfiguredTargetBuilder(ruleContext) .setFilesToBuild(filesToBuildBuilder.build()) .addProvider(xcodeProvider) .addProvider(RunfilesProvider.simple(runfiles)) .addProvider(new ExecutionInfoProvider(execInfoMapBuilder.build())) .addProvider(InstrumentedFilesProvider.class, instrumentedFilesProvider) .addProviders(testSupport.getExtraProviders()) .setRunfilesSupport(runfilesSupport, executable) .build(); }