Flutter uniFFI (#510)

* Flutter uniffi

* Set on-demand resources

* Do not build non-uniffi libraries

* Change iosLibName

* Add BreezSDKLiquid as on demand resources

* Use downloaded framework

* Add Sources to published flutter package

* Set OTHER_LDFLAGS

* Add logging

* Refactor library initialization logic and throw an error if initialization fails

* Do not statically link framework on production

* Use uniFFI headers to generate FlutterBreezLiquidBindings

* Re add frb header

* Correct the library name

* Remove static_framework

* Move source header files

* Copy iOS podspecs to macOS folder

* Update version of macOS podspecs

* Remove Windows & Linux support

* Remove CMake scripts

* Remove breez_sdk_liquid.podspec from version script

* Cleanup older build scripts used by melos & just recipes

* Remove softlink & copy recipes

Add recipe descriptions

* Rename link-uniffi recipe to link-headers

Make sure headers are linked after uniffi is built
  - Remove just gen recipe
Add recipe descriptions

* Set package versions on production files as well when publishing

* Include bindings project on melos script hooks

* Flutter uniffi

* Set on-demand resources

* Do not build non-uniffi libraries

* Change iosLibName

* Add BreezSDKLiquid as on demand resources

* Use downloaded framework

* Add Sources to published flutter package

* Set OTHER_LDFLAGS

* Add logging

* Refactor library initialization logic and throw an error if initialization fails

* Do not statically link framework on production

* Use uniFFI headers to generate FlutterBreezLiquidBindings

* Re add frb header

* Correct the library name

* Remove static_framework

* Move source header files

* Copy iOS podspecs to macOS folder

* Update version of macOS podspecs

* Remove Windows & Linux support

* Remove CMake scripts

* Remove breez_sdk_liquid.podspec from version script

* Cleanup older build scripts used by melos & just recipes

* Remove softlink & copy recipes

Add recipe descriptions

* Rename link-uniffi recipe to link-headers

Make sure headers are linked after uniffi is built
  - Remove just gen recipe
Add recipe descriptions

* Set package versions on production files as well when publishing

* Include bindings project on melos script hooks

* chore: just version

* fix: remove unused files on "Set package version" step

* copy FFI header files

* [WIP] Add macOS support

* remove example app on Flutter plugin

* Link headers before running ffigen on CI workflow

* macOS: add macos/Sources folder to .gitignore

.

* macOS: Copy iOS sources to macOS sources after downloading bindings

* macOS: copy sources & framework file to macos folder on build-uniffi-swift script

* import breez_sdk_liquidFFI header on plugin file

Update flutter_breez_liquid.c

* cleanup header file artifacts

---------

Co-authored-by: Ross Savage <hello@satimoto.com>
This commit is contained in:
Erdem Yerebasmaz
2024-10-01 10:59:11 +03:00
committed by GitHub
parent 8374a1812d
commit f6fa503cb9
197 changed files with 2949 additions and 7953 deletions

View File

@@ -1,35 +0,0 @@
#!/bin/bash
# Setup
BUILD_DIR=platform-build
mkdir -p $BUILD_DIR
cd $BUILD_DIR
# Create the jniLibs build directory
JNI_DIR=jniLibs
mkdir -p $JNI_DIR
# Set up cargo-ndk
cargo install cargo-ndk
rustup target add \
aarch64-linux-android \
armv7-linux-androideabi \
x86_64-linux-android \
i686-linux-android
# Build the android libraries in the jniLibs directory
cargo ndk -o $JNI_DIR \
--manifest-path ../../../../core/Cargo.toml \
-t aarch64-linux-android \
-t armv7-linux-androideabi \
-t i686-linux-android \
-t x86_64-linux-android \
build "$@"
# Archive the dynamic libs
cd $JNI_DIR
tar -czvf ../android.tar.gz *
cd -
# Cleanup
rm -rf $JNI_DIR

View File

@@ -1,138 +0,0 @@
#!/usr/bin/env dart
import 'dart:io';
import 'package:args/args.dart';
import 'package:cli_script/cli_script.dart';
import 'utils.dart';
const framework = 'breez_sdk_liquid.xcframework';
const frameworkZip = '$framework.zip';
const libName = 'libbreez_sdk_liquid.a';
const iosSimLipo = 'ios-sim-lipo/$libName';
const macLipo = 'mac-lipo/$libName';
const headers = '../breez_sdk_liquid/include';
const buildDir = 'platform-build';
Future<void> mainImpl(List<String> args) async {
final parser = ArgParser()
..addFlag('debug', negatable: false)
..addFlag('local')
..addFlag('ios')
..addOption('profile');
final opts = parser.parse(args);
final observer = Observer();
final String profile, profileArg;
if (opts.wasParsed('profile')) {
profile = opts['profile'];
profileArg = '--profile=$profile';
} else if (opts['debug']) {
profile = 'debug';
profileArg = '--profile=dev';
} else if (opts['local']) {
profile = 'frb';
profileArg = '--profile=frb';
} else {
profile = 'frb-min';
profileArg = '--profile=frb-min';
}
print(' Building profile: $profile');
final List<String> targets;
if (opts['local']) {
targets = [hostTarget];
} else if (opts['ios']) {
targets = const [
'aarch64-apple-ios',
'x86_64-apple-ios',
'aarch64-apple-ios-sim',
];
} else {
targets = const [
'aarch64-apple-ios',
'x86_64-apple-ios',
'aarch64-apple-ios-sim',
'x86_64-apple-darwin',
'aarch64-apple-darwin',
];
}
print('for targets:\n- ${targets.join('\n- ')}');
// -- Begin --
await run('mkdir -p $buildDir');
Directory.current = buildDir;
final outputs = targets.map((target) {
return observer.mark('../../../../target/$target/$profile/$libName');
}).toList();
for (final target in targets) {
print(' Building target $target');
await run('rustup target add $target');
await run('cargo build --package breez-sdk-liquid --target=$target $profileArg');
}
await run('mkdir -p mac-lipo ios-sim-lipo');
if (opts['local']) {
final output = outputs.single;
final isIos = output.contains('ios');
final shouldBuildFramework = observer.hasChanged(output) || !fileExists(frameworkZip);
String lipoOut;
if (shouldBuildFramework) {
lipoOut = isIos ? iosSimLipo : macLipo;
} else {
print('Nothing changed, exiting...');
return;
}
await run('lipo -create -output $lipoOut $output');
await run('xcodebuild -create-xcframework '
'-library $lipoOut -headers $headers '
'-output $framework');
} else {
final armIos = '../../../../target/aarch64-apple-ios/$profile/$libName';
var shouldBuildFramework = !fileExists(frameworkZip) || observer.hasChanged(armIos);
if (!fileExists(iosSimLipo) ||
outputs.where((output) => output.contains('ios')).any(observer.hasChanged)) {
shouldBuildFramework = true;
await run('lipo -create -output $iosSimLipo '
'../../../../target/aarch64-apple-ios-sim/$profile/$libName '
'../../../../target/x86_64-apple-ios/$profile/$libName ');
}
if (!fileExists(macLipo) ||
outputs.where((output) => output.contains('darwin')).any(observer.hasChanged)) {
shouldBuildFramework = true;
await run('lipo -create -output $macLipo '
'../../../../target/aarch64-apple-darwin/$profile/$libName '
'../../../../target/x86_64-apple-darwin/$profile/$libName');
}
if (shouldBuildFramework) {
await run('xcodebuild -create-xcframework '
'-library $iosSimLipo -headers $headers '
'-library $macLipo -headers $headers '
'-library $armIos -headers $headers '
'-output $framework');
}
}
print(' Creating $frameworkZip');
await run('zip -ry $frameworkZip $framework');
print('✅ Done!');
}
void main(List<String> args) {
wrapMain(() async {
try {
await mainImpl(args);
} finally {
await check('rm -rf ios-sim-lipo mac-lipo $framework');
}
});
}

View File

@@ -1,94 +0,0 @@
#!/usr/bin/env dart
import 'dart:io';
import 'package:args/args.dart';
import 'package:cli_script/cli_script.dart';
import 'utils.dart';
const libName = 'breez_sdk_liquid';
const linuxLibName = 'lib$libName.so';
const windowsLibName = '$libName.dll';
const buildDir = 'platform-build';
Future<void> mainImpl(List<String> args) async {
final parser = ArgParser()
..addFlag('debug')
..addFlag('local')
..addOption('profile');
final opts = parser.parse(args);
String profile, profileArg;
if (opts.wasParsed('profile')) {
profile = opts['profile'];
profileArg = '--profile=$profile';
} else if (opts['debug']) {
profile = 'debug';
profileArg = '--profile=dev';
} else if (opts['local']) {
profile = 'frb';
profileArg = '--profile=frb';
} else {
profile = 'frb-min';
profileArg = '--profile=frb-min';
}
// -- Begin --
await run('mkdir -p $buildDir');
Directory.current = buildDir;
await run('cargo install cargo-zigbuild cargo-xwin');
final targets = opts['local'] ? [Targets.host] : Targets.values;
final compilerOpts = opts.rest;
for (final target in targets) {
final triple = target.triple;
final flutterIdentifier = target.flutterIdentifier;
await run('rustup target add $triple');
await run('${target.compiler} --package breez-sdk-liquid --target $triple $profileArg',
args: compilerOpts);
await run('mkdir -p $flutterIdentifier');
await run('cp ../../../../target/$triple/$profile/${target.libName} $flutterIdentifier/');
}
final hasLinux = targets.any((target) => !target.isWindows);
final hasWindows = targets.any((target) => target.isWindows);
await run('tar -czvf other.tar.gz', args: [
if (hasLinux) ...'linux-*'.glob,
if (hasWindows) ...'windows-*'.glob,
]);
}
void main(List<String> args) {
wrapMain(() async {
try {
await mainImpl(args);
} finally {
await check('rm -rf linux-* windows-*');
}
});
}
enum Targets {
linuxArm64('aarch64-unknown-linux-gnu', 'linux-arm64'),
linuxX64('x86_64-unknown-linux-gnu', 'linux-x64');
// TODO: Enable builds for Windows targets
//windowsArm64('aarch64-pc-windows-msvc', 'windows-arm64', isWindows: true),
//windowsX64('x86_64-pc-windows-msvc', 'windows-x64', isWindows: true);
final String triple;
final String flutterIdentifier;
final bool isWindows;
// ignore: unused_element
const Targets(this.triple, this.flutterIdentifier, {this.isWindows = false});
static Targets get host {
final host = hostTarget;
return values.firstWhere((target) => target.triple == host);
}
String get compiler =>
isWindows ? 'cargo xwin build --package breez-sdk-liquid' : 'cargo zigbuild --package breez-sdk-liquid';
String get libName => isWindows ? windowsLibName : linuxLibName;
}

View File

@@ -1,50 +0,0 @@
#!/bin/bash
# ! This script is not being used by Melos and is added for local testing !
# Setup
BUILD_DIR=platform-build
mkdir -p $BUILD_DIR
cd $BUILD_DIR
# Install build dependencies
cargo install cargo-zigbuild
cargo install cargo-xwin
zig_build () {
local TARGET="$1"
local PLATFORM_NAME="$2"
local LIBNAME="$3"
local PROFILE="$4"
rustup target add "$TARGET"
cargo zigbuild --package breez-sdk-liquid --target "$TARGET" --profile $PROFILE
mkdir -p "$PLATFORM_NAME"
cp "../../../../target/$TARGET/$PROFILE/$LIBNAME" "$PLATFORM_NAME/"
}
win_build () {
local TARGET="$1"
local PLATFORM_NAME="$2"
local LIBNAME="$3"
local PROFILE="$4"
rustup target add "$TARGET"
cargo xwin build --package breez-sdk-liquid --target "$TARGET" --profile $PROFILE
mkdir -p "$PLATFORM_NAME"
cp "../../../../target/$TARGET/$PROFILE/$LIBNAME" "$PLATFORM_NAME/"
}
PROFILE=frb-min
# Build all the dynamic libraries
LIBNAME=breez_sdk_liquid
LINUX_LIBNAME=lib$LIBNAME.so
zig_build aarch64-unknown-linux-gnu linux-arm64 $LINUX_LIBNAME $PROFILE
zig_build x86_64-unknown-linux-gnu linux-x64 $LINUX_LIBNAME $PROFILE
WINDOWS_LIBNAME=$LIBNAME.dll
win_build aarch64-pc-windows-msvc windows-arm64 $WINDOWS_LIBNAME $PROFILE
win_build x86_64-pc-windows-msvc windows-x64 $WINDOWS_LIBNAME $PROFILE
# Archive the dynamic libs
tar -czvf other.tar.gz linux-* windows-*
# Cleanup
rm -rf linux-* windows-*

View File

@@ -1,7 +1,7 @@
#!/bin/bash
cd ../..
make android
rm -r ../../packages/flutter/android/src/main/kotlin
make init android
rm -r ../../packages/flutter/android/src/main/kotlin/breez_sdk_liquid*
mkdir -p ../../packages/flutter/android/src/main/jniLibs/arm64-v8a
mkdir -p ../../packages/flutter/android/src/main/jniLibs/armeabi-v7a
mkdir -p ../../packages/flutter/android/src/main/jniLibs/x86

View File

@@ -1,6 +1,9 @@
#!/bin/bash
cd ../..
make bindings-swift
rm -rf ../../packages/flutter/ios/bindings-swift
cp -r langs/swift ../../packages/flutter/ios/bindings-swift
rm -f ../../packages/flutter/ios/bindings-swift/Package.swift
make init bindings-swift
rm -rf ../../packages/flutter/ios/Frameworks/breez_sdk_liquidFFI.xcframework ../../packages/flutter/ios/Sources
rm -rf ../../packages/flutter/ios/Frameworks/breez_sdk_liquidFFI.xcframework ../../packages/flutter/macos/Sources
cp -r langs/swift/breez_sdk_liquidFFI.xcframework ../../packages/flutter/ios/Frameworks/breez_sdk_liquidFFI.xcframework
cp -r langs/swift/breez_sdk_liquidFFI.xcframework ../../packages/flutter/macos/Frameworks/breez_sdk_liquidFFI.xcframework
cp -r langs/swift/Sources ../../packages/flutter/ios/Sources
cp -r langs/swift/Sources ../../packages/flutter/macos/Sources

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart SDK" level="project" />
<orderEntry type="library" name="Dart Packages" level="project" />
</component>
</module>

View File

@@ -1,117 +0,0 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
args:
dependency: "direct main"
description:
name: args
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
url: "https://pub.dev"
source: hosted
version: "2.5.0"
async:
dependency: transitive
description:
name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
version: "2.11.0"
charcode:
dependency: transitive
description:
name: charcode
sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306
url: "https://pub.dev"
source: hosted
version: "1.3.1"
cli_script:
dependency: "direct main"
description:
name: cli_script
sha256: "3463c6e8e57271faaf557eee56cb455522f1ab1ebe618bbfb7454f74fc793967"
url: "https://pub.dev"
source: hosted
version: "0.3.1"
collection:
dependency: transitive
description:
name: collection
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
url: "https://pub.dev"
source: hosted
version: "1.19.0"
file:
dependency: transitive
description:
name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
glob:
dependency: "direct main"
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
meta:
dependency: transitive
description:
name: meta
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
url: "https://pub.dev"
source: hosted
version: "1.16.0"
path:
dependency: transitive
description:
name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev"
source: hosted
version: "1.9.0"
source_span:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.1"
tuple:
dependency: transitive
description:
name: tuple
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
url: "https://pub.dev"
source: hosted
version: "2.0.2"
sdks:
dart: ">=3.4.0 <4.0.0"

View File

@@ -1,15 +0,0 @@
name: scripts
description: Supporting scripts
version: 0.3.4
homepage: https://breez.technology
repository: https://github.com/breez/breez-sdk-liquid
publish_to: none
environment:
sdk: '>=3.4.0 <4.0.0'
dependencies:
args:
cli_script: ^0.3.0
glob: ^2.1.1

View File

@@ -1,52 +0,0 @@
import 'dart:io';
import 'package:glob/glob.dart';
import 'package:glob/list_local_fs.dart';
extension Globber on String {
Iterable<String> get glob sync* {
for (final entity in Glob(this).listSync()) {
yield entity.path;
}
}
}
String get hostTarget {
final res = Process.runSync('rustc', const ['-vV']);
return (res.stdout as String)
.split('\n')
.firstWhere((line) => line.startsWith('host:'))
.split(':')
.last
.trim();
}
bool fileExists(String path) => File(path).existsSync();
class Observer {
var fileMap = <String, DateTime?>{};
String mark(String file) {
final path = Uri.base.resolve(file).toFilePath();
final f = File(path);
fileMap[path] = f.existsSync() ? f.lastModifiedSync() : null;
return path;
}
bool hasChanged(String file) {
final path = Uri.base.resolve(file).toFilePath();
if (!fileMap.containsKey(path)) {
print('❌ Path not marked yet: $path');
return true;
}
final lastModified = fileMap[path];
if (lastModified == null) {
print(' Path nonexistent: $path');
return true;
}
return File(path).lastModifiedSync().isAfter(lastModified);
}
}

View File

@@ -5,20 +5,12 @@ TAG_NAME=`awk '/^version: /{print $2}' $ROOT/packages/flutter/pubspec.yaml`
# iOS & macOS
APPLE_HEADER="version = '$TAG_NAME' # generated; do not edit"
sed -i.bak "1 s/.*/$APPLE_HEADER/" $ROOT/packages/flutter/ios/breez_sdk_liquid.podspec
sed -i.bak "1 s/.*/$APPLE_HEADER/" $ROOT/packages/flutter/ios/flutter_breez_liquid.podspec
sed -i.bak "1 s/.*/$APPLE_HEADER/" $ROOT/packages/flutter/ios/flutter_breez_liquid.podspec.production
sed -i.bak "1 s/.*/$APPLE_HEADER/" $ROOT/packages/flutter/macos/flutter_breez_liquid.podspec
sed -i.bak "1 s/.*/$APPLE_HEADER/" $ROOT/packages/flutter/macos/flutter_breez_liquid.podspec.production
rm $ROOT/packages/flutter/macos/*.bak $ROOT/packages/flutter/ios/*.bak
# CMake platforms (Linux, Windows, and Android)
CMAKE_HEADER="set(TagName \"v$TAG_NAME\") # generated; do not edit"
for CMAKE_PLATFORM in android linux windows
do
sed -i.bak "1 s/.*/$CMAKE_HEADER/" $ROOT/packages/flutter/$CMAKE_PLATFORM/CMakeLists.txt
rm $ROOT/packages/flutter/$CMAKE_PLATFORM/*.bak
done
GRADLE_HEADER="version '$TAG_NAME' \/\/ generated; do not edit"
sed -i.bak "1 s/.*/$GRADLE_HEADER/" $ROOT/packages/flutter/android/build.gradle
sed -i.bak "1 s/.*/$GRADLE_HEADER/" $ROOT/packages/flutter/android/build.gradle.production