Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Swift info provider during framework packaging to avoid symbol redefinition #53

Merged
merged 9 commits into from
May 11, 2020

Conversation

gyfelton
Copy link
Contributor

@gyfelton gyfelton commented Apr 28, 2020

With updates on rules_swift, if a framework Foo depends on target Bar1 and Bar2, while Bar1 also depends on Bar2, without changes in this PR, bazel will produce 2 module maps for Bar2, causes symbol redefinition error (in bazel-out, it will produce Bar2.framework and Bar2-modulemap which contains Bar2.modulemap).

The fix is to provide the swift_info while packing framework Foo so that rules_swift won't produce the Bar2-modulemap.

This PR also points to latest rules_swift and rules_apple that we can support.
This PR also removes a patch fix that is no longer useful with the intro of swift_info
Major work is done by @segiddins in this PR

@segiddins
Copy link
Member

what is the output of this implementation? Is [objc_provider, swift_provider, default_info_provider] different from [swift_provider, objc_provider, default_info_provider] when I swap their order?

The order doesn't matter, it's functionally a set of the different providers -- there can only be one provider of each "type" per target returned

what it means to have ** in front of objc_provider_fields?

It's a "splat" that turns key-value pairs from a dictionary into keyword arguments

Is SwiftInfo the counter part of apple_common.Objc? Counter part meaning they are representation of a source file, where one is for objc class and one is for swift?

yes, they are counterparts. They don't represent source files, but rather are bazel "providers", which are the ways of propagating information about how to consume the target to the other targets that depend on this one

@segiddins segiddins force-pushed the swift_info_provider branch from 9fc92cb to a613799 Compare May 4, 2020 21:02
@@ -25,7 +25,7 @@ def apple_framework(name, apple_library = apple_library, **kwargs):

def _find_framework_dir(outputs):
for output in outputs:
prefix = output.path.split(".framework/")[0]
prefix = output.path.rsplit(".framework/", 1)[0]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can give an example of how this changes what's inside the prefix variable?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It only would if output.path contained multiple instances of .framework, in which case now it will return the innermost framework, instead of the outermost

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so a.framework/b/c.framework/c to give a.framework/b/c.framework

]

return [
apple_common.new_objc_provider(**objc_provider_fields),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if no change on objc_provider, why not having objc_provider = apple_common.new_objc_provider(**objc_provider_fields) as b4?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's no reason to capture the providers in locals, since they're only returned and never read from.

return [objc_provider, swift_provider, default_info_provider]
# gather swift info fields
swift_info_fields = {
"swift_infos": [dep[SwiftInfo] for dep in ctx.attr.transitive_deps if SwiftInfo in dep],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for each of the transitive dependencies of ctr.attr (the current context we are in), if there is SwiftInfo in dep, take it out and add to an array. This array then becomes the value with key = "swift_infos"


if swiftmodule_out:
# only add a swift module to the SwiftInfo if we've actually got a swiftmodule
swiftmodule_name = paths.split_extension(swiftmodule_in.basename)[0]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

example of paths? I am confused on this one
Also why not just use info inside swiftmodule_in as the swiftmodule_name ? I would look at what's actually inside the swiftmodule_in to figure this part out

# Swift won't find swiftmodule files inside of frameworks whose name doesn't match the
# module name. It's annoying (since clang finds them just fine), but we have no choice but to point to the
# original swift module/doc, so that swift can find it.
swift_module = swift_common.create_swift_module(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so this overrides the swift_module we just created because its name does not match the framework name...

@gyfelton gyfelton changed the title [WIP]Swift info provider Use Swift info provider during framework packaging to avoid symbol redefinition May 8, 2020
@gyfelton gyfelton requested a review from amberdixon May 8, 2020 19:54
@gyfelton gyfelton merged commit 0ee2eb5 into master May 11, 2020
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")

swift_library(
name = "frameworkBar",
Copy link
Contributor

@acecilia acecilia May 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by frameworkBar? Could you add some information explaining what is being tested in this example? Or change the frameworks names so it is more clear what they are used for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can give some suggestion on the name? In this case what happened is there is a target to compile a swift library called frameworkBar that depends FrameworkFoo, then it was packaged into a framework with a name Unique_FrameworkBar which also depends on FrameworkFoo. Without the change introduced in this PR, it will result in redefinition of module FrameworkBar because it is not properly propagated through the swift info. Does this makes sense?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants