[swift-dev] Feature Proposal to improve Mixed Frameworks support

Gonzalo Larralde gonzalolarralde at gmail.com
Thu Jun 29 08:34:35 CDT 2017


I wanted to bring a few points into attention to discuss potential
improvements on Mixed Frameworks support. The current status for Mixed
Frameworks present some challenges, one specifically being how the Swift
compiler generates the ObjC Interface Header.

At this moment, there's a detection procedure based on the presence of an
entry point definition (either using the main file argument, or
@UIApplicationMain). The ObjC Interface Header writer
(swift/lib/PrintAsObjC/PrintAsObjC.cpp) is using this detection to
determine if the minimum accessibility level to be exported is either
`internal` (for app targets) or `public` (for framework targets). This can
be observed here:
https://github.com/apple/swift/blob/master/lib/FrontendTool/FrontendTool.cpp#L652-L657

The result of this is a difference on how default visibility is exposed to
ObjC code in the same compilation scope.

Having this initial piece of code:

```
public class Test: NSObject {
public foo() {}
func bar() {}
}
```

results on the following Interface Header for Main App targets

<target-name>-swift.h
```
@interface Test : NSObject
- (void)foo;
- (void)bar;
@end
```

and the following for Frameworks

<target-name>-swift.h
```
@interface Test : NSObject
- (void)foo;
@end
```

This is clearly correct for the publicly visible interface of the
framework, but not quite the expected result for the ObjC code compiled in
the same target. In that scenario it would make more sense to me that all
the `internal` methods are visible.

A potential solution for this problem is to generate two Interface Headers,
one that exports all the `public` and `open` entities and members, and an
additional header exposing internal entities and declaring categories to
public entities and exposing internal members.

Something like:

<target-name>-swift-internal.h
```
@interface Test (InternalMembers)
- (void)bar;
@end
```

After that it'll be Xcode's responsability to create both files, and mark
them as Public and Project in the Headers Build Phase.

An initial implementation that I think would make sense in case this
solution is accepted could be modifying the signature of
`swift::printAsObjC` to require the list of access levels to export as a
bitmask instead of just getting the minimum. That will enable the exporter
to create the following set of files:

* Internal, Public, Open > <target-name>-swift.h for app targets
* Public, Open > <target-name>-swift.h for framework targets
* Internal > <target-name>-swift-internal.h for the internal entities and
members on framework targets.

To make this happen a new argument needs to be passed to the compiler call.
When it's not passed the default behaviour would remain the same, but when
it is the behaviour needs to be explicitly defined. One option is to just
get the explicit list of access levels to export (something like
`-export=internal,public,open`) or export levels to be defined (0 for app
targets, 1 for public framework targets and 2 for the internal header
framework targets for example)

I hope this feature proposal is complete enough to properly define the
scope and discuss the viability of a possible solution. Otherwise please
let me know.

Thanks.

--
Slds,

Gonzalo.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-dev/attachments/20170629/4b915c90/attachment.html>


More information about the swift-dev mailing list