[RFC] Modify the build system to enable/disable ObjC interop for any platform

Hello all!

While reviewing https://github.com/apple/swift/pull/5904, I had a crazy
thought, and I'd like to get some feedback on it.

Here's my original comment <
Add support for building Swift on Windows with clang-cl and MSVC by hughbe · Pull Request #5904 · apple/swift · GitHub.

Basically, I notice that we have two sets of targets we compile the Swift
runtime and standard library for:

1. 'ALL_APPLE_PLATFORMS', which is composed of macOS, iOS, tvOS, and
watchOS.
2. The other platforms: Linux, FreeBSD, Android, Cygwin, and (as of the
pull request above) Windows.

In other words:

1. All the platforms that support Objective-C interop. I suggest we call
these 'OBJC_INTEROP_PLATFORMS' in CMake.
2. All the platforms that don't. I suggest we call these
'NO_OBJC_INTEROP_PLATFORMS' in CMake.

···

---

I think the above is a good idea, regardless of how you feel about my
other, zanier thought:

Over the weekend I learned of the mulle-objc project <
https://mulle-objc.github.io>. It boasts an Objective-C compiler and
runtime that works on Linux.

Now, I don't know if Swift's Objective-C interop will work completely with
mulle-objc, but I did a bit of experimenting over the weekend, and it seems
possible. But one obstacle is the fact that the Swift build system
conflates "an Apple target" with "capable of Objective-C interop." To even
start working with mulle-objc, I had to remove a lot of `#ifdef __APPLE__`
in the code.

So I'd like to propose that we augment the build system to allow a person
compiling the Swift project to turn Objective-C interop on or off for any
given target. That would allow me to compile for Linux, but with
Objective-C interop enabled. Alternatively, I could compile for macOS, but
with Objective-C interop disabled.

Any thoughts? I could clean up my local implementation and send a pull
request, provided there's interest.

- Brian Gesiak

Hello all!

While reviewing https://github.com/apple/swift/pull/5904, I had a crazy thought, and I'd like to get some feedback on it.

Here's my original comment <Add support for building Swift on Windows with clang-cl and MSVC by hughbe · Pull Request #5904 · apple/swift · GitHub.

Basically, I notice that we have two sets of targets we compile the Swift runtime and standard library for:

1. 'ALL_APPLE_PLATFORMS', which is composed of macOS, iOS, tvOS, and watchOS.
2. The other platforms: Linux, FreeBSD, Android, Cygwin, and (as of the pull request above) Windows.

In other words:

1. All the platforms that support Objective-C interop. I suggest we call these 'OBJC_INTEROP_PLATFORMS' in CMake.
2. All the platforms that don't. I suggest we call these 'NO_OBJC_INTEROP_PLATFORMS' in CMake.

---

I think the above is a good idea, regardless of how you feel about my other, zanier thought:

Over the weekend I learned of the mulle-objc project <https://mulle-objc.github.io <https://mulle-objc.github.io/&gt;&gt;\. It boasts an Objective-C compiler and runtime that works on Linux.

Now, I don't know if Swift's Objective-C interop will work completely with mulle-objc, but I did a bit of experimenting over the weekend, and it seems possible. But one obstacle is the fact that the Swift build system conflates "an Apple target" with "capable of Objective-C interop." To even start working with mulle-objc, I had to remove a lot of `#ifdef __APPLE__` in the code.

Yeah. I’d expect the main work to be in the Swift build system, the Swift driver (which decides when to pass down “-enable-objc-interop” to the frontend), and some “#ifdef __APPLE__” in the runtime that should use “if SWIFT_OBJC_INTEROP” instead.

Swift does bake in a bit of knowledge of the Darwin Objective-C runtime, so one would likely have to tease that out of IRGen and the runtime to make mulle-objc interoperability possible. Clang has some abstractions in its CodeGen (equivalent to Swift’s IRGen) to support multiple Objective-C runtimes, and we would need something similar for Swift. That’d take a bunch of refactoring.

So I'd like to propose that we augment the build system to allow a person compiling the Swift project to turn Objective-C interop on or off for any given target. That would allow me to compile for Linux, but with Objective-C interop enabled. Alternatively, I could compile for macOS, but with Objective-C interop disabled.

Any thoughts? I could clean up my local implementation and send a pull request, provided there's interest.

It would be great to decouple “is an Apple platform” from “provides Objective-C interoperability”!

As you noted, there are two potential use cases for this:

1) Objective-C interoperability on non-Apple platforms: I (personally) don’t find this hugely motivating, because Apple platforms have the only significant stack of existing frameworks that Swift needs to interoperate with. Plus, there’s no single clear “winner” when it comes to picking an Objective-C runtime on non-Darwin platforms (e.g., what about GNUstep?), and (as I said above) actually supporting another Objective-C runtime is likely to require a bunch of refactoring in IRGen and runtime.
2) Swift-without-Objective-C interoperability on Apple platforms: this would be *extremely* useful for people writing cross-platform code in Swift, who want to make sure their code works the same way when using Darwin’s Foundation vs. the core libraries’ Foundation. I know that the Foundation developers would be particularly pleased with this.

  - Doug

···

On Nov 28, 2016, at 7:26 AM, Brian Gesiak via swift-dev <swift-dev@swift.org> wrote:

It's not only the build system, but the IRGen and runtime implementation of ObjC interop is also heavily biased towards Apple's implementations of the ObjC runtime and Foundation on Darwin. Just changing all those #ifdef __APPLE__ s to if SWIFT_OBJC_INTEROP is not going to get you very far working with another ObjC implementation. As Doug noted, supporting ObjC-less Darwin would on the other hand be very useful!

-Joe

···

On Nov 28, 2016, at 7:26 AM, Brian Gesiak via swift-dev <swift-dev@swift.org> wrote:

Hello all!

While reviewing https://github.com/apple/swift/pull/5904, I had a crazy thought, and I'd like to get some feedback on it.

Here's my original comment <Add support for building Swift on Windows with clang-cl and MSVC by hughbe · Pull Request #5904 · apple/swift · GitHub.

Basically, I notice that we have two sets of targets we compile the Swift runtime and standard library for:

1. 'ALL_APPLE_PLATFORMS', which is composed of macOS, iOS, tvOS, and watchOS.
2. The other platforms: Linux, FreeBSD, Android, Cygwin, and (as of the pull request above) Windows.

In other words:

1. All the platforms that support Objective-C interop. I suggest we call these 'OBJC_INTEROP_PLATFORMS' in CMake.
2. All the platforms that don't. I suggest we call these 'NO_OBJC_INTEROP_PLATFORMS' in CMake.

---

I think the above is a good idea, regardless of how you feel about my other, zanier thought:

Over the weekend I learned of the mulle-objc project <https://mulle-objc.github.io>. It boasts an Objective-C compiler and runtime that works on Linux.

Now, I don't know if Swift's Objective-C interop will work completely with mulle-objc, but I did a bit of experimenting over the weekend, and it seems possible. But one obstacle is the fact that the Swift build system conflates "an Apple target" with "capable of Objective-C interop." To even start working with mulle-objc, I had to remove a lot of `#ifdef __APPLE__` in the code.

Right. If you really wanted to support using Swift with a different Objective-C ABIs, I think the first step would be to do some work in clang to expose an abstract API for building classes. You'd still need *some* ABI-specific code in Swift IRGen, I expect, but it ought to be possible to re-use the majority of Clang's ObjC targeting code.

John.

···

On Nov 28, 2016, at 1:33 PM, Joe Groff via swift-dev <swift-dev@swift.org> wrote:

On Nov 28, 2016, at 7:26 AM, Brian Gesiak via swift-dev <swift-dev@swift.org> wrote:

Hello all!

While reviewing https://github.com/apple/swift/pull/5904, I had a crazy thought, and I'd like to get some feedback on it.

Here's my original comment <https://github.com/apple/swift/pull/5904#discussion_r89797900&gt;\.

Basically, I notice that we have two sets of targets we compile the Swift runtime and standard library for:

1. 'ALL_APPLE_PLATFORMS', which is composed of macOS, iOS, tvOS, and watchOS.
2. The other platforms: Linux, FreeBSD, Android, Cygwin, and (as of the pull request above) Windows.

In other words:

1. All the platforms that support Objective-C interop. I suggest we call these 'OBJC_INTEROP_PLATFORMS' in CMake.
2. All the platforms that don't. I suggest we call these 'NO_OBJC_INTEROP_PLATFORMS' in CMake.

---

I think the above is a good idea, regardless of how you feel about my other, zanier thought:

Over the weekend I learned of the mulle-objc project <https://mulle-objc.github.io>. It boasts an Objective-C compiler and runtime that works on Linux.

Now, I don't know if Swift's Objective-C interop will work completely with mulle-objc, but I did a bit of experimenting over the weekend, and it seems possible. But one obstacle is the fact that the Swift build system conflates "an Apple target" with "capable of Objective-C interop." To even start working with mulle-objc, I had to remove a lot of `#ifdef __APPLE__` in the code.

It's not only the build system, but the IRGen and runtime implementation of ObjC interop is also heavily biased towards Apple's implementations of the ObjC runtime and Foundation on Darwin. Just changing all those #ifdef __APPLE__ s to if SWIFT_OBJC_INTEROP is not going to get you very far working with another ObjC implementation. As Doug noted, supporting ObjC-less Darwin would on the other hand be very useful!

Thanks all! It's great to hear that this wouldn't be completely unwelcome
-- especially Swift Darwin with Objective-C interop disabled.

I'll try and send a patch sometime soon -- although I'm busy with work
stuff, so at the latest it'll be sometime in December... in the meantime, I
created a task for it: https://bugs.swift.org/browse/SR-3292\. Feel free to
comment there, or to claim the task for yourself. :)

- Brian Gesiak

···

On Mon, Nov 28, 2016 at 5:02 PM, John McCall <rjmccall@apple.com> wrote:

> On Nov 28, 2016, at 1:33 PM, Joe Groff via swift-dev < > swift-dev@swift.org> wrote:
>> On Nov 28, 2016, at 7:26 AM, Brian Gesiak via swift-dev < > swift-dev@swift.org> wrote:
>>
>> Hello all!
>>
>> While reviewing https://github.com/apple/swift/pull/5904, I had a
crazy thought, and I'd like to get some feedback on it.
>>
>> Here's my original comment <Apple · GitHub
swift/pull/5904#discussion_r89797900>.
>>
>> Basically, I notice that we have two sets of targets we compile the
Swift runtime and standard library for:
>>
>> 1. 'ALL_APPLE_PLATFORMS', which is composed of macOS, iOS, tvOS, and
watchOS.
>> 2. The other platforms: Linux, FreeBSD, Android, Cygwin, and (as of the
pull request above) Windows.
>>
>> In other words:
>>
>> 1. All the platforms that support Objective-C interop. I suggest we
call these 'OBJC_INTEROP_PLATFORMS' in CMake.
>> 2. All the platforms that don't. I suggest we call these
'NO_OBJC_INTEROP_PLATFORMS' in CMake.
>>
>> ---
>>
>> I think the above is a good idea, regardless of how you feel about my
other, zanier thought:
>>
>> Over the weekend I learned of the mulle-objc project <
https://mulle-objc.github.io>. It boasts an Objective-C compiler and
runtime that works on Linux.
>>
>> Now, I don't know if Swift's Objective-C interop will work completely
with mulle-objc, but I did a bit of experimenting over the weekend, and it
seems possible. But one obstacle is the fact that the Swift build system
conflates "an Apple target" with "capable of Objective-C interop." To even
start working with mulle-objc, I had to remove a lot of `#ifdef __APPLE__`
in the code.
>
> It's not only the build system, but the IRGen and runtime implementation
of ObjC interop is also heavily biased towards Apple's implementations of
the ObjC runtime and Foundation on Darwin. Just changing all those #ifdef
__APPLE__ s to if SWIFT_OBJC_INTEROP is not going to get you very far
working with another ObjC implementation. As Doug noted, supporting
ObjC-less Darwin would on the other hand be very useful!

Right. If you really wanted to support using Swift with a different
Objective-C ABIs, I think the first step would be to do some work in clang
to expose an abstract API for building classes. You'd still need *some*
ABI-specific code in Swift IRGen, I expect, but it ought to be possible to
re-use the majority of Clang's ObjC targeting code.

John.

To be clear, I didn't mean to discourage you (or anyone else watching) from adding support for non-Apple Objective-C platforms; I only wanted to make it clear that it almost definitely won't Just Work by trying to compile the existing code for a non-Apple target. Like John said, we should leverage higher-level interfaces in Clang's CodeGen to emit ObjC metadata; right now, we hardcode the Apple layouts of everything.

-Joe

···

On Nov 29, 2016, at 12:24 PM, Brian Gesiak <modocache@gmail.com> wrote:

Thanks all! It's great to hear that this wouldn't be completely unwelcome -- especially Swift Darwin with Objective-C interop disabled.

I’ll go the other way and say I do want to discourage this. Swift on other platforms actually is benefitting from not having ObjC interop—as a tiny example, dynamic casts don’t have to do something different to account for Objective-C’s duck typing. The CoreFoundation used in swift-corelibs-foundation ought to mimic the layout of Swift classes, not Objective-C ones, so now you can’t use Foundation. I’m being pessimistic, but if this is a “just-for-fun” project I think there are better ones, and if this is a “I want to ship something” project I think it’ll run into trouble down the line. I’d rather not add more constraints and configurations expected to work, especially when we’re still porting Swift to different platforms without ObjC interop.

Swift-without-ObjC on Darwin is a more interesting project: it gives us a better ability to test the corelibs properly, among other things. I’m not sure whether you’d be able to mix that in a project that does use Swift-with-ObjC, though—the runtimes might step on each other. Still, making that side configurable seems both more useful and more likely to succeed.

Jordan

···

On Nov 29, 2016, at 12:36, Joe Groff via swift-dev <swift-dev@swift.org> wrote:

On Nov 29, 2016, at 12:24 PM, Brian Gesiak <modocache@gmail.com> wrote:

Thanks all! It's great to hear that this wouldn't be completely unwelcome -- especially Swift Darwin with Objective-C interop disabled.

To be clear, I didn't mean to discourage you (or anyone else watching) from adding support for non-Apple Objective-C platforms; I only wanted to make it clear that it almost definitely won't Just Work by trying to compile the existing code for a non-Apple target. Like John said, we should leverage higher-level interfaces in Clang's CodeGen to emit ObjC metadata; right now, we hardcode the Apple layouts of everything.