Skip to content

Commit

Permalink
WIP - static build
Browse files Browse the repository at this point in the history
  • Loading branch information
za-creature committed Nov 14, 2024
1 parent 23bb243 commit 873e99e
Show file tree
Hide file tree
Showing 8 changed files with 359 additions and 77 deletions.
12 changes: 5 additions & 7 deletions bindings/swift/OuisyncLib/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ let package = Package(
platforms: [.macOS(.v13), .iOS(.v13), .macCatalyst(.v13)],
products: [
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: "OuisyncLib",
targets: ["OuisyncLib"]),
.library(name: "OuisyncLib", targets: ["OuisyncLib"]),
],
dependencies: [
.package(url: "https://github.com/a2/MessagePack.swift.git", from: "4.0.0")
Expand All @@ -20,11 +18,11 @@ let package = Package(
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "OuisyncLib",
dependencies: [.product(name:"MessagePack", package: "MessagePack.swift"), "OuisyncLibFFI"]
dependencies: [.product(name:"MessagePack",
package: "MessagePack.swift"),
"OuisyncLibFFI"]
),
.target(name: "OuisyncLibFFI", dependencies: ["OuisyncDyLibBuilder"]),
.plugin(name: "OuisyncDyLibBuilder", capability: .buildTool()),

.target(name: "OuisyncLibFFI", path: "Sources/OuisyncLibFFI"),
.testTarget(
name: "OuisyncLibTests",
dependencies: ["OuisyncLib"]),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Created by Peter Jankuliak on 26/07/2024.
//

// A package plugin which builds the libouisync_ffi.dylib library and includes it in the package.
// A package plugin which builds the libouisync_ffi.a library and includes it in the package.
// https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/Plugins.md
//
// TODO: Right now it creates only Debug version of the library and only for the current architecture.
Expand All @@ -19,20 +19,14 @@ import PackagePlugin
@main
struct OuisyncDyLibBuilder: BuildToolPlugin {
func createBuildCommands(context: PackagePlugin.PluginContext, target: PackagePlugin.Target) async throws -> [PackagePlugin.Command] {
let workDir = context.pluginWorkDirectory
let dylibName = "libouisync_ffi.dylib"
let dylibPath = workDir.appending("debug").appending(dylibName)
let cargoPath = shell("which cargo").trimmingCharacters(in: .whitespacesAndNewlines)
let inputFiles = findInputFiles()

return [
[
.buildCommand(
displayName: "Build Ouisync FFI .dylib",
executable: Path(cargoPath),
arguments: ["build", "-p", "ouisync-ffi", "--target-dir", workDir],
displayName: "Build Ouisync FFI .a",
executable: Path(shell("which cargo").trimmingCharacters(in: .whitespacesAndNewlines)),
arguments: ["build", "-p", "ouisync-ffi", "--target-dir", context.pluginWorkDirectory],
environment: [:],
inputFiles: inputFiles.map { Path($0) },
outputFiles: [ dylibPath ])
inputFiles: findInputFiles().map { Path($0) },
outputFiles: [context.pluginWorkDirectory.appending("debug").appending("libouisync_ffi.a")])
]
}
}
Expand Down
26 changes: 13 additions & 13 deletions bindings/swift/OuisyncLib/Sources/OuisyncLib/OuisyncClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Foundation
import OuisyncLibFFI

public class OuisyncClient {
var clientHandle: OuisyncClientHandle
var clientHandle: SessionHandle
let ffi: OuisyncFFI
public var onReceiveFromBackend: OuisyncOnReceiveFromBackend? = nil

Expand All @@ -18,26 +18,26 @@ public class OuisyncClient {
// create the callback, which is in turn needed to create the proper sessionHandle.
let client = OuisyncClient(0, ffi)

let callback: FFICallback = { context, dataPointer, size in
let logTag = "ouisync-backend"
let result = ffi.ffiSessionCreate(ffi.sessionKindShared, configPath, logPath, logTag,
.init(mutating: OuisyncFFI.toUnretainedPtr(obj: client))) {
context, dataPointer, size in
let client: OuisyncClient = OuisyncFFI.fromUnretainedPtr(ptr: context!)
guard let onReceive = client.onReceiveFromBackend else {
fatalError("OuisyncClient has no onReceive handler set")
}
onReceive(Array(UnsafeBufferPointer(start: dataPointer, count: Int(exactly: size)!)))
}

let logTag = "ouisync-backend"
let result = ffi.ffiSessionCreate(ffi.sessionKindShared, configPath, logPath, logTag, OuisyncFFI.toUnretainedPtr(obj: client), callback);

if result.errorCode != 0 {
throw SessionCreateError("Failed to create session, code:\(result.errorCode), message:\(result.errorMessage!)")
if result.error_code != 0 {
throw SessionCreateError("Failed to create session, code:\(result.error_code), message:\(result.error_message!)")
}

client.clientHandle = result.clientHandle
client.clientHandle = result.session
return client
}

fileprivate init(_ clientHandle: OuisyncClientHandle, _ ffi: OuisyncFFI) {
fileprivate init(_ clientHandle: SessionHandle, _ ffi: OuisyncFFI) {
self.clientHandle = clientHandle
self.ffi = ffi
}
Expand All @@ -46,7 +46,7 @@ public class OuisyncClient {
let count = data.count;
data.withUnsafeBufferPointer({ maybePointer in
if let pointer = maybePointer.baseAddress {
ffi.ffiSessionChannelSend(clientHandle, pointer, UInt64(count))
ffi.ffiSessionChannelSend(clientHandle, .init(mutating: pointer), UInt64(count))
}
})
}
Expand All @@ -55,9 +55,9 @@ public class OuisyncClient {
typealias Continuation = CheckedContinuation<Void, Never>

class Context {
let clientHandle: OuisyncClientHandle
let clientHandle: SessionHandle
let continuation: Continuation
init(_ clientHandle: OuisyncClientHandle, _ continuation: Continuation) {
init(_ clientHandle: SessionHandle, _ continuation: Continuation) {
self.clientHandle = clientHandle
self.continuation = continuation
}
Expand All @@ -69,7 +69,7 @@ public class OuisyncClient {
let context: Context = OuisyncFFI.fromRetainedPtr(ptr: context!)
context.continuation.resume()
}
ffi.ffiSessionClose(clientHandle, context, callback)
ffi.ffiSessionClose(clientHandle, .init(mutating: context), callback)
})
}
}
Expand Down
52 changes: 32 additions & 20 deletions bindings/swift/OuisyncLib/Sources/OuisyncLib/OuisyncFFI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,20 @@
import Foundation
import OuisyncLibFFI

typealias FFISessionKind = UInt8
typealias FFIContext = UnsafeRawPointer
typealias FFICallback = @convention(c) (FFIContext?, UnsafePointer<UInt8>, CUnsignedLongLong) -> Void;
typealias FFISessionCreate = @convention(c) (FFISessionKind, UnsafePointer<UInt8>, UnsafePointer<UInt8>, UnsafePointer<UInt8>, UnsafeRawPointer?, FFICallback) -> OuisyncSessionCreateResult;
typealias FFISessionGrab = @convention(c) (UnsafeRawPointer?, FFICallback) -> OuisyncSessionCreateResult;
typealias FFISessionClose = @convention(c) (OuisyncClientHandle, FFIContext?, FFICallback) -> Void;
typealias FFISessionChannelSend = @convention(c) (OuisyncClientHandle, UnsafeRawPointer, UInt64) -> Void;

/* TODO: ⬇️

Since we're now linking statically and both rust-cbindgen and swift do a reasonable job at guessing
the intended types, I don't expect these types to ever make it to the main branch because this file
will most likely go away. For now they are kept to avoid touching too much code in a single commit.
*/
typealias FFISessionKind = UInt8 // swift gets confused here and imports a UInt32 enum as well as a UInt8 typealias
typealias FFIContext = UnsafeMutableRawPointer // exported as `* mut ()` in rust so this is correct, annoyingly
typealias FFICallback = @convention(c) (FFIContext?, UnsafePointer<UInt8>?, UInt64) -> Void;
typealias FFISessionCreate = @convention(c) (FFISessionKind, UnsafePointer<Int8>?, UnsafePointer<Int8>?, UnsafePointer<Int8>?, FFIContext?, FFICallback?) -> SessionCreateResult;
typealias FFISessionGrab = @convention(c) (FFIContext?, FFICallback?) -> SessionCreateResult;
typealias FFISessionClose = @convention(c) (SessionHandle, FFIContext?, FFICallback?) -> Void;
typealias FFISessionChannelSend = @convention(c) (SessionHandle, UnsafeMutablePointer<UInt8>?, UInt64) -> Void;

class SessionCreateError : Error, CustomStringConvertible {
let message: String
Expand All @@ -23,7 +30,7 @@ class SessionCreateError : Error, CustomStringConvertible {
}

public class OuisyncFFI {
let handle: UnsafeMutableRawPointer
// let handle: UnsafeMutableRawPointer
let ffiSessionGrab: FFISessionGrab
let ffiSessionCreate: FFISessionCreate
let ffiSessionChannelSend: FFISessionChannelSend
Expand All @@ -32,27 +39,32 @@ public class OuisyncFFI {

public init() {
// The .dylib is created using the OuisyncDyLibBuilder package plugin in this Swift package.
let libraryName = "libouisync_ffi.dylib"
let resourcePath = Bundle.main.resourcePath! + "/OuisyncLib_OuisyncLibFFI.bundle/Contents/Resources"
handle = dlopen("\(resourcePath)/\(libraryName)", RTLD_NOW)!

ffiSessionGrab = unsafeBitCast(dlsym(handle, "session_grab"), to: FFISessionGrab.self)
ffiSessionChannelSend = unsafeBitCast(dlsym(handle, "session_channel_send"), to: FFISessionChannelSend.self)
ffiSessionClose = unsafeBitCast(dlsym(handle, "session_close"), to: FFISessionClose.self)
ffiSessionCreate = unsafeBitCast(dlsym(handle, "session_create"), to: FFISessionCreate.self)
// let libraryName = "libouisync_ffi.dylib"
// let resourcePath = Bundle.main.resourcePath! + "/OuisyncLib_OuisyncLibFFI.bundle/Contents/Resources"
// handle = dlopen("\(resourcePath)/\(libraryName)", RTLD_NOW)!

ffiSessionGrab = session_grab
ffiSessionChannelSend = session_channel_send
ffiSessionClose = session_close
ffiSessionCreate = session_create

//ffiSessionGrab = unsafeBitCast(dlsym(handle, "session_grab"), to: FFISessionGrab.self)
//ffiSessionChannelSend = unsafeBitCast(dlsym(handle, "session_channel_send"), to: FFISessionChannelSend.self)
//ffiSessionClose = unsafeBitCast(dlsym(handle, "session_close"), to: FFISessionClose.self)
//ffiSessionCreate = unsafeBitCast(dlsym(handle, "session_create"), to: FFISessionCreate.self)
}

// Blocks until Dart creates a session, then returns it.
func waitForSession(_ context: UnsafeRawPointer, _ callback: FFICallback) async throws -> OuisyncClientHandle {
func waitForSession(_ context: FFIContext, _ callback: FFICallback) async throws -> SessionHandle {
// TODO: Might be worth change the ffi function to call a callback when the session becomes created instead of bussy sleeping.
var elapsed: UInt64 = 0;
while true {
let result = ffiSessionGrab(context, callback)
if result.errorCode == 0 {
if result.error_code == 0 {
NSLog("😀 Got Ouisync session");
return result.clientHandle
return result.session
}
NSLog("🤨 Ouisync session not yet ready. Code: \(result.errorCode) Message:\(String(cString: result.errorMessage!))");
NSLog("🤨 Ouisync session not yet ready. Code: \(result.error_code) Message:\(String(cString: result.error_message!))");

let millisecond: UInt64 = 1_000_000
let second: UInt64 = 1000 * millisecond
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

import Foundation
import MessagePack
import OuisyncLibFFI

public class OuisyncSession {
let configsPath: String
Expand Down

This file was deleted.

Loading

0 comments on commit 873e99e

Please sign in to comment.