Skip to content
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

Add example Swift package building script #2396

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ members = [
"weedle2",

"examples/app/uniffi-bindgen-cli",
"examples/app/uniffi-bindgen-swift-cli",
"examples/arithmetic",
"examples/arithmetic-procmacro",
"examples/async-api-client",
Expand Down
33 changes: 33 additions & 0 deletions examples/app/swift-package/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# examples-app-swift-package

Builds a Swift package, currently only static library supported, for a Uniffi Rust package including Uniffi dependencies.

## Usage

Example from `./fixtures/ext-types/lib`:

```shell
% ./run-bindgen.sh
Finished release [optimized] target(s) in 0.28s
info: component 'rust-std' for target 'x86_64-apple-ios' is up to date
info: component 'rust-std' for target 'aarch64-apple-ios-sim' is up to date
info: component 'rust-std' for target 'aarch64-apple-ios' is up to date
info: component 'rust-std' for target 'x86_64-apple-darwin' is up to date
info: component 'rust-std' for target 'aarch64-apple-darwin' is up to date
Finished release [optimized] target(s) in 0.15s
Creating iOS sim fat library at path '/Users/kris/Code/kriswuollett/uniffi-rs/examples/app/swift-package/../../../target/apple-ios-sim/release/libuniffi_ext_types_lib.a'
Creating macOS fat library at path '/Users/kris/Code/kriswuollett/uniffi-rs/examples/app/swift-package/../../../target/apple-macos/release/libuniffi_ext_types_lib.a'
Creating XCFramework at path '/Users/kris/Code/kriswuollett/uniffi-rs/examples/app/swift-package/../../../target/swift-package/UniffiFixtureExtTypesFFI/UniffiFixtureExtTypesFFI.xcframework'
xcframework successfully written out to: /Users/kris/Code/kriswuollett/uniffi-rs/target/swift-package/UniffiFixtureExtTypesFFI/UniffiFixtureExtTypesFFI.xcframework
Building for debugging...

...
error: emit-module command failed with exit code 1 (use -v to see invocation)
/Users/kris/Code/kriswuollett/uniffi-rs/target/swift-package/UniffiFixtureExtTypesFFI/Sources/ImportedTypesLibFFI/ImportedTypesLibFFI.swift:564:21: error: cannot find type 'UniffiOneEnum' in scope
562 |
563 | public struct CombinedType: Sendable {
564 | public var uoe: UniffiOneEnum
| `- error: cannot find type 'UniffiOneEnum' in scope
565 | public var uot: UniffiOneType
566 | public var uots: [UniffiOneType]
```
165 changes: 165 additions & 0 deletions examples/app/swift-package/bindgen.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
#!/usr/bin/env bash

set -eou pipefail

SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
REPO_DIR="$SCRIPT_DIR/../../.."

if [[ "${MANIFEST_FILE:-}" == "" ]]; then
printf "MANIFEST_FILE env var not set!\n" 1>&2
exit 1
fi

if [[ "${RUST_PACKAGE:-}" == "" ]]; then
printf "RUST_PACKAGE env var not set!\n" 1>&2
exit 1
fi

DEFAULT_XCFRAMEWORK_MODULE_NAME="$(echo -n "$RUST_PACKAGE" | sed -e 's/-/_/g' | python3 -c "print(''.join(x.title() for x in input().split('_')) + 'FFI')")"
XCFRAMEWORK_MODULE_NAME="${XCFRAMEWORK_MODULE_NAME:-$DEFAULT_XCFRAMEWORK_MODULE_NAME}"

DEFAULT_OUTPUT_DIR="$REPO_DIR/target/swift-package/$XCFRAMEWORK_MODULE_NAME"
OUTPUT_DIR="${OUTPUT_DIR:-$DEFAULT_OUTPUT_DIR}"
XCFRAMEWORK_DIR="$OUTPUT_DIR/$XCFRAMEWORK_MODULE_NAME.xcframework"

if [[ -e "$OUTPUT_DIR" ]]; then
printf "The OUTPUT_DIR '%s' must not exist before running\n" "$OUTPUT_DIR" 1>&2
exit 1
fi

DEFAULT_LIBRARY_NAME="lib${RUST_PACKAGE}.a"
LIBRARY_NAME="${LIBRARY_NAME:-$DEFAULT_LIBRARY_NAME}"

if [[ "${UNIFFI_BINDGEN_SWIFT:-}" == "" ]]; then
UNIFFI_BINDGEN_SWIFT="$REPO_DIR/target/release/uniffi-bindgen-swift"
cargo build --manifest-path "$REPO_DIR/Cargo.toml" --release --bin uniffi-bindgen-swift
fi

rustup target add x86_64-apple-ios
rustup target add aarch64-apple-ios-sim
rustup target add aarch64-apple-ios
rustup target add x86_64-apple-darwin
rustup target add aarch64-apple-darwin

cargo build --manifest-path "$REPO_DIR/Cargo.toml" --release --package "$RUST_PACKAGE" \
--target x86_64-apple-ios \
--target aarch64-apple-ios-sim \
--target aarch64-apple-ios \
--target x86_64-apple-darwin \
--target aarch64-apple-darwin

# Generate Swift files based on sample library
SWIFT_FILES_DIR="$REPO_DIR/target/swift/$RUST_PACKAGE"
mkdir -p "$SWIFT_FILES_DIR"
"$UNIFFI_BINDGEN_SWIFT" \
--swift-sources "$REPO_DIR/target/aarch64-apple-darwin/release/$LIBRARY_NAME" \
"$SWIFT_FILES_DIR"

# Generate headers based on sample library
HEADER_FILES_DIR="$REPO_DIR/target/include/$RUST_PACKAGE"
"$UNIFFI_BINDGEN_SWIFT" --module-name "$XCFRAMEWORK_MODULE_NAME" \
--headers --modulemap --modulemap-filename module.modulemap \
"$REPO_DIR/target/aarch64-apple-darwin/release/$LIBRARY_NAME" \
"$HEADER_FILES_DIR"

mkdir -p "$XCFRAMEWORK_DIR"

SNAKE_NAMES=()
CAMEL_NAMES=()
while IFS= read -r -d $'\0'; do
FILENAME="$REPLY"
SNAKE_NAME="$(basename "$FILENAME" | sed -e 's/\.swift//g')"
CAMEL_NAME="$(echo -n "$SNAKE_NAME" | python3 -c "print(''.join(x.title() for x in input().split('_')) + 'FFI')")"
SNAKE_NAMES+=("$SNAKE_NAME")
CAMEL_NAMES+=("$CAMEL_NAME")
done < <(find "$SWIFT_FILES_DIR" -name '*.swift' -print0)
MODULE_COUNT="${#SNAKE_NAMES[@]}"

# Create fat library for iOS Simulator
IOS_SIM_FAT_LIBRARY="$REPO_DIR/target/apple-ios-sim/release/$LIBRARY_NAME"
printf "Creating iOS sim fat library at path '%s'\n" "$IOS_SIM_FAT_LIBRARY"
mkdir -p "$(dirname "$IOS_SIM_FAT_LIBRARY")"
lipo -create "$REPO_DIR/target/aarch64-apple-ios-sim/release/$LIBRARY_NAME" \
"$REPO_DIR/target/x86_64-apple-ios/release/$LIBRARY_NAME" \
-output "$IOS_SIM_FAT_LIBRARY"

# Create fat library for macOS
MACOS_FAT_LIBRARY="$REPO_DIR/target/apple-macos/release/$LIBRARY_NAME"
printf "Creating macOS fat library at path '%s'\n" "$MACOS_FAT_LIBRARY"
mkdir -p "$(dirname "$MACOS_FAT_LIBRARY")"
lipo -create "$REPO_DIR/target/aarch64-apple-darwin/release/$LIBRARY_NAME" \
"$REPO_DIR/target/x86_64-apple-darwin/release/$LIBRARY_NAME" \
-output "$MACOS_FAT_LIBRARY"

printf "Creating XCFramework at path '%s'\n" "$XCFRAMEWORK_DIR"
xcodebuild -create-xcframework \
-library "$IOS_SIM_FAT_LIBRARY" \
-headers "$HEADER_FILES_DIR" \
-library "$MACOS_FAT_LIBRARY" \
-headers "$HEADER_FILES_DIR" \
-library "$REPO_DIR/target/aarch64-apple-ios/release/$LIBRARY_NAME" \
-headers "$HEADER_FILES_DIR" \
-output "$XCFRAMEWORK_DIR"

PKG_FILE="$OUTPUT_DIR/Package.swift"

cat >"$PKG_FILE" <<EOF
// swift-tools-version:6.0
import PackageDescription

let package = Package(
name: "$XCFRAMEWORK_MODULE_NAME",
platforms: [.iOS(.v18), .macOS(.v15)],
EOF
printf >>"$PKG_FILE" " products: ["

for ((i = 0; i < "$MODULE_COUNT"; ++i)); do
if [[ "$i" != "0" ]]; then
printf >>"$PKG_FILE" ",\n"
else
printf >>"$PKG_FILE" "\n"
fi
printf >>"$PKG_FILE" " .library(\n"
printf >>"$PKG_FILE" " name: \"%s\", targets: [\"%s\"]\n" "${CAMEL_NAMES[$i]}" "${CAMEL_NAMES[$i]}"
printf >>"$PKG_FILE" " )"
done
printf >>"$PKG_FILE" "\n"

cat >>"$PKG_FILE" <<EOF
],
targets: [
EOF

for ((i = 0; i < "$MODULE_COUNT"; ++i)); do
MODULE_SRC_DIR="$OUTPUT_DIR/Sources/${CAMEL_NAMES[$i]}"
mkdir -p "$MODULE_SRC_DIR"
sed >"$MODULE_SRC_DIR/${CAMEL_NAMES[$i]}.swift" \
-e "s/${SNAKE_NAMES[$i]}FFI/$XCFRAMEWORK_MODULE_NAME/g" \
-e "s/private var initializationResult/private nonisolated(unsafe) var initializationResult/g" \
-e "s/static var vtable:/static nonisolated(unsafe) var vtable:/g" \
-e "s/fileprivate static var handleMap =/fileprivate static nonisolated(unsafe) var handleMap =/g" \
-e "s/fileprivate let uniffiContinuationHandleMap =/fileprivate nonisolated(unsafe) let uniffiContinuationHandleMap =/g" \
-e "s/\(public struct [[:alnum:]]\{1,\}\)/\1: Sendable/g" \
-e "s/\(public enum [[:alnum:]]\{1,\}\)/\1: Sendable/g" \
-e "s/\(public struct FfiConverter[[:alnum:]]\{1,\}\): Sendable/\1/g" \
"$SWIFT_FILES_DIR/${SNAKE_NAMES[$i]}.swift"
cat >>"$PKG_FILE" <<EOF
.target(
name: "${CAMEL_NAMES[$i]}",
dependencies: [
.target(name: "$XCFRAMEWORK_MODULE_NAME")

]
),
EOF
done

cat >>"$PKG_FILE" <<EOF
.binaryTarget(
name: "$XCFRAMEWORK_MODULE_NAME",
path: "./$XCFRAMEWORK_MODULE_NAME.xcframework"

)
]
)
EOF
15 changes: 15 additions & 0 deletions examples/app/uniffi-bindgen-swift-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "uniffi-bindgen-swift-cli"
version = "0.1.0"
edition = "2021"
publish = false

[[bin]]
name = "uniffi-bindgen-swift"
path = "uniffi-bindgen-swift.rs"

[dependencies]
uniffi = { workspace = true, features = ["cli"] }

[features]
ffi-trace = ["uniffi/ffi-trace"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
uniffi::uniffi_bindgen_swift()
}
2 changes: 1 addition & 1 deletion fixtures/ext-types/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ external-crates = [
]

[lib]
crate-type = ["lib", "cdylib"]
crate-type = ["lib", "cdylib", "staticlib"]
name = "uniffi_ext_types_lib"

[dependencies]
Expand Down
20 changes: 20 additions & 0 deletions fixtures/ext-types/lib/run-bindgen.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash

set -eou pipefail

SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
REPO_DIR="$SCRIPT_DIR/../../.."

export MANIFEST_FILE="$REPO_DIR/Cargo.toml"
export RUST_PACKAGE="uniffi-fixture-ext-types"
export LIBRARY_NAME="libuniffi_ext_types_lib.a"

# clean before generating
rm -rf "$REPO_DIR/target/swift" \
"$REPO_DIR/target/swift-package" \
"$REPO_DIR/target/apple-ios-sim" \
"$REPO_DIR/target/apple-macos"

"$REPO_DIR/examples/app/swift-package/bindgen.sh"

(cd "$REPO_DIR/target/swift-package/UniffiFixtureExtTypesFFI"; swift build)