Open swift-ci opened 3 years ago
You can pass the compiler flags -Xfrontend -enable-objc-interop
to get this to work. @compnerd points out that using ObjC interop adds some overhead, which is why it is off by default on non-Darwin platforms.
This is expected, and dare I say, desired behavior. The default on non-Apple targets is that the ObjC interop is disabled. You would need to provide your own build of an ABI compatible ObjC runtime if you wish to use the ObjC interop. You can enable it with the -enable-objc-interop
flag to the frontend. There are runtime overheads for the interop as well, due to the bridging of types. Note that you cannot combine build with different flags, so you would also need to do a custom runtime build as the object layout is impacted.
Comment by Eugene Gubin (JIRA)
I was told it's a bug 🙂 Details: https://forums.swift.org/t/objc-attribute-windows/46787
I don't consider this a bug, it is intentional. Objective-C interop is non-trivial, and a massive undertaking.
Comment by Eugene Gubin (JIRA)
@compnerd Sorry, when I said `bug` I mean what `@objc` should be just ignored on Windows since Objective-C runtime is not supported there. One can not use conditional defines to turn these annotations off. It breaks declaration.
```
#if os(Darwin)
@objc
#end
class MyClass: NSObject { }
```
Eugene Gubin (JIRA User) - I think that is the confusion. The runtime is not unsupported, it is unavailable by default. If you have a build of a compatible ObjC runtime, you can enable the ObjC interop via the -enable-objc-interop
flag. The original bring up work used a fork of the ObjC runtime that I cannot provide to actually test the ObjC interop 🙂
Comment by Eugene Gubin (JIRA)
@compnerd, thanks for clarification! But what to do with these @objc annotations in cross-platform code? As shown in the example above it could force you to repeat an entire declaration. I think it would be good to have a way to ignore these annotations on platforms there ObjC runtime is not available.
Changes like that require an evolution proposal, along with an implementation. For @objc
sure you could control that via -objc-interop
but not all attributes have a corresponding flag. I would suggest that the way to handle this is to extend the support for `#if` to guard the attributes.
It is a PITA to when trying to cross check same code on Windows and OSX. :-)
I have the issue I tried:
#if hasAttribute(objc)
@objc
#endif
... but as I would expect, I have still got the same error.
I had to use:
#if canImport(ObjectiveC)
@objc
#endif
which is quite verbose in the code when you go from this easily readable code:
import Foundation
@objc public class Hello: NSObject {
@objc public func say() {
print("Hello from Swift!")
}
}
to this one:
import Foundation
#if canImport(ObjectiveC)
@objc
#endif
public class Hello: NSObject {
#if canImport(ObjectiveC)
@objc
#endif
public func say() {
print("Hello from Swift!")
}
}
An alternative would be to use @objcMembers
- but there is a cost to it https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes/#objcMembers.
Another alternative would be to be able to define our own custom attribute a bit like Python decorator: https://realpython.com/primer-on-python-decorators/ - but its another topic.
I can see where people would want to be able to write Swift frameworks in such a way that on ObjC-supporting platforms, the types would be available from ObjC. And yes, having @objc
be ignored on non-ObjC-supporting platforms would make this easier.
As @compnerd pointed out above, however, this would be a change to the existing language behavior. As such, we cannot make such a change without first discussing it on the Swift forums and having a Swift Evolution proposal reviewed by the Swift Language Steering Group. For a change like this, the proposal would not need to be very involved, but we cannot make such a change without going through this process, which allows people who may have other use cases than yours to debate what the full impact would be.
If you wish to pursue doing this, the process is open to anyone who wants to participate. I'd be happy to give you pointers on how to proceed.
Just to mention, #if canImport(ObjectiveC)
would be incorrect as if the module is available, it will always return true. You should use #if _runtime(_ObjC)
instead to ensure that ObjC interop is enabled rather than whether the ObjectiveC module is available.
Attachment: Download
Environment
Windows 10, swift-DEVELOPMENT-SNAPSHOT-2021-03-02-a-windows10Additional Detail from JIRA
| | | |------------------|-----------------| |Votes | 0 | |Component/s | Compiler | |Labels | Bug, Windows | |Assignee | None | |Priority | Medium | md5: 3bc38c5bc812b76bec20dd2017e83d57is blocked by:
Issue Description:
Both @objc & @objcMembers attributes break compilation on Windows
Steps to reproduce: download the attachment, unpack and build.
Result: