Build improvements with UniFFI library mode

Bumped UniFFI to 0.28.2

Added a tool to run uniffi-bindgen in library mode.  It can input either
a specific library path or the megazord crate name.

Use that simplify several build scripts -- especially the generate docs
ones.  The best part of this is that we no longer have to maintain
hand-written modulemaps, which makes adding a new component harder than
it needs to be.

Split out the uniffi-bindgen commands from `build-xcframework.sh`.  This
way you can run them standalone and see the results, even if you don't
have XCode setup.

One change is that
automation/swift-components-docs/generate-swift-project.sh now uses
`megazord_ios` rather than `megazord`.  I think this should result in
slightly more accurate docs, since historically some components in the
Android megazord aren't in the iOS one (Although, I think they match at
the present).
This commit is contained in:
Ben Dean-Kawamura 2024-09-18 10:22:53 -04:00 коммит произвёл bendk
Родитель 581f5d2866
Коммит eb1f268654
26 изменённых файлов: 303 добавлений и 145 удалений

Просмотреть файл

@ -1,6 +1,7 @@
[alias] [alias]
regen-protobufs = ["run", "--bin", "protobuf-gen", "tools/protobuf_files.toml"] regen-protobufs = ["run", "--bin", "protobuf-gen", "tools/protobuf_files.toml"]
uniffi-bindgen = ["run", "--package", "embedded-uniffi-bindgen", "--"] uniffi-bindgen = ["run", "--package", "embedded-uniffi-bindgen", "--"]
uniffi-bindgen-library-mode = ["run", "--package", "uniffi-bindgen-library-mode", "--"]
dev-install = ["install", "asdev"] dev-install = ["install", "asdev"]
verify_env = ["asdev", "verify_env"] verify_env = ["asdev", "verify_env"]
fxa = ["run", "-p", "examples-fxa-client", "--"] fxa = ["run", "-p", "examples-fxa-client", "--"]

51
Cargo.lock сгенерированный
Просмотреть файл

@ -4805,12 +4805,13 @@ checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
[[package]] [[package]]
name = "uniffi" name = "uniffi"
version = "0.28.0" version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31bff6daf87277a9014bcdefbc2842b0553392919d1096843c5aad899ca4588" checksum = "51ce6280c581045879e11b400bae14686a819df22b97171215d15549efa04ddb"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"camino", "camino",
"cargo_metadata",
"clap 4.2.2", "clap 4.2.2",
"uniffi_bindgen", "uniffi_bindgen",
"uniffi_build", "uniffi_build",
@ -4818,11 +4819,23 @@ dependencies = [
"uniffi_macros", "uniffi_macros",
] ]
[[package]]
name = "uniffi-bindgen-library-mode"
version = "0.1.0"
dependencies = [
"anyhow",
"camino",
"cargo_metadata",
"clap 4.2.2",
"uniffi",
"uniffi_bindgen",
]
[[package]] [[package]]
name = "uniffi_bindgen" name = "uniffi_bindgen"
version = "0.28.0" version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96061d7e01b185aa405f7c9b134741ab3e50cc6796a47d6fd8ab9a5364b5feed" checksum = "5e9f25730c9db2e878521d606f54e921edb719cdd94d735e7f97705d6796d024"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"askama", "askama",
@ -4838,15 +4851,14 @@ dependencies = [
"textwrap 0.16.1", "textwrap 0.16.1",
"toml", "toml",
"uniffi_meta", "uniffi_meta",
"uniffi_testing",
"uniffi_udl", "uniffi_udl",
] ]
[[package]] [[package]]
name = "uniffi_build" name = "uniffi_build"
version = "0.28.0" version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d6b86f9b221046af0c533eafe09ece04e2f1ded04ccdc9bba0ec09aec1c52bd" checksum = "88dba57ac699bd8ec53d6a352c8dd0e479b33f698c5659831bb1e4ce468c07bd"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"camino", "camino",
@ -4855,9 +4867,9 @@ dependencies = [
[[package]] [[package]]
name = "uniffi_checksum_derive" name = "uniffi_checksum_derive"
version = "0.28.0" version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fcfa22f55829d3aaa7acfb1c5150224188fe0f27c59a8a3eddcaa24d1ffbe58" checksum = "d2c801f0f05b06df456a2da4c41b9c2c4fdccc6b9916643c6c67275c4c9e4d07"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.72", "syn 2.0.72",
@ -4865,13 +4877,12 @@ dependencies = [
[[package]] [[package]]
name = "uniffi_core" name = "uniffi_core"
version = "0.28.0" version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3210d57d6ab6065ab47a2898dacdb7c606fd6a4156196831fa3bf82e34ac58a6" checksum = "61049e4db6212d0ede80982adf0e1d6fa224e6118387324c5cfbe3083dfb2252"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
"camino",
"log", "log",
"once_cell", "once_cell",
"paste", "paste",
@ -4880,9 +4891,9 @@ dependencies = [
[[package]] [[package]]
name = "uniffi_macros" name = "uniffi_macros"
version = "0.28.0" version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b58691741080935437dc862122e68d7414432a11824ac1137868de46181a0bd2" checksum = "b40fd2249e0c5dcbd2bfa3c263db1ec981f7273dca7f4132bf06a272359a586c"
dependencies = [ dependencies = [
"bincode", "bincode",
"camino", "camino",
@ -4898,9 +4909,9 @@ dependencies = [
[[package]] [[package]]
name = "uniffi_meta" name = "uniffi_meta"
version = "0.28.0" version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7663eacdbd9fbf4a88907ddcfe2e6fa85838eb6dc2418a7d91eebb3786f8e20b" checksum = "c9ad57039b4fafdbf77428d74fff40e0908e5a1731e023c19cfe538f6d4a8ed6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@ -4910,9 +4921,9 @@ dependencies = [
[[package]] [[package]]
name = "uniffi_testing" name = "uniffi_testing"
version = "0.28.0" version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f922465f7566f25f8fe766920205fdfa9a3fcdc209c6bfb7557f0b5bf45b04dd" checksum = "21fa171d4d258dc51bbd01893cc9608c1b62273d2f9ea55fb64f639e77824567"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"camino", "camino",
@ -4923,9 +4934,9 @@ dependencies = [
[[package]] [[package]]
name = "uniffi_udl" name = "uniffi_udl"
version = "0.28.0" version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cef408229a3a407fafa4c36dc4f6ece78a6fb258ab28d2b64bddd49c8cb680f6" checksum = "f52299e247419e7e2934bef2f94d7cccb0e6566f3248b1d48b160d8f369a2668"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"textwrap 0.16.1", "textwrap 0.16.1",

Просмотреть файл

@ -50,6 +50,7 @@ members = [
"tools/protobuf-gen", "tools/protobuf-gen",
"tools/embedded-uniffi-bindgen", "tools/embedded-uniffi-bindgen",
"tools/start-bindings", "tools/start-bindings",
"tools/uniffi-bindgen-library-mode",
"automation/swift-components-docs", "automation/swift-components-docs",
"examples/*/", "examples/*/",
@ -122,6 +123,7 @@ default-members = [
# "testing/sync-test", # "testing/sync-test",
"tools/protobuf-gen", "tools/protobuf-gen",
"tools/embedded-uniffi-bindgen", "tools/embedded-uniffi-bindgen",
"tools/uniffi-bindgen-library-mode",
"examples/*/", "examples/*/",
"testing/separated/*/", "testing/separated/*/",
] ]
@ -129,7 +131,8 @@ default-members = [
[workspace.dependencies] [workspace.dependencies]
rusqlite = "0.31.0" rusqlite = "0.31.0"
libsqlite3-sys = "0.28.0" libsqlite3-sys = "0.28.0"
uniffi = "0.28.0" uniffi = "0.28.2"
uniffi_bindgen = "0.28.2"
[profile.release] [profile.release]
opt-level = "s" opt-level = "s"

Просмотреть файл

@ -14,20 +14,10 @@ CARGO="$HOME/.cargo/bin/cargo"
# Set the documentation directory # Set the documentation directory
KOTLIN_DIR="$WORKING_DIR/src/main/kotlin" KOTLIN_DIR="$WORKING_DIR/src/main/kotlin"
# Build the Rust crate using Cargo # Generate Kotlin bindings to use as the documentation source
echo "Building the Rust crate..."
$CARGO build -p megazord --release
# Define the path to the generated Rust library
LIBRARY_FILE="$REPO_ROOT/target/release/libmegazord.so"
if [[ ! -f "$LIBRARY_FILE" ]]; then
echo "Error: Rust library not found at $LIBRARY_FILE"
exit 1
fi
# Generate Kotlin bindings, headers, and module map using uniffi-bindgen
echo "Generating Kotlin bindings with uniffi-bindgen..." echo "Generating Kotlin bindings with uniffi-bindgen..."
$CARGO uniffi-bindgen generate --library "$LIBRARY_FILE" --language kotlin --out-dir "$KOTLIN_DIR"
$CARGO uniffi-bindgen-library-mode -m megazord kotlin "$KOTLIN_DIR"
# Generate documentation with increased memory # Generate documentation with increased memory
(cd "$WORKING_DIR" && "$REPO_ROOT/gradlew" --max-workers=2 dokkaHtml -Dorg.gradle.vfs.watch=false) (cd "$WORKING_DIR" && "$REPO_ROOT/gradlew" --max-workers=2 dokkaHtml -Dorg.gradle.vfs.watch=false)

Просмотреть файл

@ -1,21 +0,0 @@
#!/usr/bin/env bash
# Define the module name and path to the include directory
MODULE_NAME="MozillaRustComponents"
INCLUDE_DIR="Sources/SwiftComponents/include"
MODULEMAP_FILE="$INCLUDE_DIR/module.modulemap"
# Start creating the module map
echo "module $MODULE_NAME {" > "$MODULEMAP_FILE"
# Find all .h files in the include directory and add them to the module map
for header in "$INCLUDE_DIR"/*.h; do
echo " header \"$(basename "$header")\"" >> "$MODULEMAP_FILE"
done
# Add export statement to the end of the module map
echo " export *" >> "$MODULEMAP_FILE"
echo "}" >> "$MODULEMAP_FILE"
# Confirm module.modulemap was created
echo "module.modulemap generated at: $MODULEMAP_FILE"

Просмотреть файл

@ -8,7 +8,6 @@ set -euo pipefail
FRAMEWORK_NAME="SwiftComponents" FRAMEWORK_NAME="SwiftComponents"
THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
REPO_ROOT="$( dirname "$( dirname "$THIS_DIR" )" )"
WORKING_DIR="$THIS_DIR" WORKING_DIR="$THIS_DIR"
CARGO="$HOME/.cargo/bin/cargo" CARGO="$HOME/.cargo/bin/cargo"
@ -17,39 +16,10 @@ INCLUDE_DIR="$WORKING_DIR/Sources/$FRAMEWORK_NAME/include"
SWIFT_DIR="$WORKING_DIR/Sources/$FRAMEWORK_NAME" SWIFT_DIR="$WORKING_DIR/Sources/$FRAMEWORK_NAME"
mkdir -p "$INCLUDE_DIR" mkdir -p "$INCLUDE_DIR"
# Build the Rust crate using Cargo # Generate Swift bindings, headers, and module map to use as the documentation source
echo "Building the Rust crate..." echo "Generating Swift bindings"
$CARGO build -p megazord_ios --release $CARGO uniffi-bindgen-library-mode -m megazord_ios swift --swift-sources "$SWIFT_DIR"
$CARGO uniffi-bindgen-library-mode -m megazord_ios swift --headers --modulemap --modulemap-filename module.modulemap "$INCLUDE_DIR"
# Define the path to the generated Rust library
LIBRARY_FILE="$REPO_ROOT/target/release/libmegazord_ios.a"
if [[ ! -f "$LIBRARY_FILE" ]]; then
echo "Error: Rust library not found at $LIBRARY_FILE"
exit 1
fi
# Generate Swift bindings, headers, and module map using uniffi-bindgen
echo "Generating Swift bindings with uniffi-bindgen..."
$CARGO uniffi-bindgen generate --library "$LIBRARY_FILE" --language swift --out-dir "$SWIFT_DIR"
# Move generated header files to the include directory
echo "Moving header files to include directory..."
mv "$SWIFT_DIR"/*.h "$INCLUDE_DIR" || {
echo "Error: Failed to move header files."
exit 1
}
# Remove any old modulemaps
echo "Cleaning up old module maps..."
rm -f "$SWIFT_DIR"/*.modulemap
# Generate a new module map
echo "Generating module map..."
if [[ ! -f "$WORKING_DIR/generate-modulemap.sh" ]]; then
echo "Error: generate-modulemap.sh script not found."
exit 1
fi
"$WORKING_DIR/generate-modulemap.sh"
# Success message # Success message
echo "Successfully generated Swift bindings, headers, and module map." echo "Successfully generated Swift bindings, headers, and module map."

Просмотреть файл

@ -4,4 +4,3 @@ package_name = "mozilla.appservices.autofill"
[bindings.swift] [bindings.swift]
ffi_module_name = "MozillaRustComponents" ffi_module_name = "MozillaRustComponents"
ffi_module_filename = "autofillFFI" ffi_module_filename = "autofillFFI"
generate_module_map = false

Просмотреть файл

@ -4,4 +4,3 @@ package_name = "mozilla.appservices.crashtest"
[bindings.swift] [bindings.swift]
ffi_module_name = "MozillaRustComponents" ffi_module_name = "MozillaRustComponents"
ffi_module_filename = "crashtestFFI" ffi_module_filename = "crashtestFFI"
generate_module_map = false

Просмотреть файл

@ -4,4 +4,3 @@ package_name = "mozilla.appservices.fxaclient"
[bindings.swift] [bindings.swift]
ffi_module_name = "MozillaRustComponents" ffi_module_name = "MozillaRustComponents"
ffi_module_filename = "fxa_clientFFI" ffi_module_filename = "fxa_clientFFI"
generate_module_map = false

Просмотреть файл

@ -4,4 +4,3 @@ package_name = "mozilla.appservices.logins"
[bindings.swift] [bindings.swift]
ffi_module_name = "MozillaRustComponents" ffi_module_name = "MozillaRustComponents"
ffi_module_filename = "loginsFFI" ffi_module_filename = "loginsFFI"
generate_module_map = false

Просмотреть файл

@ -13,7 +13,6 @@ from_custom = "{}.toString()"
[bindings.swift] [bindings.swift]
ffi_module_name = "MozillaRustComponents" ffi_module_name = "MozillaRustComponents"
ffi_module_filename = "nimbusFFI" ffi_module_filename = "nimbusFFI"
generate_module_map = false
[bindings.python] [bindings.python]
# This can be commented out, and the `--library` argument of `bindgen-uniffi` should be used instead. # This can be commented out, and the `--library` argument of `bindgen-uniffi` should be used instead.

Просмотреть файл

@ -6,4 +6,3 @@ package_name = "mozilla.appservices.places.uniffi"
[bindings.swift] [bindings.swift]
ffi_module_name = "MozillaRustComponents" ffi_module_name = "MozillaRustComponents"
ffi_module_filename = "placesFFI" ffi_module_filename = "placesFFI"
generate_module_map = false

Просмотреть файл

@ -13,5 +13,4 @@ from_custom = "{}.toString()"
[bindings.swift] [bindings.swift]
ffi_module_name = "MozillaRustComponents" ffi_module_name = "MozillaRustComponents"
ffi_module_filename = "remote_settingsFFI" ffi_module_filename = "remote_settingsFFI"
generate_module_map = false

Просмотреть файл

@ -4,4 +4,3 @@ package_name = "mozilla.appservices.errorsupport"
[bindings.swift] [bindings.swift]
ffi_module_name = "MozillaRustComponents" ffi_module_name = "MozillaRustComponents"
ffi_module_filename = "errorFFI" ffi_module_filename = "errorFFI"
generate_module_map = false

Просмотреть файл

@ -4,4 +4,3 @@ package_name = "mozilla.appservices.rust_log_forwarder"
[bindings.swift] [bindings.swift]
ffi_module_name = "MozillaRustComponents" ffi_module_name = "MozillaRustComponents"
ffi_module_filename = "rustlogforwarderFFI" ffi_module_filename = "rustlogforwarderFFI"
generate_module_map = false

Просмотреть файл

@ -4,4 +4,3 @@ package_name = "mozilla.appservices.sync15"
[bindings.swift] [bindings.swift]
ffi_module_name = "MozillaRustComponents" ffi_module_name = "MozillaRustComponents"
ffi_module_filename = "sync15FFI" ffi_module_filename = "sync15FFI"
generate_module_map = false

Просмотреть файл

@ -4,4 +4,3 @@ package_name = "mozilla.appservices.syncmanager"
[bindings.swift] [bindings.swift]
ffi_module_name = "MozillaRustComponents" ffi_module_name = "MozillaRustComponents"
ffi_module_filename = "syncmanagerFFI" ffi_module_filename = "syncmanagerFFI"
generate_module_map = false

Просмотреть файл

@ -4,4 +4,3 @@ package_name = "mozilla.appservices.remotetabs"
[bindings.swift] [bindings.swift]
ffi_module_name = "MozillaRustComponents" ffi_module_name = "MozillaRustComponents"
ffi_module_filename = "tabsFFI" ffi_module_filename = "tabsFFI"
generate_module_map = false

Просмотреть файл

@ -133,7 +133,6 @@ rm -rf "$XCFRAMEWORK_ROOT"
COMMON="$XCFRAMEWORK_ROOT/common/$FRAMEWORK_NAME.framework" COMMON="$XCFRAMEWORK_ROOT/common/$FRAMEWORK_NAME.framework"
mkdir -p "$COMMON/Modules" mkdir -p "$COMMON/Modules"
cp "$WORKING_DIR/module.modulemap" "$COMMON/Modules/"
cp "$WORKING_DIR/DEPENDENCIES.md" "$COMMON/DEPENDENCIES.md" cp "$WORKING_DIR/DEPENDENCIES.md" "$COMMON/DEPENDENCIES.md"
@ -147,17 +146,8 @@ UNIFFI_BINDGEN_LIBRARY="$TARGET_DIR/aarch64-apple-ios/$BUILD_PROFILE/$LIB_NAME"
cp "$WORKING_DIR/$FRAMEWORK_NAME.h" "$COMMON/Headers" cp "$WORKING_DIR/$FRAMEWORK_NAME.h" "$COMMON/Headers"
cp "$REPO_ROOT/components/viaduct/ios/RustViaductFFI.h" "$COMMON/Headers" cp "$REPO_ROOT/components/viaduct/ios/RustViaductFFI.h" "$COMMON/Headers"
# Next, move the generated headers. # Next, generate files with uniffi-bindgen
# "$THIS_DIR/generate-files.sh" "$UNIFFI_BINDGEN_LIBRARY" "$COMMON"
# TODO: https://github.com/mozilla/uniffi-rs/issues/1060
#
# It would be neat if there was a single UniFFI command that would generate headers-only, but for
# now we generate both the `.h` and `.swift` files, then delete the `.swift`. Bleh.
$CARGO uniffi-bindgen generate --library "$UNIFFI_BINDGEN_LIBRARY" -l swift -o "$COMMON/Headers"
rm -rf "$COMMON"/Headers/*.swift
# Flesh out the framework for each architecture based on the common files. # Flesh out the framework for each architecture based on the common files.
# It's a little fiddly, because we apparently need to put all the simulator targets # It's a little fiddly, because we apparently need to put all the simulator targets

Просмотреть файл

@ -1,6 +0,0 @@
framework module MozillaRustComponents {
umbrella header "MozillaRustComponents.h"
export *
module * { export * }
}

Просмотреть файл

@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -ex
if [[ $# -ne 2 ]] ; then
echo "USAGE megazords/ios-rust/generate-files.sh [UNIFFI_BINDGEN_LIBRARY] [COMMON]"
exit 1
fi
UNIFFI_BINDGEN_LIBRARY=$1
COMMON=$2
# Helper to run the cargo build command in a controlled environment.
# It's important that we don't let environment variables from the user's default
# desktop build environment leak into the iOS build, otherwise it might e.g.
# link against the desktop build of NSS.
CARGO="$HOME/.cargo/bin/cargo"
# Run uniffi-bindgen-library-mode to generate the files.
#
# We can't use the `-m` flag because UNIFFI_BINDGEN_LIBRARY is cross-compiled, which our
# uniffi-bindgen-library-mode tool can't handle yet.
"$CARGO" uniffi-bindgen-library-mode -l "$UNIFFI_BINDGEN_LIBRARY" swift --headers "$COMMON/Headers"
"$CARGO" uniffi-bindgen-library-mode -l "$UNIFFI_BINDGEN_LIBRARY" swift --modulemap "$COMMON/Modules" --xcframework --modulemap-filename module.modulemap

Просмотреть файл

@ -1,6 +0,0 @@
framework module MozillaRustComponents {
umbrella header "MozillaRustComponents.h"
export *
module * { export * }
}

Просмотреть файл

@ -143,21 +143,16 @@ def generate_uniffi_bindings(args):
# Generate sources for Focus # Generate sources for Focus
generate_uniffi_bindings_for_target(focus_out_dir, "megazord_focus") generate_uniffi_bindings_for_target(focus_out_dir, "megazord_focus")
def generate_uniffi_bindings_for_target(out_dir, library_name): def generate_uniffi_bindings_for_target(out_dir, megazord):
log(f"generating sources for {library_name}") log(f"generating sources for {megazord}")
# Use a megazord library that was built for the XCFramework. Pick an arbitrary target, since # We can't use the `-m` flag here because the megazord library was cross-compiled and the
# the target doesn't affect the UniFFI bindings. # `uniffi-bindgen-library-mode` tool can't handle that yet. Instead, send one of the library
lib_path = f'target/aarch64-apple-ios/release/lib{library_name}.a' # paths using the `-l` flag. Pick an arbitrary target, since the it doesn't affect the UniFFI
# bindings.
cmdline = ['generate', '--library', lib_path, '-l', 'swift', '-o', out_dir] lib_path = f'target/aarch64-apple-ios/release/lib{megazord}.a'
run_uniffi_bindgen(cmdline) subprocess.check_call([
'cargo', 'uniffi-bindgen-library-mode', '-l', lib_path, "swift", out_dir
def run_uniffi_bindgen(bindgen_args): ])
all_args = [
'cargo', 'run', '-p', 'embedded-uniffi-bindgen',
]
all_args.extend(bindgen_args)
subprocess.check_call(all_args, cwd=ROOT_DIR)
def copy_source_dirs(args): def copy_source_dirs(args):
out_dir = args.out_dir / 'all' out_dir = args.out_dir / 'all'

Просмотреть файл

@ -89,17 +89,20 @@ def _build_shared_library(megazord, target, dist_dir):
'cargo', 'build', '--manifest-path', f'{SRC_ROOT}/megazords/{megazord}/Cargo.toml', '--release', '--target', target, 'cargo', 'build', '--manifest-path', f'{SRC_ROOT}/megazords/{megazord}/Cargo.toml', '--release', '--target', target,
], env=env, cwd=SRC_ROOT) ], env=env, cwd=SRC_ROOT)
# Move the .so file to the dist_directory
shutil.move(SRC_ROOT / 'target' / target / 'release' / filename, dist_dir / filename)
# This is only temporary, until cirrus uses pre-built binaries. # This is only temporary, until cirrus uses pre-built binaries.
_patch_uniffi_tomls() _patch_uniffi_tomls()
# Generate the Python FFI. We do this with `--library` so we don't have to specify the UDL or the uniffi.toml file. library_path = SRC_ROOT / 'target' / target / 'release' / filename
# Generate the Python FFI. We do this with `uniffi-bindgen-library-mode` so we don't have to specify the UDL or the uniffi.toml file.
# Use the `-l` flag rather than `-m` since we want to specify a particular target.
subprocess.check_call([ subprocess.check_call([
'cargo', 'uniffi-bindgen', 'generate', '--library', dist_dir / filename, '--language', 'python', '--out-dir', dist_dir, 'cargo', 'uniffi-bindgen-library-mode', '-l', library_path.as_posix(), 'python', dist_dir
], env=env, cwd=SRC_ROOT) ], env=env, cwd=SRC_ROOT)
# Move the .so file to the dist_directory
shutil.move(SRC_ROOT / 'target' / target / 'release' / filename, dist_dir / filename)
return filename return filename
def _patch_uniffi_tomls(): def _patch_uniffi_tomls():

Просмотреть файл

@ -0,0 +1,14 @@
[package]
name = "uniffi-bindgen-library-mode"
version = "0.1.0"
authors = ["The Firefox Sync Developers <sync-team@mozilla.com>"]
edition = "2021"
license = "MPL-2.0"
[dependencies]
uniffi = { workspace = true, features = ["cli"] }
uniffi_bindgen = { workspace = true }
clap = "4"
cargo_metadata = "0.15"
camino = "1"
anyhow = "1"

Просмотреть файл

@ -0,0 +1,202 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::{
env::consts::{DLL_PREFIX, DLL_SUFFIX},
fmt, process,
};
use anyhow::{bail, Result};
use camino::{Utf8Path, Utf8PathBuf};
use clap::{Args, Parser, Subcommand};
use uniffi_bindgen::bindings::{generate_swift_bindings, SwiftBindingsOptions};
#[derive(Parser)]
#[command(version, about, long_about = None)]
struct Cli {
#[command(flatten)]
megazord: MegazordArg,
#[command(subcommand)]
command: Command,
}
#[derive(Args)]
#[group(required = true, multiple = false)]
struct MegazordArg {
/// Name of the megazord to use
#[arg(short, long, value_parser=["megazord", "megazord_ios", "megazord_focus", "cirrus", "nimbus-experimenter"])]
megazord: Option<String>,
/// Path to a library file
#[arg(short, long)]
library: Option<Utf8PathBuf>,
}
#[derive(Subcommand)]
enum Command {
Kotlin {
out_dir: Utf8PathBuf,
},
Swift {
out_dir: Utf8PathBuf,
/// Generate swift files
#[arg(long)]
swift_sources: bool,
/// Generate header files
#[arg(long)]
headers: bool,
/// Generate modulemap
#[arg(long)]
modulemap: bool,
// Generate an xcframework-compatible modulemap
#[arg(long)]
xcframework: bool,
/// module name for the generated modulemap
#[arg(long)]
module_name: Option<String>,
/// filename for the generate modulemap
#[arg(long)]
modulemap_filename: Option<String>,
},
Python {
out_dir: Utf8PathBuf,
},
}
enum Language {
Kotlin,
Swift,
Python,
}
fn main() {
if let Err(e) = run_uniffi_bindgen(Cli::parse()) {
eprintln!("{e}");
std::process::exit(1);
}
}
fn run_uniffi_bindgen(cli: Cli) -> Result<()> {
let metadata = cargo_metadata::MetadataCommand::new()
.exec()
.expect("error running cargo metadata");
let megazord = Megazord::new(
&cli.megazord,
cli.command.language(),
&metadata.workspace_root,
)?;
let config_supplier = uniffi::CargoMetadataConfigSupplier::from(metadata);
match cli.command {
Command::Kotlin { out_dir } => {
uniffi::generate_bindings_library_mode(
&megazord.library_path,
None,
&uniffi::KotlinBindingGenerator,
&config_supplier,
None,
&out_dir,
false,
)?;
}
Command::Swift {
out_dir,
mut swift_sources,
mut headers,
mut modulemap,
xcframework,
module_name,
modulemap_filename,
} => {
let module_name = module_name.unwrap_or_else(|| "MozillaRustComponents".to_owned());
// If no generate kinds were specified, generate them all
if !(swift_sources || headers || modulemap) {
swift_sources = true;
headers = true;
modulemap = true;
}
generate_swift_bindings(SwiftBindingsOptions {
out_dir,
generate_swift_sources: swift_sources,
generate_headers: headers,
generate_modulemap: modulemap,
library_path: megazord.library_path,
xcframework,
module_name: Some(module_name),
modulemap_filename,
metadata_no_deps: false,
})?;
}
Command::Python { out_dir } => {
uniffi::generate_bindings_library_mode(
&megazord.library_path,
None,
&uniffi::PythonBindingGenerator,
&config_supplier,
None,
&out_dir,
false,
)?;
}
};
Ok(())
}
struct Megazord {
library_path: Utf8PathBuf,
}
impl Megazord {
fn new(arg: &MegazordArg, language: Language, workspace_root: &Utf8Path) -> Result<Self> {
if let Some(crate_name) = &arg.megazord {
// Build the megazord
process::Command::new("cargo")
.args(["build", "--release", "-p", crate_name])
.spawn()?
.wait()?;
let filename = match language {
// Swift uses static libs
Language::Swift => format!("lib{}.a", crate_name.replace('-', "_")),
// Everything else uses dynamic libraries
_ => format!(
"{}{}{}",
DLL_PREFIX,
crate_name.replace('-', "_"),
DLL_SUFFIX
),
};
let library_path = workspace_root.join("target").join("release").join(filename);
Ok(Self { library_path })
} else if let Some(library_path) = &arg.library {
Ok(Self {
library_path: library_path.clone(),
})
} else {
bail!("Neither megazord nor library specified")
}
}
}
impl fmt::Display for Language {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let name = match self {
Self::Swift => "swift",
Self::Kotlin => "kotlin",
Self::Python => "python",
};
write!(f, "{}", name)
}
}
impl Command {
fn language(&self) -> Language {
match self {
Self::Kotlin { .. } => Language::Kotlin,
Self::Swift { .. } => Language::Swift,
Self::Python { .. } => Language::Python,
}
}
}