<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">The way that I have done this in the past is pass a protocol as an unsafe pointer to an exposed entry point:<div class="">```swift</div><div class=""> let entryPoint = dlsym(handle, “initializePlugin”)</div><div class=""> guard entryPoint != nil else {</div><div class=""> fatalError("missing plugin entry point: \(pluginPath)")</div><div class=""> }</div><div class=""> typealias PluginInitializationFunc = @convention(c) (UnsafeRawPointer) -> ()</div><div class=""> let f = unsafeBitCast(entryPoint, to: PluginInitializationFunc.self)</div><div class=""> f(Unmanaged.passUnretained(self).toOpaque())</div><div class="">```</div><div class=""><br class=""></div><div class="">and then in the plugin convert back to the appropriate type:</div><div class=""><br class=""></div><div class="">```</div><div class=""><div class="">@_cdecl("initializePlugin")</div><div class="">public func initializePlugin(_ ptr: UnsafeRawPointer) {</div><div class=""> let manager = Unmanaged<PluginManager>.fromOpaque(ptr).takeUnretainedValue()</div><div class="">```</div><div class=""><br class=""></div><div class="">HTH,</div><div class=""> - Daniel</div><div><br class=""><blockquote type="cite" class=""><div class="">On Oct 4, 2017, at 11:02 AM, Ján Kosa via swift-users <<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">Hello folks,<div class=""><br class=""></div><div class="">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.</div><div class=""><br class=""></div><div class="">There are 3 projects<br class=""></div><div class="">- PluginConsumer is an app that loads plugin libraries </div><div class="">- MyPlugin is a plugin implementation, output is dynamic library that PluginConsumer loads</div><div class="">- PluginInterface is common interface that both MyPlugin and PluginConsumer use, so that they know how to communicate</div><div class=""><br class=""></div><div class="">My first idea was to have PluginInterface be a simple SPM project with single file where the bare-bones PluginInterface class would be:</div><div class=""><p class="gmail-p1"><span class="gmail-s1"><br class=""></span></p><p class="gmail-p1"><span class="gmail-s1">open</span> <span class="gmail-s1">class</span> PluginInterface {</p><p class="gmail-p2"> open func sayHi()</p><p class="gmail-p1">}</p><p class="gmail-p1"><br class=""></p><p class="gmail-p1">Package.swift file:</p><p class="gmail-p1"><br class=""></p><p class="gmail-p2">// swift-tools-version:4.0</p><p class="gmail-p3"><span class="gmail-s1">import</span> PackageDescription</p><p class="gmail-p3"><span class="gmail-s1">let</span> package = Package(</p><p class="gmail-p4"><span class="gmail-s2"><span class="gmail-Apple-tab-span"></span> name: </span>"PluginInterface"<span class="gmail-s2">,</span></p><p class="gmail-p3"><span class="gmail-Apple-tab-span"></span> products: [ .library(name: <span class="gmail-s3">"PluginInterface"</span>, type: .dynamic, targets: [<span class="gmail-s3">"PluginInterface"</span>]) ],</p><p class="gmail-p3"><span class="gmail-Apple-tab-span"></span> targets: [ <span class="gmail-s2">.target(name: </span>"PluginInterface"<span class="gmail-s2">) </span>]</p><div class="">
<br class="webkit-block-placeholder"></div><p class="gmail-p3">)</p><p class="gmail-p3"><br class=""></p><p class="gmail-p3"><br class=""></p><p class="gmail-p1">UserPlugin is also very simple project containing only one file:</p><p class="gmail-p1"><br class=""></p><p class="gmail-p1"><span class="gmail-s1">public</span> <span class="gmail-s1">func</span> getPlugin() -> <span class="gmail-s2">AnyObject</span> {</p><p class="gmail-p2"><span class="gmail-s3"><span class="gmail-Apple-tab-span"></span></span><span class="gmail-s1"> return</span><span class="gmail-s3"> </span>MyPlugin<span class="gmail-s3">()</span></p><div class="">
<br class="webkit-block-placeholder"></div><p class="gmail-p1">}</p><p class="gmail-p1"><br class=""></p><p class="gmail-p1">class MyPlugin: PluginInterface {</p><p class="gmail-p1"> override func sayHi() {</p><p class="gmail-p1"> print("Hi from my plugin")</p><p class="gmail-p1"> }</p><p class="gmail-p1">}</p><p class="gmail-p1">Package.swift:</p><p class="gmail-p1"><br class=""></p><p class="gmail-p2">// swift-tools-version:4.0</p><p class="gmail-p3"><span class="gmail-s1">import</span> PackageDescription</p><p class="gmail-p3"><span class="gmail-s1">let</span> package = <span class="gmail-s2">Package</span>(</p><p class="gmail-p4"><span class="gmail-s3"><span class="gmail-Apple-tab-span"></span> name: </span>"MyPlugin"<span class="gmail-s3">,</span></p><p class="gmail-p3"><span class="gmail-Apple-tab-span"></span> products: [ .<span class="gmail-s4">library</span>(name: <span class="gmail-s5">"MyPlugin"</span>, type: .<span class="gmail-s4">dynamic</span>, targets: [<span class="gmail-s5">"MyPlugin"</span>]) ],</p><p class="gmail-p3"><span class="gmail-Apple-tab-span"></span> dependencies: [ .<span class="gmail-s4">package</span>(url: <span class="gmail-s5">"url_to_PluginInterface"</span>, from: <span class="gmail-s5">"0.0.0"</span>), ],</p><p class="gmail-p3"><span class="gmail-Apple-tab-span"></span> targets: [</p><p class="gmail-p4"><span class="gmail-s3"><span class="gmail-Apple-tab-span"></span><span class="gmail-Apple-tab-span"></span> .</span><span class="gmail-s4">target</span><span class="gmail-s3">(name: </span>"PluginInterface"<span class="gmail-s3">, dependencies: [</span>"PluginInterface"<span class="gmail-s3">]),</span></p><p class="gmail-p3"><span class="gmail-Apple-tab-span"></span><span class="gmail-Apple-tab-span"></span> .<span class="gmail-s4">target</span>(name: <span class="gmail-s5">"MyPlugin"</span>, dependencies: [<span class="gmail-s5">"PluginInterface"</span>]),</p><p class="gmail-p3"><span class="gmail-Apple-tab-span"></span><span class="gmail-Apple-tab-span"></span> ]</p><div class="">
<br class="webkit-block-placeholder"></div><p class="gmail-p3">)</p><p class="gmail-p1"><br class=""></p><p class="gmail-p1">The PluginConsumer is bit more complicated, but here is relevant part (lib loading and function calling):</p><p class="gmail-p1"><br class=""></p><p class="gmail-p1"><span class="gmail-s1">typealias</span> <span class="gmail-s2">I</span>nitFunction = <span class="gmail-s1">@convention</span>(c) () -> <span class="gmail-s3">AnyObject</span></p><p class="gmail-p2"><br class=""></p><p class="gmail-p1"><span class="gmail-s1">let</span> openRes = <span class="gmail-s4">dlopen</span>(<span class="gmail-s2">p</span>athToLib, <span class="gmail-s3">RTLD_NOW</span>|<span class="gmail-s3">RTLD_LOCAL</span>)</p><p class="gmail-p3"><span class="gmail-s5">i</span><span class="gmail-s1">f</span><span class="gmail-s6"> </span>openRes<span class="gmail-s6"> != </span><span class="gmail-s1">nil</span><span class="gmail-s6"> {</span></p><p class="gmail-p4"><span class="gmail-s6"><span class="gmail-Apple-tab-span"></span></span> defer<span class="gmail-s6"> {</span></p><p class="gmail-p5"><span class="gmail-s6"><span class="gmail-Apple-tab-span"></span><span class="gmail-Apple-tab-span"></span></span> dlclose<span class="gmail-s6">(</span><span class="gmail-s7">openRes</span><span class="gmail-s6">)</span></p><p class="gmail-p1"><span class="gmail-Apple-tab-span"></span> }</p><p class="gmail-p6"><span class="gmail-s1"> let</span><span class="gmail-s6"> symbolName = </span>"mangled_symbol_name"<br class=""></p><p class="gmail-p1"><span class="gmail-Apple-tab-span"></span><span class="gmail-s1"> let</span> sym = <span class="gmail-s4">dlsym</span>(<span class="gmail-s7">openRes</span>, symbolName)</p><p class="gmail-p2"><br class=""></p><p class="gmail-p1"><span class="gmail-Apple-tab-span"></span><span class="gmail-s1"> if</span> sym != <span class="gmail-s1">nil</span> {</p><p class="gmail-p3"><span class="gmail-s6"><span class="gmail-Apple-tab-span"></span><span class="gmail-Apple-tab-span"></span></span><span class="gmail-s1"> let</span><span class="gmail-s6"> f: </span>InitFunction<span class="gmail-s6"> = </span><span class="gmail-s4">unsafeBitCast</span><span class="gmail-s6">(sym, to: </span>InitFunction<span class="gmail-s6">.</span><span class="gmail-s1">self</span><span class="gmail-s6">)</span></p><p class="gmail-p1"><span class="gmail-Apple-tab-span"></span><span class="gmail-Apple-tab-span"></span><span class="gmail-s1"> let</span> plugin = f() as? PluginInterface</p><p class="gmail-p1"><span class="gmail-Apple-tab-span"></span> }</p><div class="">
<br class="webkit-block-placeholder"></div><p class="gmail-p1">}</p><p class="gmail-p1">Package.swift file:</p><p class="gmail-p1">// swift-tools-version:4.0</p><p class="gmail-p3"><span class="gmail-s1">import</span> PackageDescription</p><p class="gmail-p3"><span class="gmail-s1">let</span> package = <span class="gmail-s2">Package</span>(</p><p class="gmail-p3"><span class="gmail-Apple-tab-span"></span> name: <span class="gmail-s3">"PluginConsumer"</span>,</p><p class="gmail-p3"><span class="gmail-Apple-tab-span"></span> dependencies: [ <span class="gmail-s4">.</span><span class="gmail-s5">package</span><span class="gmail-s4">(url: </span>"path_to_plugin_interface"<span class="gmail-s4">, from: </span>"0.0.0"<span class="gmail-s4">) </span>],</p><p class="gmail-p3"><span class="gmail-Apple-tab-span"></span> targets: [ <span class="gmail-s4">.</span><span class="gmail-s5">target</span><span class="gmail-s4">(name: </span>"PluginConsumer"<span class="gmail-s4">, dependencies: [</span>"PluginConsumer"<span class="gmail-s4">]) </span>]</p><div class="">
<br class="webkit-block-placeholder"></div><p class="gmail-p3">)</p><p class="gmail-p3"><br class=""></p><p class="gmail-p3">This all compiles nicely, MyPlugin project creates dylib file that executable created by PluginConsumer can load, but the problem is with following line:</p><p class="gmail-p3"><span class="gmail-s1">let</span> plugin = f() as? PluginInterface<br class=""></p><p class="gmail-p3">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?</p><p class="gmail-p3">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).<br class=""></p><p class="gmail-p3"><br class=""></p><p class="gmail-p3">Any help appreciated :)</p><p class="gmail-p3">Lope</p></div></div>
_______________________________________________<br class="">swift-users mailing list<br class=""><a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-users<br class=""></div></blockquote></div><br class=""></div></body></html>