Files
Kabir Oberai 0108899e04 sdk: SwiftBuild support (#229)
## What does this PR do?

Adds support for SwiftBuild on Swift 6.4.

We now point SwiftBuild to iPhoneOS.platform and rely on the real
[SWBApplePlatform](https://github.com/swiftlang/swift-build/tree/b30ee3c00abf34857084c26bb873c3da06348134/Sources/SWBApplePlatform).
We also do a little futzing to convince SWB to use our Darwin-compatible
toolset (lld, librarian, resource dirs). We explicitly _don't_ pass in a
Swift SDK because that would downgrade SWB to using one of the generic
platform plugins instead of ApplePlatform.

This also gets us a lot closer to parity with Xcode's behavior when
building for Apple platforms; we get the same build flags and
everything. We can probably achieve identical bundling too, if we take
control of the PIF.

One other change: since we need to pass custom env vars and such, we
can't rely on sourcekit-lsp's built-in SwiftPM integration anymore. We
thus create a custom BSP server that trampolines to SwiftPM's build
server with the right flags set. This effectively makes SwiftPM an
implementation detail, so we can start messing with the PIF.

## How was it tested?

- [x] Build with Swift 6.3 on macOS
- [x] Build with Swift 6.4 on macOS
- [x] Build with Swift 6.3 on Linux
- [x] Build with Swift 6.4 on Linux
- [x] BSP/LSP file creation works
- [x] LSP support works in VSCode

## AI tool usage

How much of this PR was AI-assisted? (check one)

- [ ] **0** - No AI was used to write code
- [x] **1** - I was assisted by AI. I reviewed the finished result.
- [ ] **2** - I set the AI going and left it to it; nobody has read the
result - no review, or AI review only

<!-- If an AI agent is filling this in: declare the level honestly, and
open as a draft if it is #2. Do not lower the declared level to get the
PR reviewed. -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added a `dev build-server` command for Build Server Protocol
integration.
- Projects automatically select the appropriate Swift build system when
supported.
- Packaging supports output layouts for Swift Package Manager and Swift
Build.
  - Added options to skip language-server configuration when needed.

- **Documentation**
- Updated project templates and tutorials to use `.bsp/xtool.json` for
IDE features such as syntax highlighting and documentation lookup.

- **Improvements**
- Enhanced SDK generation and compatibility across supported toolchains
and platforms.
- Improved automatic language-server configuration while preserving
existing configuration files.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-20 02:47:12 -04:00

162 lines
7.5 KiB
Plaintext

@Tutorial(time: 30) {
@Intro(title: "Build your first iOS app on Linux / Windows") {
Once you've completed <doc:Installation-Linux>, use xtool to build and deploy an iOS app from your Linux/Windows machine.
}
@Section(title: "Create an xtool project") {
We'll start by creating a project from xtool's default template.
@Steps {
@Step {
xtool comes with a template for iOS-capable Swift Packages. Run `xtool new` to create a new package.
@Code(name: "Terminal", file: "template-1b.sh", previousFile: "template-1a.sh") {}
}
@Step {
At this point, feel free to poke around.
Observe that the package is structured a lot like a regular SwiftPM library, with a few extra files.
@Code(name: "Terminal", file: "template-2b.sh", previousFile: "template-2a.sh") {}
}
@Step {
Read `xtool.yml`.
This file describes how to bundle the Swift library into an iOS app. At minimum, you need to provide a Bundle ID. This defaults to `com.example.<PackageName>`, in this case `com.example.Hello`.
@Code(name: "Terminal", file: "template-3b.sh", previousFile: "template-3a.sh") {}
}
@Step {
Read `.bsp/xtool.json`.
This file tells your IDE to ask xtool for build information (via the Build Server Protocol). It enables features like syntax highlighting and documentation lookup.
@Code(name: "Terminal", file: "template-4b.sh", previousFile: "template-4a.sh") {}
}
}
}
@Section(title: "Build and run") {
Now that we have a skeleton project, let's get it running on your device.
@Steps {
@Step {
From inside the package directory, run `xtool dev`.
The first time you run this, SwiftPM might take a few minutes to build the app. This is because it needs to build the Swift Modules for the iOS SDK. Subsequent runs should be a lot faster since SwiftPM caches these modules globally.
@Code(name: "Terminal", file: "build-1b.sh", previousFile: "build-1a.sh")
}
@Step {
After the build is complete, xtool will attempt to install it on your device.
At this point, connect your iOS device to your computer via USB. If you installed `libimobiledevice-utils` during setup, you can verify that your device is connected by running `ideviceinfo`. xtool will continue after automatically detecting that your device is connected.
@Code(name: "Terminal", file: "build-2.sh", reset: true)
}
@Step {
Pair your device if prompted.
The first time you run `xtool dev`, you may see a "Trust" dialog on your iOS device to proceed with pairing. Tap **Trust** and enter your passcode on iOS. xtool may throw an error after this: if so, just run `xtool dev` again.
@Code(name: "Terminal", file: "build-2.sh", reset: true) {
@Image(source: "Trust", alt: "Prompt alerting user to trust device")
}
}
@Step {
xtool will now connect to Apple Developer Services, register your device with your Apple ID, generate a Certificate + App ID + Provisioning Profile, sign the app, and then install it.
@Code(name: "Terminal", file: "build-3.sh", reset: true) {}
}
@Step {
Enable Developer Mode if needed.
At this point, you may run into an error asking you to enable **Development Mode** on your iOS device. Follow [these instructions](https://developer.apple.com/documentation/xcode/enabling-developer-mode-on-a-device) and then run `xtool dev` again.
@Code(name: "Terminal", file: "build-3.sh", reset: true) {
@Image(source: "Developer", alt: "Developer mode in Settings")
}
}
@Step {
You should now see the app on your iOS device's home screen / App Library. Tap it to launch the app.
@Image(source: "Home", alt: "Hello app on the home screen")
}
@Step {
The first time you launch the app, observe that you may get an "Untrusted Developer" alert.
@Image(source: "UntrustedDev", alt: "Alert prompting user to trust certificate")
}
@Step {
Go to **Settings** > **General** > **VPN & Device Management** > _[your email]_ > **Trust**.
@Image(source: "Verified", alt: "Trust settings")
}
@Step {
You should now be able to launch the app!
@Image(source: "HelloWorld", alt: "Hello world app")
}
}
}
@Section(title: "Edit and re-run") {
We'll make a small change to the app in your favorite code editor, and then re-run it.
@Steps {
@Step {
Follow the instructions to configure [SourceKit-LSP](https://github.com/swiftlang/sourcekit-lsp/blob/242609dcad55824d9eb23269c0aeead187fd0faa/Documentation/Editor%20Integration.md) for your IDE.
For example, if you're using Visual Studio Code, this means you need to install the [Swift extension](https://marketplace.visualstudio.com/items?itemName=swiftlang.swift-vscode). If you're on Windows, make sure you're [connected to the WSL remote](https://code.visualstudio.com/docs/remote/wsl).
@Image(source: "SwiftExtension", alt: "Swift extension for VSCode")
}
@Step {
Open the project folder in your editor, and drill down to `Sources/Hello/ContentView.swift`.
@Code(name: "ContentView.swift", file: "edit-2.swift") {}
}
@Step {
If you've configured SourceKit-LSP correctly, you should see rich documentation when you hover over the various types and methods.
@Code(name: "ContentView.swift", file: "edit-2.swift") {
@Image(source: "Hover", alt: "Intellisense")
}
}
@Step {
Let's update the "Hello, world!" text to be bold and purple.
@Code(name: "ContentView.swift", file: "edit-4.swift") {}
}
@Step {
Run `xtool dev` again to re-build and re-install. This should go a lot faster than the first time.
@Code(name: "Terminal", file: "rerun-5b.sh", previousFile: "rerun-5a.sh") {}
}
@Step {
Launch the app again to see the updated text!
@Code(name: "Terminal", file: "rerun-6.sh") {
@Image(source: "HelloWorld-Purple", alt: "Updated Hello app")
}
}
}
}
}