Skip to content

Add quick switcher between iOS and macOS targets #381

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 14, 2022

Conversation

complexspaces
Copy link
Contributor

This PR adds a command palette action to the extension that allows a user to quickly switch between the macOS and iOS SDK targets. It's only available if the host is macOS because the iOS SDK is not (officially) available for distribution on other operating systems.

The goal of these changes are to make the extension a more reasonable replacement for XCode by getting closer to the cross-compiling convenience that XCode offers through its UI.

demo.mov

@swift-server-bot
Copy link

Can one of the admins verify this patch?

3 similar comments
@swift-server-bot
Copy link

Can one of the admins verify this patch?

@swift-server-bot
Copy link

Can one of the admins verify this patch?

@swift-server-bot
Copy link

Can one of the admins verify this patch?

@complexspaces
Copy link
Contributor Author

I was hoping that this would work in the context of a standalone Swift file (no SPM package present), but it doesn't seem to. I don't know if this is because my changes are wrong or because the extension doesn't currently support this. Single files seem to only work for the host's SDK.

@stevapple
Copy link
Contributor

@complexspaces Thanks for your PR and I think it’s a good idea.

As for cross-compiling a standalone file, I didn’t add the support because scripts are mostly intended to be run on the host machine directly, but it’s certainly useful to cross-compile a file without running it immediately. Perhaps we can add an action to generate a task.json entry for the current script?


I initially designed the cross-compilation ability with swift build arguments, but it ends up making the build command too long and introducing divergence between SwiftPM and SourceKit-LSP. Recently I’ve thought about redesigning the feature with autogenerated destination.json by the plugin. If you have any suggestions you could just point out.

Copy link
Contributor

@adam-fowler adam-fowler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the contribution. In general this looks good. A few comments

*
* @param indirect whether to pass the flags by -Xswiftc
*/
export function swiftDriverTargetFlags(indirect = false): string[] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about setting the target command line parameter based on the sdk parameter. It seems a little fragile although I don't see a quick and easy way to set it otherwise.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that this is a bit fragile, but I wasn't sure of another way to do this without exposing SDK versioning information to the user as well, something that wouldn't necessary 95% of the time because XCode's SDK uses symlinks.

Copy link
Contributor

@adam-fowler adam-fowler Aug 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about adding/removing the target parameter from the build arguments setting when you choose the platform? It would be clearer to the user what is happening. The current version is adding hidden arguments which might confuse the user. I don't have an issue with exposing the underlying details to the user

EDIT: forget this. It's just as clunky

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we move to using destination files that'll make this a lot simpler

@@ -46,6 +46,11 @@ interface SwiftTargetInfo {
[name: string]: string | object | undefined;
}

export enum DarwinCompatibleTarget {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to support building for the simulator as well as device.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure about how to expose the simulator, hence why I didn't add it to start. Do you think it should be (in the switcher UI), labeled something like iOS (Simulator)? I have not personally written any code that required simulator guards so I can't speak for how useful this is.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can give this a miss just now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I'm not familiar with that phrase 😓. Does "give this a miss" (here and other instances in this PR) mean to not worry about it for now?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"give this a miss" means "lets not bother"

@complexspaces
Copy link
Contributor Author

As for cross-compiling a standalone file, I didn’t add the support because scripts are mostly intended to be run on the host machine directly, but it’s certainly useful to cross-compile a file without running it immediately. Perhaps we can add an action to generate a task.json entry for the current script?

@stevapple My use case is probably fairly unique, but I have a large code repository where individual Swift files are compiled (mostly) on their own into standalone static libraries before being linked into larger Rust library builds. If it helps, the organization looks like this:

.
├── rust-crate-1/
│   ├── src/
│   │   ├── lib.rs
│   │   └── swift/
│   │       └── Supporting.swift
│   └── Cargo.toml
└── rust-crate-2/
    ├── src/
    │   ├── lib.rs
    │   └── swift/
    │       └── Supporting.Swift
    └── Cargo.toml

One of my goals with this PR was to support a structure like this where an IDE such as XCode is unable to work with individual files. It works OK with just macOS today, but we have the need to also have iOS-specific Swift code that uses things like UIKit. So, I'm not looking to ever run the file directly, but just to get a smooth editing experience. Does that make sense for the most part? Given that, I don't think a task.json would be the correct approach.

@complexspaces complexspaces force-pushed the ios-sdk-switcher branch 2 times, most recently from e7c96bc to 09862e4 Compare August 3, 2022 04:24
*
* @param indirect whether to pass the flags by -Xswiftc
*/
export function swiftDriverTargetFlags(indirect = false): string[] {
Copy link
Contributor

@adam-fowler adam-fowler Aug 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about adding/removing the target parameter from the build arguments setting when you choose the platform? It would be clearer to the user what is happening. The current version is adding hidden arguments which might confuse the user. I don't have an issue with exposing the underlying details to the user

EDIT: forget this. It's just as clunky

@@ -46,6 +46,11 @@ interface SwiftTargetInfo {
[name: string]: string | object | undefined;
}

export enum DarwinCompatibleTarget {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can give this a miss just now

*
* @param indirect whether to pass the flags by -Xswiftc
*/
export function swiftDriverTargetFlags(indirect = false): string[] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we move to using destination files that'll make this a lot simpler

@adam-fowler
Copy link
Contributor

I stole your quickPick in #384. It works really well. Hopefully we can combine the work from both #384 and this PR.

break;
}

const { stdout } = await execFile("xcrun", ["--sdk", sdkType, "--show-sdk-path"]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you include the following as an argument in the execFile call. Means we can pass DEVELOPER_DIR to the xcrun call and get the sdk from non-default Xcode installs

options: {
    env: {...process.env, ...configuration.swiftEnvironmentVariables},
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, no problem. That seems reasonable to me. I've added the environment variable forwarding to my changes.

@adam-fowler
Copy link
Contributor

@swift-server-bot test this please

@adam-fowler adam-fowler merged commit 70f7585 into swiftlang:main Aug 14, 2022
@complexspaces
Copy link
Contributor Author

Thank you for working with me on this one, I'm happy to see it merged 🎉

@adam-fowler
Copy link
Contributor

adam-fowler commented Aug 14, 2022

@complexspaces Although I just noticed after merging, building doesn't work. I know you can't build a complete iOS package, but it is still useful to build.

By the way thanks for your contribution.

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

Successfully merging this pull request may close these issues.

4 participants