Clean up framework support
RELNOTES: Add --incompatible_objc_framework_cleanup to control whether to enable some objc framework cleanup that changes the API. Specifically, the cleanup changes the objc provider API pertaining to frameworks. This change is expected to be transparent to most users unless they write their own Starlark rules to handle frameworks. See https://github.com/bazelbuild/bazel/issues/7594 for details.
PiperOrigin-RevId: 243373818
diff --git a/src/main/java/com/google/devtools/build/lib/packages/StarlarkSemanticsOptions.java b/src/main/java/com/google/devtools/build/lib/packages/StarlarkSemanticsOptions.java
index bc7faa9..916fb69 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/StarlarkSemanticsOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/StarlarkSemanticsOptions.java
@@ -523,6 +523,22 @@
+ "See https://github.com/bazelbuild/bazel/issues/7670 for details.")
public boolean incompatibleDoNotSplitLinkingCmdline;
+ @Option(
+ name = "incompatible_objc_framework_cleanup",
+ defaultValue = "false",
+ documentationCategory = OptionDocumentationCategory.STARLARK_SEMANTICS,
+ effectTags = {OptionEffectTag.BUILD_FILE_SEMANTICS},
+ metadataTags = {
+ OptionMetadataTag.INCOMPATIBLE_CHANGE,
+ OptionMetadataTag.TRIGGERED_BY_ALL_INCOMPATIBLE_CHANGES
+ },
+ help =
+ "If enabled, use the post-cleanup mode for prebuilt frameworks. The cleanup changes "
+ + "the objc provider API pertaining to frameworks. This change is expected to be "
+ + "transparent to most users unless they write their own Starlark rules to handle "
+ + "frameworks. See https://github.com/bazelbuild/bazel/issues/7944 for details.")
+ public boolean incompatibleObjcFrameworkCleanup;
+
/** Constructs a {@link StarlarkSemantics} object corresponding to this set of option values. */
public StarlarkSemantics toSkylarkSemantics() {
return StarlarkSemantics.builder()
@@ -558,6 +574,7 @@
.incompatibleNoSupportToolsInActionInputs(incompatibleNoSupportToolsInActionInputs)
.incompatibleNoTargetOutputGroup(incompatibleNoTargetOutputGroup)
.incompatibleNoTransitiveLoads(incompatibleNoTransitiveLoads)
+ .incompatibleObjcFrameworkCleanup(incompatibleObjcFrameworkCleanup)
.incompatibleRemapMainRepo(incompatibleRemapMainRepo)
.incompatibleRemoveNativeMavenJar(incompatibleRemoveNativeMavenJar)
.incompatibleStaticNameResolutionInBuildFiles(incompatibleStaticNameResolutionInBuildFiles)
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java
index 291fa37..ff5c600 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java
@@ -22,6 +22,7 @@
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.DYNAMIC_FRAMEWORK_FILE;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FORCE_LOAD_LIBRARY;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FRAMEWORK_SEARCH_PATH_ONLY;
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FRAMEWORK_SUFFIX;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.HEADER;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY;
import static com.google.devtools.build.lib.rules.objc.ObjcProvider.INCLUDE;
@@ -121,6 +122,7 @@
import com.google.devtools.build.lib.rules.cpp.UmbrellaHeaderAction;
import com.google.devtools.build.lib.rules.objc.ObjcProvider.Flag;
import com.google.devtools.build.lib.rules.objc.ObjcVariablesExtension.VariableCategory;
+import com.google.devtools.build.lib.syntax.StarlarkSemantics;
import com.google.devtools.build.lib.util.FileTypeSet;
import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -190,8 +192,6 @@
static final ImmutableList<SdkFramework> AUTOMATIC_SDK_FRAMEWORKS =
ImmutableList.of(new SdkFramework("Foundation"), new SdkFramework("UIKit"));
- private static final String FRAMEWORK_SUFFIX = ".framework";
-
/** Selects cc libraries that have alwayslink=1. */
private static final Predicate<Artifact> ALWAYS_LINKED_CC_LIBRARY =
input -> LINK_LIBRARY_FILETYPES.matches(input.getFilename());
@@ -270,12 +270,14 @@
private IncludeProcessing createIncludeProcessing(
Iterable<Artifact> privateHdrs, ObjcProvider objcProvider, @Nullable Artifact pchHdr) {
if (isHeaderThinningEnabled()) {
- Iterable<Artifact> potentialInputs =
- Iterables.concat(
- privateHdrs,
- objcProvider.get(HEADER),
- objcProvider.get(STATIC_FRAMEWORK_FILE),
- objcProvider.get(DYNAMIC_FRAMEWORK_FILE));
+ Iterable<Artifact> potentialInputs = Iterables.concat(privateHdrs, objcProvider.get(HEADER));
+ if (!starlarkSemantics.incompatibleObjcFrameworkCleanup()) {
+ potentialInputs =
+ Iterables.concat(
+ potentialInputs,
+ objcProvider.get(STATIC_FRAMEWORK_FILE),
+ objcProvider.get(DYNAMIC_FRAMEWORK_FILE));
+ }
if (pchHdr != null) {
potentialInputs = Iterables.concat(potentialInputs, ImmutableList.of(pchHdr));
}
@@ -512,7 +514,8 @@
ruleContext.getFragment(ObjcConfiguration.class),
isHeaderThinningEnabled(),
intermediateArtifacts,
- buildConfiguration);
+ buildConfiguration,
+ starlarkSemantics);
}
private FeatureConfiguration getFeatureConfiguration(
@@ -670,19 +673,28 @@
.build();
}
- /** Returns a list of frameworks for clang actions. */
- static Iterable<String> commonFrameworkNames(
- ObjcProvider provider, RuleContext ruleContext, ApplePlatform platform) {
+ /** Add framework search paths common to both headers and libraries. */
+ private static void addCommonFrameworkSearchPaths(
+ ImmutableList.Builder<String> paths,
+ RuleContext ruleContext,
+ BuildConfiguration buildConfiguration) {
- ImmutableList.Builder<String> frameworkNames =
- new ImmutableList.Builder<String>()
- .add(
- AppleToolchain.sdkFrameworkDir(
- platform, XcodeConfig.getXcodeConfigProvider(ruleContext)));
+ ApplePlatform platform =
+ buildConfiguration.getFragment(AppleConfiguration.class).getSingleArchPlatform();
+ paths.add(
+ AppleToolchain.sdkFrameworkDir(platform, XcodeConfig.getXcodeConfigProvider(ruleContext)));
// As of sdk8.1, XCTest is in a base Framework dir.
if (platform.getType() != PlatformType.WATCHOS) { // WatchOS does not have this directory.
- frameworkNames.add(AppleToolchain.platformDeveloperFrameworkDir(platform));
+ paths.add(AppleToolchain.platformDeveloperFrameworkDir(platform));
}
+ }
+
+ /** Returns a list of framework search paths for clang actions for pre-cleanup mode. */
+ static ImmutableList<String> preCleanupFrameworkSearchPaths(
+ ObjcProvider provider, RuleContext ruleContext, BuildConfiguration buildConfiguration) {
+
+ ImmutableList.Builder<String> frameworkNames = new ImmutableList.Builder<String>();
+ addCommonFrameworkSearchPaths(frameworkNames, ruleContext, buildConfiguration);
return frameworkNames
// Add custom (non-SDK) framework search paths. For each framework foo/bar.framework,
// include "foo" as a search path.
@@ -701,7 +713,48 @@
.build();
}
+ /** Returns a list of framework header search paths. */
+ static ImmutableList<String> frameworkHeaderSearchPaths(
+ ObjcProvider provider, RuleContext ruleContext, BuildConfiguration buildConfiguration)
+ throws InterruptedException {
+ StarlarkSemantics starlarkSemantics =
+ ruleContext.getAnalysisEnvironment().getSkylarkSemantics();
+ if (!starlarkSemantics.incompatibleObjcFrameworkCleanup()) {
+ return preCleanupFrameworkSearchPaths(provider, ruleContext, buildConfiguration);
+ }
+ ImmutableList.Builder<String> searchPaths = new ImmutableList.Builder<String>();
+ addCommonFrameworkSearchPaths(searchPaths, ruleContext, buildConfiguration);
+ return searchPaths
+ // Add header search paths corresponding to custom (non-SDK) frameworks. For each framework
+ // foo/bar.framework, include "foo" as a search path.
+ .addAll(
+ Iterables.transform(
+ uniqueParentDirectories(provider.get(FRAMEWORK_SEARCH_PATH_ONLY)),
+ PathFragment::getSafePathString))
+ .build();
+ }
+
+ /** Returns a list of framework library search paths. */
+ static ImmutableList<String> frameworkLibrarySearchPaths(
+ ObjcProvider provider, RuleContext ruleContext, BuildConfiguration buildConfiguration)
+ throws InterruptedException {
+ StarlarkSemantics starlarkSemantics =
+ ruleContext.getAnalysisEnvironment().getSkylarkSemantics();
+ if (!starlarkSemantics.incompatibleObjcFrameworkCleanup()) {
+ return preCleanupFrameworkSearchPaths(provider, ruleContext, buildConfiguration);
+ }
+ ImmutableList.Builder<String> searchPaths = new ImmutableList.Builder<String>();
+ addCommonFrameworkSearchPaths(searchPaths, ruleContext, buildConfiguration);
+ return searchPaths
+ // Add library search paths corresponding to custom (non-SDK) frameworks. For each framework
+ // foo/bar.framework, include "foo" as a search path.
+ .addAll(provider.staticFrameworkPaths())
+ .addAll(provider.dynamicFrameworkPaths())
+ .build();
+ }
+
private final RuleContext ruleContext;
+ private final StarlarkSemantics starlarkSemantics;
private final BuildConfiguration buildConfiguration;
private final ObjcConfiguration objcConfiguration;
private final AppleConfiguration appleConfiguration;
@@ -735,8 +788,10 @@
ImmutableList.Builder<Artifact> objectFilesCollector,
CcToolchainProvider toolchain,
boolean isTestRule,
- boolean usePch) {
+ boolean usePch)
+ throws InterruptedException {
this.ruleContext = ruleContext;
+ this.starlarkSemantics = ruleContext.getAnalysisEnvironment().getSkylarkSemantics();
this.buildConfiguration = buildConfiguration;
this.objcConfiguration = buildConfiguration.getFragment(ObjcConfiguration.class);
this.appleConfiguration = buildConfiguration.getFragment(AppleConfiguration.class);
@@ -844,7 +899,7 @@
}
/** Returns a {@link CompilationSupport} instance. */
- public CompilationSupport build() {
+ public CompilationSupport build() throws InterruptedException {
Preconditions.checkNotNull(ruleContext, "CompilationSupport is missing RuleContext");
if (buildConfiguration == null) {
@@ -1024,7 +1079,9 @@
.setObjcProvider(objcProvider)
.setCompilationArtifacts(compilationArtifacts)
.setIntermediateArtifacts(intermediateArtifacts)
- .setConfiguration(buildConfiguration);
+ .setConfiguration(buildConfiguration)
+ .setFrameworkSearchPath(
+ frameworkHeaderSearchPaths(objcProvider, ruleContext, buildConfiguration));
Pair<CcCompilationOutputs, ImmutableMap<String, NestedSet<Artifact>>> compilationInfo;
@@ -1163,6 +1220,8 @@
.setConfiguration(buildConfiguration)
.setIntermediateArtifacts(intermediateArtifacts)
.setFrameworkNames(frameworkNames(objcProvider))
+ .setFrameworkSearchPath(
+ frameworkLibrarySearchPaths(objcProvider, ruleContext, buildConfiguration))
.setLibraryNames(libraryNames(objcProvider))
.setForceLoadArtifacts(getForceLoadArtifacts(objcProvider))
.setAttributeLinkopts(attributes.linkopts())
@@ -1344,6 +1403,8 @@
.setObjcProvider(objcProvider)
.setConfiguration(buildConfiguration)
.setIntermediateArtifacts(intermediateArtifacts)
+ .setFrameworkSearchPath(
+ frameworkHeaderSearchPaths(objcProvider, ruleContext, buildConfiguration))
.setFullyLinkArchive(outputArchive)
.addVariableCategory(VariableCategory.FULLY_LINK_VARIABLES)
.build();
@@ -1389,15 +1450,21 @@
private Set<String> frameworkNames(ObjcProvider provider) {
Set<String> names = new LinkedHashSet<>();
Iterables.addAll(names, SdkFramework.names(provider.get(SDK_FRAMEWORK)));
- for (PathFragment frameworkDir :
- Iterables.concat(provider.getStaticFrameworkDirs(), provider.get(DYNAMIC_FRAMEWORK_DIR))) {
- String segment = frameworkDir.getBaseName();
- Preconditions.checkState(
- segment.endsWith(FRAMEWORK_SUFFIX),
- "expect %s to end with %s, but it does not",
- segment,
- FRAMEWORK_SUFFIX);
- names.add(segment.substring(0, segment.length() - FRAMEWORK_SUFFIX.length()));
+ if (!starlarkSemantics.incompatibleObjcFrameworkCleanup()) {
+ for (PathFragment frameworkDir :
+ Iterables.concat(
+ provider.getStaticFrameworkDirs(), provider.get(DYNAMIC_FRAMEWORK_DIR))) {
+ String segment = frameworkDir.getBaseName();
+ Preconditions.checkState(
+ segment.endsWith(FRAMEWORK_SUFFIX),
+ "expect %s to end with %s, but it does not",
+ segment,
+ FRAMEWORK_SUFFIX);
+ names.add(segment.substring(0, segment.length() - FRAMEWORK_SUFFIX.length()));
+ }
+ } else {
+ Iterables.addAll(names, provider.staticFrameworkNames());
+ Iterables.addAll(names, provider.dynamicFrameworkNames());
}
return names;
}
@@ -1857,6 +1924,11 @@
"%s:%s", info.sourceFile.getExecPath(), info.headersListFile.getExecPath());
builder.addInput(info.sourceFile).addOutput(info.headersListFile);
}
+ if (!starlarkSemantics.incompatibleObjcFrameworkCleanup()) {
+ builder
+ .addTransitiveInputs(objcProvider.get(ObjcProvider.STATIC_FRAMEWORK_FILE))
+ .addTransitiveInputs(objcProvider.get(ObjcProvider.DYNAMIC_FRAMEWORK_FILE));
+ }
ruleContext.registerAction(
builder
.addCommandLine(cmdLine.add("--").addAll(args).build())
@@ -1864,8 +1936,6 @@
.addTransitiveInputs(attributes.hdrs())
.addTransitiveInputs(objcProvider.get(ObjcProvider.HEADER))
.addInputs(getPchFile().asSet())
- .addTransitiveInputs(objcProvider.get(ObjcProvider.STATIC_FRAMEWORK_FILE))
- .addTransitiveInputs(objcProvider.get(ObjcProvider.DYNAMIC_FRAMEWORK_FILE))
.build(ruleContext));
}
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 8a7be99..39bdcda 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
@@ -225,8 +225,8 @@
}
/**
- * Adds all given artifacts as members of static frameworks. They must be contained in
- * {@code .frameworks} directories and the binary in that framework should be statically linked.
+ * Add the library files corresponding to static frameworks. They must be contained in {@code
+ * .frameworks} directories and the binaries should be statically linked.
*/
Builder addStaticFrameworkImports(Iterable<Artifact> frameworkImports) {
this.staticFrameworkImports = Iterables.concat(this.staticFrameworkImports, frameworkImports);
@@ -234,9 +234,8 @@
}
/**
- * Adds all given artifacts as members of dynamic frameworks. They must be contained in
- * {@code .frameworks} directories and the binary in that framework should be dynamically
- * linked.
+ * Add the library files corresponding to dynamic frameworks. They must be contained in {@code
+ * .frameworks} directories and the binaries should be dynamically linked.
*/
Builder addDynamicFrameworkImports(Iterable<Artifact> frameworkImports) {
this.dynamicFrameworkImports =
@@ -410,18 +409,26 @@
.addAll(SDK_DYLIB, extraSdkDylibs)
.addAll(STATIC_FRAMEWORK_FILE, staticFrameworkImports)
.addAll(DYNAMIC_FRAMEWORK_FILE, dynamicFrameworkImports)
- .addAll(
- DYNAMIC_FRAMEWORK_DIR,
- uniqueContainers(dynamicFrameworkImports, FRAMEWORK_CONTAINER_TYPE))
.addAll(INCLUDE, includes)
.add(IQUOTE, buildConfiguration.getGenfilesFragment())
.addAllForDirectDependents(INCLUDE, directDependencyIncludes)
.addAll(DEFINE, defines)
.addTransitiveAndPropagate(depObjcProviders);
+ if (!semantics.incompatibleObjcFrameworkCleanup()) {
+ objcProvider.addAll(
+ DYNAMIC_FRAMEWORK_DIR,
+ uniqueContainers(dynamicFrameworkImports, FRAMEWORK_CONTAINER_TYPE));
+ }
+
for (ObjcProvider provider : runtimeDepObjcProviders) {
- objcProvider.addTransitiveAndPropagate(ObjcProvider.DYNAMIC_FRAMEWORK_FILE, provider);
- objcProvider.addTransitiveAndPropagate(ObjcProvider.STATIC_FRAMEWORK_FILE, provider);
+ if (!semantics.incompatibleObjcFrameworkCleanup()) {
+ objcProvider.addTransitiveAndPropagate(ObjcProvider.DYNAMIC_FRAMEWORK_FILE, provider);
+ objcProvider.addTransitiveAndPropagate(ObjcProvider.STATIC_FRAMEWORK_FILE, provider);
+ } else {
+ objcProvider.addTransitiveAndPropagate(ObjcProvider.FRAMEWORK_SEARCH_PATH_ONLY, provider);
+ objcProvider.addTransitiveAndPropagate(ObjcProvider.HEADER, provider);
+ }
objcProvider.addTransitiveAndPropagate(ObjcProvider.MERGE_ZIP, provider);
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCppSemantics.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCppSemantics.java
index f54a263..a9d67dc 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCppSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCppSemantics.java
@@ -32,6 +32,7 @@
import com.google.devtools.build.lib.rules.cpp.CppSemantics;
import com.google.devtools.build.lib.rules.cpp.HeaderDiscovery.DotdPruningMode;
import com.google.devtools.build.lib.rules.cpp.IncludeProcessing;
+import com.google.devtools.build.lib.syntax.StarlarkSemantics;
import com.google.devtools.build.lib.util.FileTypeSet;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.List;
@@ -47,6 +48,7 @@
private final boolean isHeaderThinningEnabled;
private final IntermediateArtifacts intermediateArtifacts;
private final BuildConfiguration buildConfiguration;
+ private final StarlarkSemantics starlarkSemantics;
/**
* Set of {@link com.google.devtools.build.lib.util.FileType} of source artifacts that are
@@ -78,13 +80,15 @@
ObjcConfiguration config,
boolean isHeaderThinningEnabled,
IntermediateArtifacts intermediateArtifacts,
- BuildConfiguration buildConfiguration) {
+ BuildConfiguration buildConfiguration,
+ StarlarkSemantics starlarkSemantics) {
this.objcProvider = objcProvider;
this.includeProcessing = includeProcessing;
this.config = config;
this.isHeaderThinningEnabled = isHeaderThinningEnabled;
this.intermediateArtifacts = intermediateArtifacts;
this.buildConfiguration = buildConfiguration;
+ this.starlarkSemantics = starlarkSemantics;
}
@Override
@@ -96,9 +100,13 @@
// Because Bazel does not support include scanning, we need the entire crosstool filegroup,
// including header files, as opposed to just the "compile" filegroup.
.addTransitiveMandatoryInputs(actionBuilder.getToolchain().getAllFiles())
- .setShouldScanIncludes(false)
- .addTransitiveMandatoryInputs(objcProvider.get(STATIC_FRAMEWORK_FILE))
- .addTransitiveMandatoryInputs(objcProvider.get(DYNAMIC_FRAMEWORK_FILE));
+ .setShouldScanIncludes(false);
+
+ if (!starlarkSemantics.incompatibleObjcFrameworkCleanup()) {
+ actionBuilder
+ .addTransitiveMandatoryInputs(objcProvider.get(STATIC_FRAMEWORK_FILE))
+ .addTransitiveMandatoryInputs(objcProvider.get(DYNAMIC_FRAMEWORK_FILE));
+ }
if (isHeaderThinningEnabled) {
Artifact sourceFile = actionBuilder.getSourceFile();
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 c416d07..c97c9f5 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
@@ -58,6 +58,9 @@
/** Skylark name for the ObjcProvider. */
public static final String SKYLARK_NAME = "objc";
+ /** Expected suffix for a framework-containing directory. */
+ public static final String FRAMEWORK_SUFFIX = ".framework";
+
/**
* Represents one of the things this provider can provide transitively. Things are provided as
* {@link NestedSet}s of type E.
@@ -232,11 +235,7 @@
public static final Key<PathFragment> FRAMEWORK_SEARCH_PATH_ONLY =
new Key<>(LINK_ORDER, "framework_search_paths", PathFragment.class);
-
- /**
- * Files in {@code .framework} directories that should be included as inputs when compiling and
- * linking.
- */
+ /** The static library files of user-specified static frameworks. */
public static final Key<Artifact> STATIC_FRAMEWORK_FILE =
new Key<>(STABLE_ORDER, "static_framework_file", Artifact.class);
@@ -249,11 +248,7 @@
public static final Key<PathFragment> DYNAMIC_FRAMEWORK_DIR =
new Key<>(LINK_ORDER, "dynamic_framework_dir", PathFragment.class);
- /**
- * Files in {@code .framework} directories belonging to a dynamically linked framework. They
- * should be included as inputs when compiling and linking as well as copied into the final
- * application bundle.
- */
+ /** The dynamic library files of user-specified dynamic frameworks. */
public static final Key<Artifact> DYNAMIC_FRAMEWORK_FILE =
new Key<>(STABLE_ORDER, "dynamic_framework_file", Artifact.class);
@@ -926,6 +921,74 @@
}
/**
+ * Check whether that a path fragment is a framework directory (i.e. ends in FRAMEWORK_SUFFIX).
+ */
+ private static void checkIsFrameworkDirectory(PathFragment dir) {
+ Preconditions.checkState(dir.getBaseName().endsWith(FRAMEWORK_SUFFIX));
+ }
+
+ /** The input path must be of the form <path>/<name>.FRAMEWORK_SUFFIX. Return the names. */
+ private static String getFrameworkName(PathFragment frameworkPath) {
+ String segment = frameworkPath.getBaseName();
+ return segment.substring(0, segment.length() - FRAMEWORK_SUFFIX.length());
+ }
+
+ /** The input path must be of the form <path>/<name>.FRAMEWORK_SUFFIX. Return the paths. */
+ private static String getFrameworkPath(PathFragment frameworkPath) {
+ return frameworkPath.getParentDirectory().getSafePathString();
+ }
+
+ /**
+ * @param key either DYNAMIC_FRAMEWORK_FILE or STATIC_FRAMEWORK_FILE. Return the corresponding
+ * framework names, i.e. for a given a file <path>/<name>.FRAMEWORK_SUFFIX/<name>, return
+ * <name>.
+ */
+ private NestedSet<String> getFrameworkNames(Key<Artifact> key) {
+ NestedSetBuilder<String> names = new NestedSetBuilder<>(key.order);
+ for (Artifact file : get(key)) {
+ PathFragment frameworkDir = file.getExecPath().getParentDirectory();
+ checkIsFrameworkDirectory(frameworkDir);
+ names.add(getFrameworkName(frameworkDir));
+ }
+ return names.build();
+ }
+
+ /**
+ * @param key either DYNAMIC_FRAMEWORK_FILE or STATIC_FRAMEWORK_FILE. Return the corresponding
+ * framework paths, i.e. for a given a file <path>/<name>.FRAMEWORK_SUFFIX/<name>, return
+ * <path>.
+ */
+ private NestedSet<String> getFrameworkPaths(Key<Artifact> key) {
+ NestedSetBuilder<String> paths = new NestedSetBuilder<>(key.order);
+ for (Artifact file : get(key)) {
+ PathFragment frameworkDir = file.getExecPath().getParentDirectory();
+ checkIsFrameworkDirectory(frameworkDir);
+ paths.add(getFrameworkPath(frameworkDir));
+ }
+ return paths.build();
+ }
+
+ @Override
+ public NestedSet<String> dynamicFrameworkNames() {
+ return getFrameworkNames(DYNAMIC_FRAMEWORK_FILE);
+ }
+
+ @Override
+ public NestedSet<String> dynamicFrameworkPaths() {
+ return getFrameworkPaths(DYNAMIC_FRAMEWORK_FILE);
+ }
+
+ @Override
+ public NestedSet<String> staticFrameworkNames() {
+ return getFrameworkNames(STATIC_FRAMEWORK_FILE);
+ }
+
+ @Override
+ public NestedSet<String> staticFrameworkPaths() {
+ return getFrameworkPaths(STATIC_FRAMEWORK_FILE);
+ }
+
+ /**
* A builder for this context with an API that is optimized for collecting information from
* several transitive dependencies.
*/
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcVariablesExtension.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcVariablesExtension.java
index 876eea4..651a852 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcVariablesExtension.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcVariablesExtension.java
@@ -25,10 +25,7 @@
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.packages.BuildType;
-import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
-import com.google.devtools.build.lib.rules.apple.ApplePlatform;
import com.google.devtools.build.lib.rules.cpp.CcToolchainVariables;
-import com.google.devtools.build.lib.rules.cpp.CcToolchainVariables.StringSequenceBuilder;
import com.google.devtools.build.lib.rules.cpp.CcToolchainVariables.VariablesExtension;
import java.util.Set;
@@ -36,7 +33,7 @@
class ObjcVariablesExtension implements VariablesExtension {
static final String PCH_FILE_VARIABLE_NAME = "pch_file";
- static final String FRAMEWORKS_VARIABLE_NAME = "framework_paths";
+ static final String FRAMEWORKS_PATH_NAME = "framework_paths";
static final String MODULES_MAPS_DIR_NAME = "module_maps_dir";
static final String OBJC_MODULE_CACHE_DIR_NAME = "_objc_module_cache";
static final String OBJC_MODULE_CACHE_KEY = "modules_cache_path";
@@ -72,6 +69,7 @@
private final Artifact fullyLinkArchive;
private final IntermediateArtifacts intermediateArtifacts;
private final BuildConfiguration buildConfiguration;
+ private final ImmutableList<String> frameworkSearchPaths;
private final Set<String> frameworkNames;
private final ImmutableList<String> libraryNames;
private final ImmutableSet<Artifact> forceLoadArtifacts;
@@ -89,6 +87,7 @@
Artifact fullyLinkArchive,
IntermediateArtifacts intermediateArtifacts,
BuildConfiguration buildConfiguration,
+ ImmutableList<String> frameworkSearchPaths,
Set<String> frameworkNames,
ImmutableList<String> libraryNames,
ImmutableSet<Artifact> forceLoadArtifacts,
@@ -104,6 +103,7 @@
this.fullyLinkArchive = fullyLinkArchive;
this.intermediateArtifacts = intermediateArtifacts;
this.buildConfiguration = buildConfiguration;
+ this.frameworkSearchPaths = frameworkSearchPaths;
this.frameworkNames = frameworkNames;
this.libraryNames = libraryNames;
this.forceLoadArtifacts = forceLoadArtifacts;
@@ -165,14 +165,7 @@
}
private void addFrameworkVariables(CcToolchainVariables.Builder builder) {
- ApplePlatform applePlatform =
- buildConfiguration.getFragment(AppleConfiguration.class).getSingleArchPlatform();
- StringSequenceBuilder frameworkSequence = new StringSequenceBuilder();
- for (String framework :
- CompilationSupport.commonFrameworkNames(objcProvider, ruleContext, applePlatform)) {
- frameworkSequence.addValue(framework);
- }
- builder.addCustomBuiltVariable(FRAMEWORKS_VARIABLE_NAME, frameworkSequence);
+ builder.addStringSequenceVariable(FRAMEWORKS_PATH_NAME, frameworkSearchPaths);
}
private void addModuleMapVariables(CcToolchainVariables.Builder builder) {
@@ -254,6 +247,7 @@
private Artifact fullyLinkArchive;
private IntermediateArtifacts intermediateArtifacts;
private BuildConfiguration buildConfiguration;
+ private ImmutableList<String> frameworkSearchPaths;
private Set<String> frameworkNames;
private ImmutableSet<Artifact> forceLoadArtifacts;
private ImmutableList<String> libraryNames;
@@ -302,6 +296,12 @@
return this;
}
+ /** Sets the framework search paths to be passed to the compiler/linker using {@code -F}. */
+ public Builder setFrameworkSearchPath(ImmutableList<String> frameworkSearchPaths) {
+ this.frameworkSearchPaths = Preconditions.checkNotNull(frameworkSearchPaths);
+ return this;
+ }
+
/** Sets the framework names to be passed to the linker using {@code -framework}. */
public Builder setFrameworkNames(Set<String> frameworkNames) {
this.frameworkNames = Preconditions.checkNotNull(frameworkNames);
@@ -365,6 +365,7 @@
Preconditions.checkNotNull(objcProvider, "missing ObjcProvider");
Preconditions.checkNotNull(buildConfiguration, "missing BuildConfiguration");
Preconditions.checkNotNull(intermediateArtifacts, "missing IntermediateArtifacts");
+ Preconditions.checkNotNull(frameworkSearchPaths, "missing FrameworkSearchPaths");
if (activeVariableCategories.contains(VariableCategory.ARCHIVE_VARIABLES)) {
Preconditions.checkNotNull(compilationArtifacts, "missing CompilationArtifacts");
}
@@ -394,6 +395,7 @@
fullyLinkArchive,
intermediateArtifacts,
buildConfiguration,
+ frameworkSearchPaths,
frameworkNames,
libraryNames,
forceLoadArtifacts,
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ProtobufSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ProtobufSupport.java
index f383960..d334084 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ProtobufSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ProtobufSupport.java
@@ -161,7 +161,7 @@
* Registers the proto generation actions. These actions generate the ObjC/CPP code to be compiled
* by this rule.
*/
- public ProtobufSupport registerGenerationActions() {
+ public ProtobufSupport registerGenerationActions() throws InterruptedException {
int actionId = 0;
for (ImmutableSet<Artifact> inputProtos : orderedInputOutputKeySet()) {
@@ -177,7 +177,7 @@
return this;
}
- private void registerModuleMapGenerationAction() {
+ private void registerModuleMapGenerationAction() throws InterruptedException {
CompilationArtifacts.Builder moduleMapCompilationArtifacts =
new CompilationArtifacts.Builder()
.setIntermediateArtifacts(intermediateArtifacts)
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/apple/ObjcProviderApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/apple/ObjcProviderApi.java
index 1a50100..ee1c923 100644
--- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/apple/ObjcProviderApi.java
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/apple/ObjcProviderApi.java
@@ -57,16 +57,19 @@
)
public NestedSet<String> define();
- @SkylarkCallable(name = "dynamic_framework_dir",
+ @SkylarkCallable(
+ name = "dynamic_framework_dir",
structField = true,
- doc = "Exec paths of .framework directories corresponding to dynamic frameworks to link."
- )
+ doc = "Exec paths of .framework directories corresponding to dynamic frameworks to link.",
+ disableWithFlag = FlagIdentifier.INCOMPATIBLE_OBJC_FRAMEWORK_CLEANUP)
public SkylarkNestedSet dynamicFrameworkDir();
- @SkylarkCallable(name = "dynamic_framework_file",
+ @SkylarkCallable(
+ name = "dynamic_framework_file",
structField = true,
- doc = "Files in .framework directories belonging to a dynamically linked framework."
- )
+ doc =
+ "The library files in .framework directories belonging to a dynamically linked "
+ + "framework.")
public NestedSet<FileApiT> dynamicFrameworkFile();
@SkylarkCallable(name = "exported_debug_artifacts",
@@ -224,11 +227,10 @@
)
public NestedSet<FileApiT> source();
- @SkylarkCallable(name = "static_framework_file",
+ @SkylarkCallable(
+ name = "static_framework_file",
structField = true,
- doc = "Files in .framework directories that should be statically included as inputs "
- + "when compiling and linking."
- )
+ doc = "The library files in .framework directories that should be statically linked.")
public NestedSet<FileApiT> staticFrameworkFile();
@SkylarkCallable(
@@ -291,8 +293,37 @@
@SkylarkCallable(
name = "framework_dir",
structField = true,
- doc = "Returns all unique static framework directories (directories ending in '.framework') "
- + "for all static framework files in this provider."
- )
+ doc =
+ "Returns all unique static framework directories (directories ending in '.framework') "
+ + "for all static framework files in this provider.",
+ disableWithFlag = FlagIdentifier.INCOMPATIBLE_OBJC_FRAMEWORK_CLEANUP)
public SkylarkNestedSet getStaticFrameworkDirsForSkylark();
+
+ @SkylarkCallable(
+ name = "dynamic_framework_names",
+ structField = true,
+ doc = "Returns all names of dynamic frameworks in this provider.",
+ enableOnlyWithFlag = FlagIdentifier.INCOMPATIBLE_OBJC_FRAMEWORK_CLEANUP)
+ public NestedSet<String> dynamicFrameworkNames();
+
+ @SkylarkCallable(
+ name = "dynamic_framework_paths",
+ structField = true,
+ doc = "Returns all framework paths to dynamic frameworks in this provider.",
+ enableOnlyWithFlag = FlagIdentifier.INCOMPATIBLE_OBJC_FRAMEWORK_CLEANUP)
+ public NestedSet<String> dynamicFrameworkPaths();
+
+ @SkylarkCallable(
+ name = "static_framework_names",
+ structField = true,
+ doc = "Returns all names of static frameworks in this provider.",
+ enableOnlyWithFlag = FlagIdentifier.INCOMPATIBLE_OBJC_FRAMEWORK_CLEANUP)
+ public NestedSet<String> staticFrameworkNames();
+
+ @SkylarkCallable(
+ name = "static_framework_paths",
+ structField = true,
+ doc = "Returns all framework paths to static frameworks in this provider.",
+ enableOnlyWithFlag = FlagIdentifier.INCOMPATIBLE_OBJC_FRAMEWORK_CLEANUP)
+ public NestedSet<String> staticFrameworkPaths();
}
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkSemantics.java b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkSemantics.java
index 983f3cd..e07179e 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/StarlarkSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/StarlarkSemantics.java
@@ -50,6 +50,7 @@
INCOMPATIBLE_NO_OUTPUT_ATTR_DEFAULT(StarlarkSemantics::incompatibleNoOutputAttrDefault),
INCOMPATIBLE_NO_TARGET_OUTPUT_GROUP(StarlarkSemantics::incompatibleNoTargetOutputGroup),
INCOMPATIBLE_NO_ATTR_LICENSE(StarlarkSemantics::incompatibleNoAttrLicense),
+ INCOMPATIBLE_OBJC_FRAMEWORK_CLEANUP(StarlarkSemantics::incompatibleObjcFrameworkCleanup),
NONE(null);
// Using a Function here makes the enum definitions far cleaner, and, since this is
@@ -170,6 +171,8 @@
public abstract boolean incompatibleNoTransitiveLoads();
+ public abstract boolean incompatibleObjcFrameworkCleanup();
+
public abstract boolean incompatibleRemapMainRepo();
public abstract boolean incompatibleRemoveNativeMavenJar();
@@ -226,6 +229,7 @@
.incompatibleNoSupportToolsInActionInputs(false)
.incompatibleNoTargetOutputGroup(false)
.incompatibleNoTransitiveLoads(true)
+ .incompatibleObjcFrameworkCleanup(false)
.incompatibleRemapMainRepo(false)
.incompatibleRemoveNativeMavenJar(false)
.incompatibleStaticNameResolutionInBuildFiles(false)
@@ -297,6 +301,8 @@
public abstract Builder incompatibleNoTransitiveLoads(boolean value);
+ public abstract Builder incompatibleObjcFrameworkCleanup(boolean value);
+
public abstract Builder incompatibleRemapMainRepo(boolean value);
public abstract Builder incompatibleRemoveNativeMavenJar(boolean value);
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/apple/FakeObjcProvider.java b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/apple/FakeObjcProvider.java
index 475de33..2a668ed 100644
--- a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/apple/FakeObjcProvider.java
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/apple/FakeObjcProvider.java
@@ -216,5 +216,25 @@
}
@Override
+ public NestedSet<String> dynamicFrameworkNames() {
+ return null;
+ }
+
+ @Override
+ public NestedSet<String> dynamicFrameworkPaths() {
+ return null;
+ }
+
+ @Override
+ public NestedSet<String> staticFrameworkNames() {
+ return null;
+ }
+
+ @Override
+ public NestedSet<String> staticFrameworkPaths() {
+ return null;
+ }
+
+ @Override
public void repr(SkylarkPrinter printer) {}
}
diff --git a/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java b/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java
index 08aad7f..5b08481 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java
@@ -153,6 +153,7 @@
"--incompatible_no_support_tools_in_action_inputs=" + rand.nextBoolean(),
"--incompatible_no_target_output_group=" + rand.nextBoolean(),
"--incompatible_no_transitive_loads=" + rand.nextBoolean(),
+ "--incompatible_objc_framework_cleanup=" + rand.nextBoolean(),
"--incompatible_remap_main_repo=" + rand.nextBoolean(),
"--incompatible_remove_native_maven_jar=" + rand.nextBoolean(),
"--incompatible_static_name_resolution_in_build_files=" + rand.nextBoolean(),
@@ -199,6 +200,7 @@
.incompatibleNoSupportToolsInActionInputs(rand.nextBoolean())
.incompatibleNoTargetOutputGroup(rand.nextBoolean())
.incompatibleNoTransitiveLoads(rand.nextBoolean())
+ .incompatibleObjcFrameworkCleanup(rand.nextBoolean())
.incompatibleRemapMainRepo(rand.nextBoolean())
.incompatibleRemoveNativeMavenJar(rand.nextBoolean())
.incompatibleStaticNameResolutionInBuildFiles(rand.nextBoolean())
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/AppleBinaryTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/AppleBinaryTest.java
index 597579a..42a021e 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/objc/AppleBinaryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/AppleBinaryTest.java
@@ -967,13 +967,23 @@
}
@Test
- public void testFrameworkDepLinkFlags() throws Exception {
- checkFrameworkDepLinkFlags(getRuleType(), new ExtraLinkArgs());
+ public void testFrameworkDepLinkFlagsPreCleanup() throws Exception {
+ checkFrameworkDepLinkFlags(getRuleType(), new ExtraLinkArgs(), false);
}
@Test
- public void testDylibDependencies() throws Exception {
- checkDylibDependencies(getRuleType(), new ExtraLinkArgs());
+ public void testFrameworkDepLinkFlagsPostCleanup() throws Exception {
+ checkFrameworkDepLinkFlags(getRuleType(), new ExtraLinkArgs(), true);
+ }
+
+ @Test
+ public void testDylibDependenciesPreCleanup() throws Exception {
+ checkDylibDependencies(getRuleType(), new ExtraLinkArgs(), false);
+ }
+
+ @Test
+ public void testDylibDependenciesPostCleanup() throws Exception {
+ checkDylibDependencies(getRuleType(), new ExtraLinkArgs(), true);
}
@Test
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/AppleDynamicLibraryTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/AppleDynamicLibraryTest.java
index d215df7..3e61fc8 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/objc/AppleDynamicLibraryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/AppleDynamicLibraryTest.java
@@ -136,13 +136,23 @@
}
@Test
- public void testFrameworkDepLinkFlags() throws Exception {
- checkFrameworkDepLinkFlags(RULE_TYPE, new ExtraLinkArgs("-dynamiclib"));
+ public void testFrameworkDepLinkFlagsPreCleanup() throws Exception {
+ checkFrameworkDepLinkFlags(RULE_TYPE, new ExtraLinkArgs("-dynamiclib"), false);
}
@Test
- public void testDylibDependencies() throws Exception {
- checkDylibDependencies(RULE_TYPE, new ExtraLinkArgs("-dynamiclib"));
+ public void testFrameworkDepLinkFlagsPostCleanup() throws Exception {
+ checkFrameworkDepLinkFlags(RULE_TYPE, new ExtraLinkArgs("-dynamiclib"), true);
+ }
+
+ @Test
+ public void testDylibDependenciesPreCleanup() throws Exception {
+ checkDylibDependencies(RULE_TYPE, new ExtraLinkArgs("-dynamiclib"), false);
+ }
+
+ @Test
+ public void testDylibDependenciesPostCleanup() throws Exception {
+ checkDylibDependencies(RULE_TYPE, new ExtraLinkArgs("-dynamiclib"), true);
}
@Test
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java
index 3675f2d..6810fd4 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcLibraryTest.java
@@ -518,9 +518,11 @@
}
@Test
- public void testCompileWithFrameworkImportsIncludesFlagsAndInputArtifacts() throws Exception {
+ public void testCompileWithFrameworkImportsIncludesFlagsAndInputArtifactsPreCleanup()
+ throws Exception {
useConfiguration("--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL);
- addBinWithTransitiveDepOnFrameworkImport();
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=false");
+ addBinWithTransitiveDepOnFrameworkImport(false);
CommandAction compileAction = compileAction("//lib:lib", "a.o");
assertThat(compileAction.getArguments()).doesNotContain("-framework");
@@ -534,6 +536,17 @@
}
@Test
+ public void testCompileWithFrameworkImportsIncludesFlagsPostCleanup() throws Exception {
+ useConfiguration("--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL);
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=true");
+ addBinWithTransitiveDepOnFrameworkImport(true);
+ CommandAction compileAction = compileAction("//lib:lib", "a.o");
+
+ assertThat(compileAction.getArguments()).doesNotContain("-framework");
+ assertThat(Joiner.on("").join(compileAction.getArguments())).contains("-Ffx");
+ }
+
+ @Test
public void testPrecompiledHeaders() throws Exception {
useConfiguration("--crosstool_top=" + MockObjcSupport.DEFAULT_OSX_CROSSTOOL);
scratch.file("objc/a.m");
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcRuleTestCase.java b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcRuleTestCase.java
index 8b05356..f9b6ae2 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcRuleTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcRuleTestCase.java
@@ -470,15 +470,21 @@
assertThat(action.getExecutionInfo()).containsKey(ExecutionRequirements.REQUIRES_DARWIN);
}
- protected ConfiguredTarget addBinWithTransitiveDepOnFrameworkImport() throws Exception {
- ConfiguredTarget lib = addLibWithDepOnFrameworkImport();
+ protected ConfiguredTarget addBinWithTransitiveDepOnFrameworkImport(boolean cleanup)
+ throws Exception {
+ ConfiguredTarget lib;
+ if (!cleanup) {
+ lib = addLibWithDepOnFrameworkImportPreCleanup();
+ } else {
+ lib = addLibWithDepOnFrameworkImportPostCleanup();
+ }
return createBinaryTargetWriter("//bin:bin")
.setList("deps", lib.getLabel().toString())
.write();
}
- protected ConfiguredTarget addLibWithDepOnFrameworkImport() throws Exception {
+ private ConfiguredTarget addLibWithDepOnFrameworkImportPreCleanup() throws Exception {
scratch.file(
"fx/defs.bzl",
"def _custom_static_framework_import_impl(ctx):",
@@ -505,6 +511,29 @@
.write();
}
+ private ConfiguredTarget addLibWithDepOnFrameworkImportPostCleanup() throws Exception {
+ scratch.file(
+ "fx/defs.bzl",
+ "def _custom_static_framework_import_impl(ctx):",
+ " return [apple_common.new_objc_provider(",
+ " framework_search_paths=depset(ctx.attr.framework_search_paths))]",
+ "custom_static_framework_import = rule(",
+ " _custom_static_framework_import_impl,",
+ " attrs={'framework_search_paths': attr.string_list()},",
+ ")");
+ scratch.file(
+ "fx/BUILD",
+ "load(':defs.bzl', 'custom_static_framework_import')",
+ "custom_static_framework_import(",
+ " name = 'fx',",
+ " framework_search_paths = ['fx/fx1.framework', 'fx/fx2.framework'],",
+ ")");
+ return createLibraryTargetWriter("//lib:lib")
+ .setAndCreateFiles("srcs", "a.m", "b.m", "private.h")
+ .setList("deps", "//fx:fx")
+ .write();
+ }
+
protected CommandAction compileAction(String ownerLabel, String objFileName) throws Exception {
Action archiveAction = archiveAction(ownerLabel);
return (CommandAction)
@@ -836,8 +865,8 @@
assertThat(protoProvider).isNotNull();
}
- protected void checkFrameworkDepLinkFlags(RuleType ruleType,
- ExtraLinkArgs extraLinkArgs) throws Exception {
+ protected void checkFrameworkDepLinkFlags(
+ RuleType ruleType, ExtraLinkArgs extraLinkArgs, boolean cleanup) throws Exception {
scratch.file(
"libs/defs.bzl",
"def _custom_static_framework_import_impl(ctx):",
@@ -861,6 +890,12 @@
" link_inputs = glob(['buzzbuzz.framework/*']),",
")");
+ if (!cleanup) {
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=true");
+ } else {
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=false");
+ }
+
ruleType.scratchTarget(scratch, "deps", "['//libs:objc_lib']");
CommandAction linkAction = linkAction("//x:x");
@@ -1558,11 +1593,7 @@
ruleType.target(scratch, "x", "x", "minimum_os_version", "'4.3.1'"));
}
- protected void checkDylibDependencies(RuleType ruleType,
- ExtraLinkArgs extraLinkArgs) throws Exception {
- ruleType.scratchTarget(scratch,
- "dylibs", "['//fx:framework_import']");
-
+ private void checkDylibDependenciesSetupFrameworkPreCleanup() throws Exception {
scratch.file(
"fx/defs.bzl",
"def _custom_dynamic_framework_import_impl(ctx):",
@@ -1584,6 +1615,43 @@
" name = 'framework_import',",
" link_inputs = glob(['MyFramework.framework/*']),",
")");
+ }
+
+ private void checkDylibDependenciesSetupFrameworkPostCleanup() throws Exception {
+ scratch.file(
+ "fx/defs.bzl",
+ "def _custom_dynamic_framework_import_impl(ctx):",
+ " return [",
+ " apple_common.new_objc_provider(",
+ " dynamic_framework_file=depset(ctx.files.link_inputs)),",
+ " apple_common.new_dynamic_framework_provider(objc=apple_common.new_objc_provider()),",
+ " ]",
+ "custom_dynamic_framework_import = rule(",
+ " _custom_dynamic_framework_import_impl,",
+ " attrs={'link_inputs': attr.label_list(allow_files=True)},",
+ ")");
+ scratch.file("fx/MyFramework.framework/MyFramework");
+ scratch.file(
+ "fx/BUILD",
+ "load(':defs.bzl', 'custom_dynamic_framework_import')",
+ "custom_dynamic_framework_import(",
+ " name = 'framework_import',",
+ " link_inputs = ['MyFramework.framework/MyFramework'],",
+ ")");
+ }
+
+ protected void checkDylibDependencies(
+ RuleType ruleType, ExtraLinkArgs extraLinkArgs, boolean cleanup) throws Exception {
+ ruleType.scratchTarget(scratch, "dylibs", "['//fx:framework_import']");
+
+ if (!cleanup) {
+ checkDylibDependenciesSetupFrameworkPreCleanup();
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=false");
+ } else {
+ checkDylibDependenciesSetupFrameworkPostCleanup();
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=true");
+ }
+
useConfiguration("--ios_multi_cpus=i386,x86_64");
Action lipobinAction = lipoBinAction("//x:x");
diff --git a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcSkylarkTest.java b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcSkylarkTest.java
index 5b6cc48..67c168e 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcSkylarkTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/objc/ObjcSkylarkTest.java
@@ -1590,4 +1590,168 @@
boolean runMemleaks = (boolean) skylarkTarget.get("run_memleaks");
assertThat(runMemleaks).isEqualTo(expectedValue);
}
+
+ private void addDummyObjcProviderRule(String name) throws Exception {
+ scratch.file(
+ "fx/defs.bzl",
+ "def _my_rule_impl(ctx):",
+ " objc = apple_common.new_objc_provider()",
+ String.format(" return struct(names=objc.%s)", name),
+ "my_rule = rule(implementation = _my_rule_impl,",
+ " attrs = {})");
+ scratch.file("fx/BUILD", "load(':defs.bzl', 'my_rule')", "my_rule(name = 'lib')");
+ }
+
+ private void testObjcProviderHas(String name) throws Exception {
+ addDummyObjcProviderRule(name);
+ assertThat(view.hasErrors(getConfiguredTarget("//fx:lib"))).isFalse();
+ }
+
+ private void testObjcProviderDoesNotHave(String name) throws Exception {
+ addDummyObjcProviderRule(name);
+ try {
+ getConfiguredTarget("//fx:lib");
+ fail("Should throw AssertionError");
+ } catch (AssertionError e) {
+ if (name.endsWith("()")) {
+ assertThat(e).hasMessageThat().contains("'ObjcProvider' has no method " + name);
+ } else {
+ assertThat(e).hasMessageThat().contains("'ObjcProvider' has no field '" + name + "'");
+ }
+ }
+ }
+
+ @Test
+ public void testObjcProviderDynamicFrameworkDirPreCleanup() throws Exception {
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=false");
+ testObjcProviderHas("dynamic_framework_dir");
+ }
+
+ @Test
+ public void testObjcProviderFrameworkDirPreCleanup() throws Exception {
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=false");
+ testObjcProviderHas("framework_dir");
+ }
+
+ @Test
+ public void testObjcProviderDynamicFrameworkNamesPreCleanup() throws Exception {
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=false");
+ testObjcProviderDoesNotHave("dynamic_framework_names");
+ }
+
+ @Test
+ public void testObjcProviderDynamicFrameworkPathsPreCleanup() throws Exception {
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=false");
+ testObjcProviderDoesNotHave("dynamic_framework_paths");
+ }
+
+ @Test
+ public void testObjcProviderStaticFrameworkNamesPreCleanup() throws Exception {
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=false");
+ testObjcProviderDoesNotHave("static_framework_names");
+ }
+
+ @Test
+ public void testObjcProviderStaticFrameworkPathsPreCleanup() throws Exception {
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=false");
+ testObjcProviderDoesNotHave("static_framework_paths");
+ }
+
+ @Test
+ public void testObjcProviderDynamicFrameworkDirPostCleanup() throws Exception {
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=true");
+ testObjcProviderDoesNotHave("dynamic_framework_dir");
+ }
+
+ @Test
+ public void testObjcProviderFrameworkDirPostCleanup() throws Exception {
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=true");
+ testObjcProviderDoesNotHave("framework_dir");
+ }
+
+ @Test
+ public void testObjcProviderDynamicFrameworkNamesPostCleanup() throws Exception {
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=true");
+ testObjcProviderHas("dynamic_framework_names");
+ }
+
+ @Test
+ public void testObjcProviderDynamicFrameworkPathsPostCleanup() throws Exception {
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=true");
+ testObjcProviderHas("dynamic_framework_paths");
+ }
+
+ @Test
+ public void testObjcProviderStaticFrameworkNamesPostCleanup() throws Exception {
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=true");
+ testObjcProviderHas("static_framework_names");
+ }
+
+ @Test
+ public void testObjcProviderStaticFrameworkPathsPostCleanup() throws Exception {
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=true");
+ testObjcProviderHas("static_framework_paths");
+ }
+
+ @Test
+ public void testStaticFrameworkApiPostCleanup() throws Exception {
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=true");
+
+ scratch.file(
+ "fx/defs.bzl",
+ "def _custom_static_framework_import_impl(ctx):",
+ " return [apple_common.new_objc_provider(",
+ " static_framework_file=depset(ctx.files.link_inputs))]",
+ "custom_static_framework_import = rule(",
+ " _custom_static_framework_import_impl,",
+ " attrs={'link_inputs': attr.label_list(allow_files=True)},",
+ ")");
+ scratch.file("fx/fx1.framework/fx1");
+ scratch.file("fx/fx2.framework/fx2");
+ scratch.file(
+ "fx/BUILD",
+ "load(':defs.bzl', 'custom_static_framework_import')",
+ "custom_static_framework_import(",
+ " name = 'framework',",
+ " link_inputs = ['fx1.framework/fx1', 'fx2.framework/fx2'],",
+ ")");
+
+ ConfiguredTarget framework = getConfiguredTarget("//fx:framework");
+ ObjcProvider objc = framework.get(ObjcProvider.SKYLARK_CONSTRUCTOR);
+ assertThat(Artifact.toRootRelativePaths(objc.staticFrameworkFile()))
+ .containsExactly("fx/fx1.framework/fx1", "fx/fx2.framework/fx2");
+ assertThat(objc.staticFrameworkNames()).containsExactly("fx1", "fx2");
+ assertThat(objc.staticFrameworkPaths()).containsExactly("fx");
+ }
+
+ @Test
+ public void testDynamicFrameworkApiPostCleanup() throws Exception {
+ setSkylarkSemanticsOptions("--incompatible_objc_framework_cleanup=true");
+
+ scratch.file(
+ "fx/defs.bzl",
+ "def _custom_dynamic_framework_import_impl(ctx):",
+ " return [apple_common.new_objc_provider(",
+ " dynamic_framework_file=depset(ctx.files.link_inputs))]",
+ "custom_dynamic_framework_import = rule(",
+ " _custom_dynamic_framework_import_impl,",
+ " attrs={'link_inputs': attr.label_list(allow_files=True)},",
+ ")");
+ scratch.file("fx/fx1.framework/fx1");
+ scratch.file("fx/fx2.framework/fx2");
+ scratch.file(
+ "fx/BUILD",
+ "load(':defs.bzl', 'custom_dynamic_framework_import')",
+ "custom_dynamic_framework_import(",
+ " name = 'framework',",
+ " link_inputs = ['fx1.framework/fx1', 'fx2.framework/fx2'],",
+ ")");
+
+ ConfiguredTarget framework = getConfiguredTarget("//fx:framework");
+ ObjcProvider objc = framework.get(ObjcProvider.SKYLARK_CONSTRUCTOR);
+ assertThat(Artifact.toRootRelativePaths(objc.dynamicFrameworkFile()))
+ .containsExactly("fx/fx1.framework/fx1", "fx/fx2.framework/fx2");
+ assertThat(objc.dynamicFrameworkNames()).containsExactly("fx1", "fx2");
+ assertThat(objc.dynamicFrameworkPaths()).containsExactly("fx");
+ }
}