Propagate user link flags from `deps` on `objc_library` CcInfo provider
Currently `objc_library` propagates frameworks to the CcInfo provider,
based on the target's built ObjC provider `sdk_frameworks` field. This
change aims to propagate both dylibs and frameworks from both the
ObjC provider, and merged `deps` CcInfo's.
PiperOrigin-RevId: 438387102
diff --git a/src/main/starlark/builtins_bzl/common/objc/objc_library.bzl b/src/main/starlark/builtins_bzl/common/objc/objc_library.bzl
index 9252d40..bed58dd 100644
--- a/src/main/starlark/builtins_bzl/common/objc/objc_library.bzl
+++ b/src/main/starlark/builtins_bzl/common/objc/objc_library.bzl
@@ -26,9 +26,6 @@
coverage_common = _builtins.toplevel.coverage_common
apple_common = _builtins.toplevel.apple_common
-def _rule_error(msg):
- fail(msg)
-
def _attribute_error(attr_name, msg):
fail("in attribute '" + attr_name + "': " + msg)
@@ -71,10 +68,10 @@
libraries.extend(objc_provider.cc_library.to_list())
- sdk_frameworks = objc_provider.sdk_framework.to_list()
- user_link_flags = []
- for sdk_framework in sdk_frameworks:
- user_link_flags.append(["-framework", sdk_framework])
+ user_link_flags = _user_link_flags(
+ cc_info = merged_objc_library_cc_infos,
+ objc_provider = objc_provider,
+ )
direct_linker_inputs = []
if len(user_link_flags) != 0 or len(libraries) != 0 or objc_provider.linkstamp:
@@ -106,6 +103,41 @@
alwayslink = alwayslink,
)
+def _user_link_flags(*, cc_info, objc_provider):
+ """Builds objc_library CcInfo user link flags for frameworks and dylibs.
+
+ Args:
+ cc_info: Merged CcInfo provider from objc_library target deps.
+ objc_provider: Current objc_library ObjC provider.
+ Returns:
+ List of user link flags for frameworks and dylibs.
+ """
+
+ sdk_dylibs = objc_provider.sdk_dylib.to_list()
+ sdk_frameworks = objc_provider.sdk_framework.to_list()
+
+ all_user_link_flags = []
+ all_user_link_flags.extend(objc_provider.linkopt.to_list())
+
+ for linker_input in cc_info.linking_context.linker_inputs.to_list():
+ all_user_link_flags.extend(linker_input.user_link_flags)
+
+ for i, user_link_flag in enumerate(all_user_link_flags):
+ if user_link_flag.startswith("-l"):
+ sdk_dylibs.append("lib" + user_link_flag[2:])
+ elif user_link_flag == "-framework":
+ sdk_frameworks.append(all_user_link_flags[i + 1])
+
+ sdk_user_link_flags = []
+ for sdk_framework in depset(sdk_frameworks).to_list():
+ sdk_user_link_flags.append(["-framework", sdk_framework])
+ for sdk_dylib in depset(sdk_dylibs).to_list():
+ if sdk_dylib.startswith("lib"):
+ sdk_dylib = sdk_dylib[3:]
+ sdk_user_link_flags.append(["-l" + sdk_dylib])
+
+ return sdk_user_link_flags
+
def _objc_library_impl(ctx):
_validate_attributes(ctx)
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 c54a916..ecef140 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
@@ -53,6 +53,7 @@
import com.google.devtools.build.lib.analysis.test.InstrumentedFilesInfo;
import com.google.devtools.build.lib.analysis.util.AnalysisMock;
import com.google.devtools.build.lib.analysis.util.ScratchAttributeWriter;
+import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.packages.NoSuchTargetException;
@@ -2444,4 +2445,96 @@
assertThat(instrumentedFilesInfo.getCoverageSupportFiles().toList()).isEmpty();
}
+
+ private ImmutableList<String> getCcInfoUserLinkFlagsFromTarget(String target)
+ throws LabelSyntaxException {
+ return getConfiguredTarget(target)
+ .get(CcInfo.PROVIDER)
+ .getCcLinkingContext()
+ .getUserLinkFlags()
+ .toList()
+ .stream()
+ .map(CcLinkingContext.LinkOptions::get)
+ .flatMap(List::stream)
+ .collect(toImmutableList());
+ }
+
+ @Test
+ public void testSdkUserLinkFlagsFromSdkFieldsAndLinkoptsArePropagatedOnCcInfo() throws Exception {
+ scratch.file(
+ "x/BUILD",
+ "objc_library(",
+ " name = 'foo',",
+ " linkopts = [",
+ " '-lxml2',",
+ " '-framework AVFoundation',",
+ " ],",
+ " sdk_dylibs = ['libz'],",
+ " sdk_frameworks = ['CoreData'],",
+ " deps = [':bar', ':car'],",
+ ")",
+ "objc_library(",
+ " name = 'bar',",
+ " linkopts = [",
+ " '-lsqlite3',",
+ " ],",
+ " sdk_frameworks = ['Foundation'],",
+ ")",
+ "objc_library(",
+ " name = 'car',",
+ " linkopts = [",
+ " '-framework UIKit',",
+ " ],",
+ " sdk_dylibs = ['libc++'],",
+ ")");
+
+ ImmutableList<String> userLinkFlags = getCcInfoUserLinkFlagsFromTarget("//x:foo");
+ assertThat(userLinkFlags).isNotEmpty();
+ assertThat(userLinkFlags).containsAtLeast("-framework", "AVFoundation").inOrder();
+ assertThat(userLinkFlags).containsAtLeast("-framework", "CoreData").inOrder();
+ assertThat(userLinkFlags).containsAtLeast("-framework", "Foundation").inOrder();
+ assertThat(userLinkFlags).containsAtLeast("-framework", "UIKit").inOrder();
+ assertThat(userLinkFlags).containsAtLeast("-lz", "-lc++", "-lxml2", "-lsqlite3");
+ }
+
+ @Test
+ public void testNoDuplicateSdkUserLinkFlagsFromMultipleDepsOnCcInfo() throws Exception {
+ scratch.file(
+ "x/BUILD",
+ "objc_library(",
+ " name = 'foo',",
+ " linkopts = [",
+ " '-lsqlite3',",
+ " '-framework UIKit',",
+ " ],",
+ " sdk_dylibs = ['libc++'],",
+ " sdk_frameworks = ['Foundation'],",
+ " deps = [':bar', ':car'],",
+ ")",
+ "objc_library(",
+ " name = 'bar',",
+ " linkopts = [",
+ " '-lsqlite3',",
+ " '-framework CoreData',",
+ " ],",
+ " sdk_frameworks = ['Foundation'],",
+ ")",
+ "objc_library(",
+ " name = 'car',",
+ " linkopts = [",
+ " '-framework UIKit',",
+ " '-framework CoreData',",
+ " ],",
+ " sdk_dylibs = ['libc++'],",
+ ")");
+ ImmutableList<String> userLinkFlags = getCcInfoUserLinkFlagsFromTarget("//x:foo");
+ assertThat(userLinkFlags).isNotEmpty();
+ assertThat(userLinkFlags).containsAtLeast("-framework", "CoreData").inOrder();
+ assertThat(userLinkFlags).containsAtLeast("-framework", "Foundation").inOrder();
+ assertThat(userLinkFlags).containsAtLeast("-framework", "UIKit").inOrder();
+ assertThat(userLinkFlags).containsAtLeast("-lc++", "-lsqlite3");
+ ImmutableList<String> userLinkFlagsWithoutFrameworkFlags =
+ userLinkFlags.stream().filter(s -> !s.equals("-framework")).collect(toImmutableList());
+ assertThat(userLinkFlagsWithoutFrameworkFlags).containsNoDuplicates();
+ }
}