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 9252d408c608c2..bed58dd2237f1e 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 @@ cc_common = _builtins.toplevel.cc_common 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 @@ def _build_linking_context(ctx, feature_configuration, cc_toolchain, objc_provid 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 @@ def _static_library( 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 c54a916095f7ad..ecef14036cbc3a 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 @@ public void testDisableCoverageDoesNotPropagateSupportFiles() throws Exception { assertThat(instrumentedFilesInfo.getCoverageSupportFiles().toList()).isEmpty(); } + + private ImmutableList 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 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 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 userLinkFlagsWithoutFrameworkFlags = + userLinkFlags.stream().filter(s -> !s.equals("-framework")).collect(toImmutableList()); + assertThat(userLinkFlagsWithoutFrameworkFlags).containsNoDuplicates(); + } }