tiferrei
(Tiago Ferreira)
1
Good afternoon,
I'm working on a project that depends on a Swift 4.1.1 ready framework. When compiling my project on my Mac (with Swift 4.1.1) all the dependencies compile and are linked perfectly. However, when testing this in Linux (also with Swift 4.1.1) it seems to complain about casting errors. More precisely:
/home/tiferrei/Desktop/UCLRooms/.build/checkouts/RequestKit.git-7566548506740707509/RequestKit/JSONPostRouter.swift:27:61: error: '[String : AnyObject]?' is not convertible to 'AnyObject?'; did you mean to use 'as!' to force downcast?
userInfo[RequestKitErrorKey] = json as AnyObject?
~~~~~^~~~~~~~~~~~~
as!
/home/tiferrei/Desktop/UCLRooms/.build/checkouts/RequestKit.git-7566548506740707509/RequestKit/JSONPostRouter.swift:29:56: error: cannot convert value of type 'String' to type 'AnyObject?' in coercion
userInfo[RequestKitErrorKey] = string as AnyObject?
^~~~~~
/home/tiferrei/Desktop/UCLRooms/.build/checkouts/RequestKit.git-7566548506740707509/RequestKit/JSONPostRouter.swift:72:61: error: '[String : AnyObject]?' is not convertible to 'AnyObject?'; did you mean to use 'as!' to force downcast?
userInfo[RequestKitErrorKey] = json as AnyObject?
~~~~~^~~~~~~~~~~~~
as!
/home/tiferrei/Desktop/UCLRooms/.build/checkouts/RequestKit.git-7566548506740707509/RequestKit/JSONPostRouter.swift:74:56: error: cannot convert value of type 'String' to type 'AnyObject?' in coercion
userInfo[RequestKitErrorKey] = string as AnyObject?
^~~~~~
/home/tiferrei/Desktop/UCLRooms/.build/checkouts/RequestKit.git-7566548506740707509/RequestKit/Router.swift:75:62: error: cannot convert value of type 'String' to type 'AnyObject?' in coercion
parameters[configuration.accessTokenFieldName] = accessToken as AnyObject?
^~~~~~~~~~~
/home/tiferrei/Desktop/UCLRooms/.build/checkouts/RequestKit.git-7566548506740707509/RequestKit/Router.swift:167:61: error: '[String : AnyObject]?' is not convertible to 'AnyObject?'; did you mean to use 'as!' to force downcast?
userInfo[RequestKitErrorKey] = json as AnyObject?
~~~~~^~~~~~~~~~~~~
as!
/home/tiferrei/Desktop/UCLRooms/.build/checkouts/RequestKit.git-7566548506740707509/RequestKit/Router.swift:202:61: error: '[String : AnyObject]?' is not convertible to 'AnyObject?'; did you mean to use 'as!' to force downcast?
userInfo[RequestKitErrorKey] = json as AnyObject?
~~~~~^~~~~~~~~~~~~
as!
None of these errors happens in macOS. I even cloned the dependency separately and compiled it, all fine on macOS.
Is this a known issue? How do we even debug something like this?
Thank you,
Tiago
Jon_Shier
(Jon Shier)
2
On macOS, String is convertible to AnyObject due to Foundation's automatic bridging with NSString, which is a reference type. On Linux that bridge doesn't exist and so you get the errors you see. I suggest working with real types rather than trying to cast to AnyObject in order to get (I'm guessing) dynamic messaging.
svanimpe
(Steven Van Impe)
3
Have you tried using [String: Any] instead of [String: AnyObject]?
1 Like
tiferrei
(Tiago Ferreira)
4
I was able to fix those errors using Any instead of AnyObject, thanks!
tiferrei
(Tiago Ferreira)
5
Now I have other weird errors like:
/home/tiferrei/Desktop/UCLRooms/.build/checkouts/UCLKit.git-1403556243857012072/Source/RoomBookings.swift:138:2: error: only classes that inherit from NSObject can be declared @objc
@objc public final class Location: NSObject, Codable {
That again, only happen in Linux.
tkrajacic
(Thomas Krajacic)
6
Well, the @objc stuff needs to be guarded to be Apple-platforms only I guess. You can't use them in your Linux code.
allevato
(Tony Allevato)
7
Unfortunately there are still many Swift third-party libraries out there that have no real reason to be Apple-OS-specific but are because of things like this; since the Linux experience for Swift is still much weaker, folks just don't test their code there or consider which parts of the language they need to avoid if they want it to run there.
Sending pull requests to those projects that make them build on Linux when possible would be a great help moving forward, and hopefully those project owners would accept them. (Of course, then the projects have to make sure they're not using any of the bits of Foundation that aren't implemented yet on Linux...)
1 Like
tiferrei
(Tiago Ferreira)
8
Interesting. So is there a way I can have the class be Obj-C compatible and Linux compatible at the same time? Or would I have to sacrifice Obj-C for Linux support?
svanimpe
(Steven Van Impe)
9
Maybe the real question is: Why do you use/need Objective-C here and could you do the same in Swift?
tiferrei
(Tiago Ferreira)
10
I'd like the framework to be available for people that still use Obj-C, although that's not a requirement.
Jon_Shier
(Jon Shier)
11
AFAIK, you'd have to duplicate your types to make one Obj-C visible and the other Linux buildable. There's no way to put the Obj-C references behind platform checks. Personally I find no value in Obj-C compatibility and it can really restrict your usage of Swift. I usually only see it in Swift ports of libraries which had a previous Obj-C version, though not always even then.
1 Like
tiferrei
(Tiago Ferreira)
12
That would look horrible, alright Obj-C is out then. Thanks!
1 Like
tkrajacic
(Thomas Krajacic)
13
Well, you still need @objc if you want to load your code at runtime on macOS. That part is sadly missing from the Swift story so far.
tiferrei
(Tiago Ferreira)
14
Alright here's an interesting one: I've managed to make the package Linux compatible, so now when I build my project everything works as expected, sweet. However, if I try to git clone just the dependency, and I try to swift build it, it fails because it doesn't have a Linux Main file.
Am I the only one confused by this?
jrose
(Jordan Rose)
15
I will note that you do not need @objc on a class declaration, ever, if you subclass another Objective-C-exposed class (unless you're trying to set the class's Objective-C runtime name). The only times you should be writing @objc explicitly is on protocols and on methods that you specifically want to expose to Objective-C, and both of those wouldn't work on Linux anyway.
1 Like
Any and AnyObject should be avoided in favor of generics where possible. Requires a bit more work on your part, but always worth it in the long run.
2 Likes
tiferrei
(Tiago Ferreira)
17
So now I can compile and use the dependency in a project but I can't compile it directly on Linux because of error: missingLinuxMain. Is there any way I can set it up to just treat everything as both Linux and macOS?
felix91gr
(Félix Fischer)
18
IIRC, the missing LinuxMain error is related to the swift file required for testing on linux.
Look that up. I'd help you more but atm I haven't slept for like 21 hours so I'm really conserving energy here. After I finish this presentation I'm gonna give, I'll come back and try to help some more, if you're still trying to make that work.
1 Like
svanimpe
(Steven Van Impe)
19
See swift - Build error: missingLinuxMain - Stack Overflow
If you have test modules, you need a LinuxMain.swift file (for now).
1 Like
tiferrei
(Tiago Ferreira)
20
Thank you @felix91gr and @svanimpe, you're help and time is greatly appreciated, I was able to make it work on Linux by adding the LinuxMain file and following @svanimpe's link.
I did however hit another roadblock: URLSession seems to be missing? My code compiles and Unit tests pass on Xcode, but not on the CLI, on neither Linux nor macOS. On Linux I was kind of expecting it as shown in this link: ubuntu - Swift 3 preview 2 linux error: use of unresolved identifier - Stack Overflow However, I don't see why this also applies to builds on macOS, has URLSession not been implemented at all in Open Source Foundation?
The specific error I'm referring to is:
/Users/tiferrei/Developer/RequestKit/Tests/RequestKitTests/TestInterface.swift:18:53: error: use of unresolved identifier 'URLSession'
func postJSON(_ session: RequestKitURLSession = URLSession.shared, completion: @escaping (_ response: Response<[String: AnyObject]>) -> Void) -> URLSessionDataTaskProtocol? {
1 Like