Skip to content

Commit

Permalink
Merge pull request #54 from MarcelStruckWO/multi-crate
Browse files Browse the repository at this point in the history
Bundle all headers and swift files for multi-crate UniFFI setups
  • Loading branch information
antoniusnaumann authored Apr 9, 2024
2 parents 06324e0 + 012c920 commit ae162f7
Show file tree
Hide file tree
Showing 22 changed files with 657 additions and 44 deletions.
34 changes: 18 additions & 16 deletions .github/workflows/examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: Examples

on:
push:
branches: [ "main" ]
branches: ["main"]
pull_request:
branches: [ "main" ]
branches: ["main"]

env:
CARGO_TERM_COLOR: always
Expand All @@ -13,23 +13,25 @@ jobs:
tests:
strategy:
matrix:
path: [
'./swift-examples/hello-world/greeter',
'./swift-examples/hello-world-macro/greeter'
path:
[
"./swift-examples/hello-world/greeter",
"./swift-examples/hello-world-macro/greeter",
"./swift-examples/hello-world-macro-multi-crate/greeter",
]
target: [
'platform=macOS,arch=x86_64',
'generic/platform=iOS',
"platform=macOS,arch=x86_64",
"generic/platform=iOS",
# 'platform=iOS Simulator,os=latest'
]
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Install
run: cargo install --force --path .
- name: Build example libraries
working-directory: ${{ matrix.path }}
run: cargo swift package --accept-all
- name: Build example apps
working-directory: ${{ matrix.path }}/../app
run: xcodebuild -scheme App -destination "${{ matrix.target }}" CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO
- uses: actions/checkout@v4
- name: Install
run: cargo install --force --path .
- name: Build example libraries
working-directory: ${{ matrix.path }}
run: cargo swift package --accept-all
- name: Build example apps
working-directory: ${{ matrix.path }}/../app
run: xcodebuild -scheme App -destination "${{ matrix.target }}" CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO
1 change: 1 addition & 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 @@ -21,6 +21,7 @@ camino = "1.1.6"
cargo_metadata = "0.18.1"
clap = { version = "4.5.4", features = ["derive"] }
convert_case = "0.6.0"
glob = "0.3.1"
nonempty = "0.10.0"
serde = { version = "1.0.197", features = ["derive"] }

Expand Down
45 changes: 30 additions & 15 deletions src/bindings.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::fs::{self, create_dir};
use std::{
fs::{self, create_dir},
io,
};

use crate::Result;
use camino::Utf8Path;
Expand All @@ -7,7 +10,7 @@ use uniffi_bindgen::{bindings::TargetLanguage, BindingGeneratorDefault};
use crate::recreate_dir;

/// Generates UniFFI bindings for crate and returns the .udl namespace
pub fn generate_bindings(lib_path: &Utf8Path, crate_name: &str) -> Result<()> {
pub fn generate_bindings(lib_path: &Utf8Path) -> Result<()> {
let out_dir = Utf8Path::new("./generated");
let headers = out_dir.join("headers");
let sources = out_dir.join("sources");
Expand All @@ -16,9 +19,9 @@ pub fn generate_bindings(lib_path: &Utf8Path, crate_name: &str) -> Result<()> {
create_dir(&headers)?;
create_dir(&sources)?;

uniffi_bindgen::library_mode::generate_bindings(
let uniffi_outputs = uniffi_bindgen::library_mode::generate_bindings(
lib_path,
Some(crate_name.to_owned()),
None,
&BindingGeneratorDefault {
target_languages: vec![TargetLanguage::Swift],
try_format_code: false,
Expand All @@ -28,17 +31,29 @@ pub fn generate_bindings(lib_path: &Utf8Path, crate_name: &str) -> Result<()> {
false,
)?;

fs::copy(
out_dir.join(format!("{crate_name}.swift")),
sources.join(format!("{crate_name}.swift")),
)?;

let header = format!("{crate_name}FFI.h");
fs::copy(out_dir.join(&header), headers.join(&header))?;
fs::copy(
out_dir.join(format!("{crate_name}FFI.modulemap")),
headers.join("module.modulemap"),
)?;
let mut modulemap = fs::OpenOptions::new()
.create(true)
.append(true)
.open(headers.join("module.modulemap"))?;

for output in uniffi_outputs {
let crate_name = output.crate_name;
fs::copy(
out_dir.join(format!("{crate_name}.swift")),
sources.join(format!("{crate_name}.swift")),
)?;

let ffi_name = format!("{crate_name}FFI");
fs::copy(
out_dir.join(format!("{ffi_name}.h")),
headers.join(format!("{ffi_name}.h")),
)?;

let mut modulemap_part = fs::OpenOptions::new()
.read(true)
.open(out_dir.join(format!("{ffi_name}.modulemap")))?;
io::copy(&mut modulemap_part, &mut modulemap)?;
}

Ok(())
}
7 changes: 3 additions & 4 deletions src/commands/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ fn run_for_crate(

recreate_output_dir(&package_name).expect("Could not create package output directory!");
create_xcframework_with_output(&targets, &crate_name, &package_name, mode, lib_type, config)?;
create_package_with_output(&package_name, &crate_name, disable_warnings, config)?;
create_package_with_output(&package_name, disable_warnings, config)?;

Ok(())
}
Expand Down Expand Up @@ -361,7 +361,7 @@ fn generate_bindings_with_output(
let arch = archs.first();
let lib_path: Utf8PathBuf = format!("{target}/{arch}/{mode}/{lib_file}").into();

generate_bindings(&lib_path, lib_name)
generate_bindings(&lib_path)
.map_err(|e| format!("Could not generate UniFFI bindings for udl files due to the following error: \n {e}").into())
})
}
Expand Down Expand Up @@ -415,14 +415,13 @@ fn create_xcframework_with_output(

fn create_package_with_output(
package_name: &str,
namespace: &str,
disable_warnings: bool,
config: &Config,
) -> Result<()> {
run_step(
config,
format!("Creating Swift Package '{package_name}'..."),
|| create_swiftpackage(package_name, namespace, disable_warnings),
|| create_swiftpackage(package_name, disable_warnings),
)?;

let spinner = config.silent.not().then(|| {
Expand Down
28 changes: 19 additions & 9 deletions src/swiftpackage.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use askama::Template;
use glob::glob;
use std::fs::{copy, create_dir_all, write};

use crate::{recreate_dir, templating, Result};

/// Create artifacts for a swift package given the package name
///
/// **Note**: This method assumes that a directory with the package name and the .xcframework already exists
pub fn create_swiftpackage(package_name: &str, namespace: &str, disable_warnings: bool) -> Result<()> {
pub fn create_swiftpackage(package_name: &str, disable_warnings: bool) -> Result<()> {
// TODO: Instead of assuming the directory and the xcframework, let this manage directory
// recreation and let it copy the xcframework
let package_manifest = templating::PackageSwift {
Expand All @@ -23,14 +24,23 @@ pub fn create_swiftpackage(package_name: &str, namespace: &str, disable_warnings
create_dir_all(format!("{}/Sources/{}", package_name, package_name))
.map_err(|e| format!("Could not create module sources directory: \n {e}"))?;

copy(
format!("./generated/sources/{namespace}.swift"),
format!(
"{}/Sources/{}/{}.swift",
package_name, package_name, namespace
),
)
.map_err(|e| format!("Could not copy generated swift source files: \n {e}"))?;
for swift_file in glob("./generated/sources/*.swift")
.map_err(|e| format!("Could not find generated swift source files: \n {e}"))?
{
let swift_file = swift_file
.map_err(|e| format!("Could not find generated swift source file: \n {e}"))?;
let file_name = swift_file
.file_name()
.ok_or("Could not get file name")?
.to_str()
.ok_or("Could not convert file name to string")?
.to_string();
copy(
swift_file,
format!("{}/Sources/{}/{}", package_name, package_name, file_name),
)
.map_err(|e| format!("Could not copy generated swift source files: \n {e}"))?;
}

Ok(())
}
Expand Down
3 changes: 3 additions & 0 deletions swift-examples/hello-world-macro-multi-crate/app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
**/xcuserdata/
.DS_Store
build/
Loading

0 comments on commit ae162f7

Please sign in to comment.