The way that I have done this in the past is pass a protocol as an unsafe
pointer to an exposed entry point:
```swift
let entryPoint = dlsym(handle, “initializePlugin”)
guard entryPoint != nil else {
fatalError("missing plugin entry point: \(pluginPath)")
}
typealias PluginInitializationFunc = @convention(c)
(UnsafeRawPointer) -> ()
let f = unsafeBitCast(entryPoint, to: PluginInitializationFunc.self)
f(Unmanaged.passUnretained(self).toOpaque())
```
and then in the plugin convert back to the appropriate type:
```
@_cdecl("initializePlugin")
public func initializePlugin(_ ptr: UnsafeRawPointer) {
let manager = Unmanaged<PluginManager>.fromOpaque(ptr).takeUnretainedValue()
```
HTH,
- Daniel
> On Oct 4, 2017, at 11:02 AM, Ján Kosa via swift-users <[email protected]>
> wrote:
>
> Hello folks,
>
> I have been toying with dynamic libraries, trying to implement plugin
> functionality. I was able to get to the point where I can call simple
> function in loaded library, but I am having troubles starting more
> sophisticated communication channel.
>
> There are 3 projects
> - PluginConsumer is an app that loads plugin libraries
> - MyPlugin is a plugin implementation, output is dynamic library that
> PluginConsumer loads
> - PluginInterface is common interface that both MyPlugin and PluginConsumer
> use, so that they know how to communicate
>
> My first idea was to have PluginInterface be a simple SPM project with single
> file where the bare-bones PluginInterface class would be:
>
>
> open class PluginInterface {
>
> open func sayHi()
>
> }
>
>
>
> Package.swift file:
>
>
>
> // swift-tools-version:4.0
>
> import PackageDescription
>
> let package = Package(
>
> name: "PluginInterface",
>
> products: [ .library(name: "PluginInterface", type: .dynamic, targets:
> ["PluginInterface"]) ],
>
> targets: [ .target(name: "PluginInterface") ]
>
>
> )
>
>
>
>
>
> UserPlugin is also very simple project containing only one file:
>
>
>
> public func getPlugin() -> AnyObject {
>
> return MyPlugin()
>
>
> }
>
>
>
> class MyPlugin: PluginInterface {
>
> override func sayHi() {
>
> print("Hi from my plugin")
>
> }
>
> }
>
> Package.swift:
>
>
>
> // swift-tools-version:4.0
>
> import PackageDescription
>
> let package = Package(
>
> name: "MyPlugin",
>
> products: [ .library(name: "MyPlugin", type: .dynamic, targets:
> ["MyPlugin"]) ],
>
> dependencies: [ .package(url: "url_to_PluginInterface", from: "0.0.0"), ],
>
> targets: [
>
> .target(name: "PluginInterface", dependencies: ["PluginInterface"]),
>
> .target(name: "MyPlugin", dependencies: ["PluginInterface"]),
>
> ]
>
>
> )
>
>
>
> The PluginConsumer is bit more complicated, but here is relevant part (lib
> loading and function calling):
>
>
>
> typealias InitFunction = @convention(c) () -> AnyObject
>
>
>
> let openRes = dlopen(pathToLib, RTLD_NOW|RTLD_LOCAL)
>
> if openRes != nil {
>
> defer {
>
> dlclose(openRes)
>
> }
>
> let symbolName = "mangled_symbol_name"
>
> let sym = dlsym(openRes, symbolName)
>
>
>
> if sym != nil {
>
> let f: InitFunction = unsafeBitCast(sym, to: InitFunction.self)
>
> let plugin = f() as? PluginInterface
>
> }
>
>
> }
>
> Package.swift file:
>
> // swift-tools-version:4.0
>
> import PackageDescription
>
> let package = Package(
>
> name: "PluginConsumer",
>
> dependencies: [ .package(url: "path_to_plugin_interface", from: "0.0.0")
> ],
>
> targets: [ .target(name: "PluginConsumer", dependencies:
> ["PluginConsumer"]) ]
>
>
> )
>
>
>
> This all compiles nicely, MyPlugin project creates dylib file that executable
> created by PluginConsumer can load, but the problem is with following line:
>
> let plugin = f() as? PluginInterface
>
> Type of the plugin is MyPlugin, but from the consumer's view, it doesn't
> inherit from PluginInterface so I can't call sayHi() method. I assume this is
> because there is no relation between PluginInterface class that compiler uses
> for MyPlugin project one that it uses for PluginConsumer project. After
> library is loaded, they are two completely different classes that happen to
> share same name. Is my assumption correct and how do I go about fixing it?
>
> I had an idea I could make PluginInterface emit dynamic library that would be
> dynamically linked by both MyPlugin and PluginConsumer, thus making them
> share same PluginInterface class, but I can't figure out how to do that (or
> if it's right way of doing this).
>
>
>
> Any help appreciated :)
>
> Lope
>
> _______________________________________________
> swift-users mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-users
_______________________________________________
swift-users mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-users