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 <swift-users@swift.org> 
> 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
> swift-users@swift.org
> https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Reply via email to