Skip to content
This repository has been archived by the owner on Nov 10, 2023. It is now read-only.

Swift support #423

Open
ghost opened this issue Sep 17, 2015 · 67 comments
Open

Swift support #423

ghost opened this issue Sep 17, 2015 · 67 comments
Labels

Comments

@ghost
Copy link

ghost commented Sep 17, 2015

Since all the xcode problems are not limited to Objective-C 😆 My question is if there are any plans to support Swift.

@sdwilsh
Copy link
Contributor

sdwilsh commented Sep 17, 2015

We don't currently have any plans around this. We'd happily help someone get it in, but we don't have a need for it internally yet.

@bhamiltoncx
Copy link
Contributor

I did some investigation into the ins and outs of using the swift and clang command-line to compile binaries which use Swift and Objective-C together. Here's what I found:

https://www.facebook.com/beng/posts/10153662256352720

Example:

https://gist.github.com/bhamiltoncx/3d846862eb42eede17fa

@bhamiltoncx
Copy link
Contributor

I hacked together very very basic Swift support for Xcode project generation:

https://github.com/facebook/buck/tree/swift

I updated the demo app to use it:

https://github.com/fbsamples/bucksamples/tree/swift

This doesn't support Swift frameworks yet, but the basics work.

@cbrauchli
Copy link

I'd love to see this too. Is anyone actively working on it? Can I be of help?

@sdwilsh
Copy link
Contributor

sdwilsh commented Dec 17, 2015

I don't believe anybody is actively working on it, so if you wanted to try and pick up @bhamiltoncx's work and drive it forward, I'm pretty sure that would be okay.

@sdwilsh
Copy link
Contributor

sdwilsh commented Dec 17, 2015

If you are interested in continuing that work, @Coneko has a good write up of how Buck uses graphs, which is a good primer for one of our core pieces of architecture: https://www.facebook.com/notes/uri-baghin/architecture-of-buck-1-graphs/1660525917559134

@bhamiltoncx
Copy link
Contributor

Sorry for the long silence here. Expect to see some movement soon!

ghost pushed a commit that referenced this issue Feb 2, 2016
Summary:
* Add Swift tool
* Swift sdk and target params
* Introduce the package com.facebook.buck.swift
* Add Swift tool
* swift_library() rule to compile swift sources into `.swiftmodule`/`.o`; example:

```
swift_library(
    name='greetings',
    srcs=['greetings.swift', 'input.swift']
)
```
* Linking swift modules into Mach-O binaries
* Add swiftName (optional) to platform, as it sometimes differ from the Xcode SDK names.
* Copying swift standard libraries for app bundles

Part of the long journey for #423

Test Plan: CI

Reviewed By: bhamiltoncx

fb-gh-sync-id: 2a5b7f6
ghost pushed a commit that referenced this issue Feb 3, 2016
Summary:
* Swift looks for `swift_static` and will default to static linking (currently only MacOS has this defined)
* Add integration test for OS X binaries.
* Automatically add runtime library path when linking.

Part of the long journey for #423

Test Plan: CI

Reviewed By: bhamiltoncx

fb-gh-sync-id: 7cf7683
ghost pushed a commit that referenced this issue Feb 3, 2016
Summary:
This allows Buck-built swift apps to be installable on device.

Part of the long journey for #423

Test Plan: Build the `iphoneos-arm64` flavor of a Swift app (for example: `test/com/facebook/buck/swift/testdata/simple_swift_application_bundle`with Buck, make sure it installs and runs on device.

Reviewed By: bhamiltoncx

fb-gh-sync-id: 9d0ac39
@rowillia
Copy link
Contributor

rowillia commented Feb 5, 2016

It's Happening

@bhamiltoncx
Copy link
Contributor

So the very basics have landed. You can build apple_binary() rules and apple_bundle() rules with one or more swift_library() dependencies. OS X, iOS simulator, and iOS device are all working.

swift_library() rules currently cannot have any dependencies, and there isn't any Obj-C/Swift interop. But it's a start.

@fkorotkov
Copy link

How can I specify a particular swift version? I've tried to use *_toolchains_override but with no luck :-( Buck chooses the latest toolchain but my app is not ready for Swift 3.0.

@ryu2
Copy link
Contributor

ryu2 commented Sep 22, 2016

You're right, right now we can only override the toolchain globally. @nguyentruongtho is working on adding swift-specific toolchain override as a config option.

@nguyentruongtho
Copy link
Contributor

nguyentruongtho commented Sep 22, 2016

In the mean time, you could use this settings:

[apple]
  iphonesimulator10.0_toolchains_override = com.apple.dt.toolchain.Swift_2_3,com.apple.dt.toolchain.XcodeDefault
  iphoneos10.0_toolchains_override = ...

@fkorotkov
Copy link

@nguyentruongtho thank you! It worked!

@fkorotkov
Copy link

fkorotkov commented Sep 23, 2016

I continued playing with Buck and Swift and faced some strange behaviour while running Swift tests only. Objective-C tests are working fine! And even a mix of Objective-C and Swift is working fine.

I've created a small example that illustrates the issues here: https://github.com/fkorotkov/buck-sandbox.

Even added Travis so you can easily see output! 😜 https://travis-ci.org/fkorotkov/buck-sandbox/builds/162268899

@nguyentruongtho
Copy link
Contributor

yeah, apple_test can handle mixed swift & objective-c (thanks to this PR: #881). For swift-only target, I've just landed #895, that PR should make apple_test to work with swift-only target, but obviously I have not tested it yet, you can try.

@fkorotkov
Copy link

@nguyentruongtho I would love to but brew install --HEAD buck is failing. Fixed it here: #898

@fkorotkov
Copy link

@nguyentruongtho I built Buck locally with the fix and only swift tests are working now!

@nguyentruongtho
Copy link
Contributor

Very nice, I didn't think of this when working on #895. Good to know 🚀!

@fkorotkov
Copy link

BTW I'm working on a fix for #909.

@nguyentruongtho
Copy link
Contributor

nguyentruongtho commented Sep 29, 2016

I doesn't look like an issue to me, you should not include a header from parent folder like in objc/Foo.h, but I might be wrong, @ryu2 probably knows more.

@fkorotkov
Copy link

Agreed on a bad example structure. Fixed the example :-) see #909 (comment)

@piotrwach
Copy link

piotrwach commented Oct 13, 2016

I have a library that has Swift and Objective-C code. Some Swift classes I want to export to Objective-C, I see that buck correctly generates MyLibrary-Swift.h for all classes marked as @objc, however I don't see a way export this header from my library, so that I can used it in my dependencies. Is this possible?

apple_library(
    name = 'MyLibrary',
    srcs = [
        'ObjC.m',
        'SwiftKit1.swift',
        'SwiftKit2.swift'
    ],
    exported_headers = [
        'ObjC.h',
        'MyLibrary-Swift.h' <---------------------------------------- this doesn't work
    ],
    visibility = ['PUBLIC']
)

@nguyentruongtho
Copy link
Contributor

Currently, swift_library can export its generated header, but not for an apple_library that contains swift files, feel free to open a ticket for it.
Your example is actually a special case of dependency problem, where a swift_library cannot have an apple_library target as a dependency. I'm currently working to fix this.

@piotrwach
Copy link

Created issue here: #943

@piotrwach
Copy link

piotrwach commented Oct 13, 2016

If you are working on it, do you have a branch somewhere for me to have a look? I want my team to migrate to Buck, but we may have to implement few things, that seem to be missing right now, for example support for clang module maps, and better swift support.

@afturner
Copy link

afturner commented Sep 2, 2017

Wondering what the status is on this, sorry if I missed something

@adc-amatosov
Copy link

I am now trying to understand if buck is ready for mixed obj-c and swift project
@nguyentruongtho @fkorotkov do you have any updates on the swift support?

@vhbit
Copy link

vhbit commented Sep 29, 2017

@adc-amatosov my guess is that a better person to ask would be @milend as he is pushing a lot of Swift-related changes since August.

@adc-amatosov
Copy link

Thanks @vhbit
Hi @milend, I am looking forward to use Buck, but a bit concern with the swift support. Can you please help me figuring out what is the current state of the swift support for obj-c and swift mixed projects?

@adc-amatosov
Copy link

Thanks @FredLoh

@dinhvh
Copy link

dinhvh commented Oct 2, 2017

I think the current state is the you can mix Swift and Objective-C in an apple_library rule. Can you verify that everything works for you?

@adc-amatosov
Copy link

I will try to migrate one small mixed language project in next couple days and will keep you posted. If it works well I will try to migrate something bigger.
What I still need to figure out is what to do with 3rd parties. We have a ton of 3rd party deps that get installed via CocoaPods now and most of them don't have other distribution channels. Some of them are source based, some prebuild static frameworks, some prebuild dynamic frameworks. But this is totally offtop for this ticket

@milend
Copy link
Contributor

milend commented Oct 2, 2017

Mixing Swift + Obj-C is supported but there are multiple caveats:

  • It's only officially supported for apple_library and apple_test.apple_binary is not supported at present.
  • In order to enable the support, you have to set apple.use_swift_delegate config option to false.
  • Currently only a Swift static lib workflow is supported (i.e., non-modular). This means you cannot import your apple_library in Obj-C through @import Module;
  • You must set swift_version of the apple_library so that project generation works.
  • You lose the ability to debug the Swift code (i.e., no local vars + ability to print using lldb). This is due to SR-2660.
  • In order to expose Obj-C code, you must use bridging headers.
  • If you want to understand the latest Swift support, the best source of truth is the integration suite.

@adc-amatosov
Copy link

Thanks for very detailed update @milend

You lose the ability to debug the Swift code

This looks like pretty severe to me. Are there any workaround for this?

@milend
Copy link
Contributor

milend commented Oct 3, 2017

This looks like pretty severe to me. Are there any workaround for this?

There are no workarounds. Breakpoints still work, though, you just lose the ability to inspect variables (either through Xcode's debugger view or via lldb).

@rFlex
Copy link

rFlex commented Oct 3, 2017

@milend Is that because Swift librairies are compiled as static libs? Any hope to have the debugger working for static libraries at some point or is that just never going to work until the dynamic framework workflow is implemented?

@milend
Copy link
Contributor

milend commented Oct 3, 2017

Is that because Swift librairies are compiled as static libs?

Yes and no. The usage of static libs exposes an underlying bug. The details are documented in SR-2660.

Any hope to have the debugger working for static libraries at some point or is that just never going to work until the dynamic framework workflow is implemented?

It's just a question of getting SR-2660 addressed, so that it starts working. Given that Xcode 9 added official support for Swift static libs, I believe this would be addressed in the future. But that's just my guess, I'm not aware of anyone addressing the bug at present.

@milend
Copy link
Contributor

milend commented Oct 3, 2017

One aspect I forgot to mention is that you can still debug a single Swift module at a time (not ideal but at least it's something). This can be done by adding something like the following to the linker flags for the final binary (macOS example):

-Xlinker -add_ast_path -Xlinker $BUILT_PRODUCTS_DIR/Module.swiftmodule/x86_64.swiftmodule

@KieranLafferty
Copy link
Contributor

I managed to get my apple_binary and all dependencies building properly for a swift app but am getting a weird error when it tries to launch on simulator/device. Any idea whats going on here?

screen shot 2017-10-03 at 2 14 36 pm

@milend
Copy link
Contributor

milend commented Oct 3, 2017

@KieranLafferty I encountered the same issue when the apple_binary did not actually have any source files (all the code was in a mixed apple_library with an @NSApplicationMain). The solution is to just have a simple main.m in the apple_binary that bootstraps your app (UIApplicationMain() in your case).

@KieranLafferty
Copy link
Contributor

KieranLafferty commented Oct 4, 2017

Ok! So the app now launches and runs the main.m but I'm unable to make reference to my AppDelegate file that's contained in the apple_library.

I've attempted the following with no success

#import <UIKit/UIKit.h>
#import <CompanyLibrary/CompanyLibrary-swift.h>

int main(int argc, char * argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

This gets very close and code completion works for this file but I get a compilation error because the #import <CompanyLibrary/CompanyLibrary-swift.h> contains a reference to @import MyCustomLib; which complains Module 'MyCustomLib' can not be found

I also tried simply going into <CompanyLibrary/CompanyLibrary-swift.h> and finding the class definition for my AppDelegate class which I found to have the following definition:

SWIFT_CLASS("_TtC11YarnLibrary11AppDelegate")
@interface AppDelegate : UIResponder <UIApplicationDelegate, UNUserNotificationCenterDelegate>

I thought that simply copying the string _TtC11YarnLibrary11AppDelegate to main.m's UIApplicationMain(argc, argv, nil, @"_TtC11YarnLibrary11AppDelegate"); but that didn't work either.

Definitely getting closer but would be great to hear how you got it to load your AppDelegate that was contained in dependency

Note:

I've also removed @UIApplicationMain from my AppDelegate file and added the following to my buck config as per your comment

[apple]
  use_swift_delegate=false

@adc-amatosov
Copy link

adc-amatosov commented Oct 4, 2017

Hi @KieranLafferty, the real name of your swift class from Obj-C is "CompanyLibrary.AppDelegate"
You can also change it by adding @objc(AppDelegate) in front of class AppDelegate in swift file. In this case name of the swift class will be "AppDelegate" on the obj-c side

@KieranLafferty
Copy link
Contributor

Thanks for the response @adc-amatosov, I tried what you suggested (with and without @objc before the class) and didn't have any luck.

Without @objc in AppDelegate

int main(int argc, char * argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, @"CompanyLibrary.AppDelegate");
    }
}

With @objc in AppDelegate

int main(int argc, char * argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, @"AppDelegate");
    }
}

In both situations I get the following error

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Unable to instantiate the UIApplication delegate instance. No class named AppDelegate is loaded.'

@adc-amatosov
Copy link

That is weird. Are you sure your swift library links successfully to the app binary?
You can check it using nm -gU "/path/to/your/Name.app/Name" | grep AppDelegate

@milend
Copy link
Contributor

milend commented Oct 4, 2017

@KieranLafferty The names of Obj-C classes defined in Swift are mangled. You will usually something like:

SWIFT_CLASS("_TtC9ComponentLibrary21AppDelegate")
@interface AppDelegate: NSObject
...
@end

Instead, you should do the following:

  • In your main.m file, do #import <ComponentLibrary/ComponentLibrary-Swift.h> (where ComponentLibrary is the name of the mixed apple_library)
  • Use NSStringFromClass([AppDelegate class]) in the call to UIApplicationMain, not a literal string.
  • You must remember to annotate your AppDelegate in Swift with @objc, in addition to subclassing NSObject.

@KieranLafferty
Copy link
Contributor

Tried that too but it can’t compile the Lib-swift.h (see my previous comment above) because the header tried to import another swift library of mine using @import which isn’t supported yet by buck

@milend
Copy link
Contributor

milend commented Oct 4, 2017

@KieranLafferty:

it can’t compile the Lib-swift.h (see my previous comment above) because the header tried to import another swift library of mine using @import which isn’t supported yet by buck

There's a trick to workaround this. Instead of importing <ComponentLib/ComponentLib-Swift.h>, you create a header like <ComponentLib/ComponentLib-Public-Swift.h> inside of which you do:

#import <LibA/Header.h> // LibA is the module which you imported via `import` in Swift
#import <ComponentLib/ComponentLib-Public-Swift.h>

ComponentLib-Public-Swift.h effectively ensures that any deps from the Swift side of ComponentLib which are exposed to Obj-C are always imported beforehand.

Then whenever you want to import ComponentLib-Swift.h, instead use ComponentLib-Public-Swift.h.

@mgrebenets
Copy link

@milend Did you mean to say

#import <LibA/Header.h> // LibA is the module which you imported via `import` in Swift
#import <ComponentLib/ComponentLib-Swift.h>

?

I.e. the idea is to import private ComponentLib-Swift.h via public header?

@lstomberg
Copy link

It has been almost a year since the last discussion on this. At that time it seemed possible to build mixed-language projects but the process wasn't very straightforward. What is the current state of Swift support and mixed Swift-ObjC projects in Buck? Would using Buck be straightforward if we split mixed projects into language-specific projects?

@beefon
Copy link
Contributor

beefon commented Oct 9, 2018

Currently there is no clean documentation about Swift support in Buck. It supports it up to some degree and I personally don't know what is that degree (e.g. does it support Swift 4/4.1/4.2?), but you can check out the unit tests as they have some clues how would you combine ObjC and Swift in a single module. The rest of the information is available in this thread. I wish it could be structured somehow on buckbuild.com. This is what we have now.

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

No branches or pull requests