Sunday, April 2, 2023
Learning Code
  • Home
  • JavaScript
  • Java
  • Python
  • Swift
  • C++
  • C#
No Result
View All Result
  • Home
  • JavaScript
  • Java
  • Python
  • Swift
  • C++
  • C#
No Result
View All Result
Learning Code
No Result
View All Result
Home Swift

Building and loading dynamic libraries at runtime in Swift

learningcode_x1mckf by learningcode_x1mckf
September 22, 2022
in Swift
0
Building and loading dynamic libraries at runtime in Swift
74
SHARES
1.2k
VIEWS
Share on FacebookShare on Twitter


2020/05/20

Discover ways to create a plugin system utilizing dynamic libraries and the ability of Swift, aka. modular frameworks on the server-side.

Swift

Why ought to we make a plugin system?

Within the modules and hooks article I used to be writing about how modules (plugins) can work collectively through the use of varied invocation factors and hooks. The one drawback with that strategy is that you could’t actually activate or off modules on-the-fly, since we often construct our apps in a static means.

An excellent plugin system ought to allow us to alter the conduct of our code at runtime. WordPress plugins are extraordinarily profitable, as a result of you possibly can add additional performance to the CMS with out recompiling or altering the core. Outdoors the Apple ecosystem, there’s a large world that might make the most of this idea. Sure, I’m speaking about Swift on the server and backend functions.


My thought right here is to construct an open-source modular CMS that may be quick, protected and extensible by means of plugins. Thankfully now we now have this superb type-safe programming language that we are able to use. Swift is quick and dependable, it’s the excellent selection for constructing backend apps on the long run. ✅


On this article I want to present you a methods to construct a dynamic plugin system. The entire idea relies on Lopdo‘s GitHub repositories, he did fairly an incredible job implementing it. Thanks very a lot for exhibiting me methods to use dlopen and different comparable capabilities. 🙏



The magic of dynamic linking

Handmade iOS frameworks are often bundled with the applying itself, you possibly can study just about everything about a framework if you recognize some command line instruments. This time we’re solely going to give attention to static and dynamic linking. By default Swift package dependencies are linked statically into your utility, however you possibly can change this for those who outline a dynamic library product.

First we’re going to create a shared plugin interface containing the plugin API as a protocol.



import PackageDescription

let package deal = Package deal(
    identify: "PluginInterface",
    merchandise: [
        .library(name: "PluginInterface", type: .dynamic, targets: ["PluginInterface"]),
    ],
    targets: [
        .target(name: "PluginInterface", dependencies: []),
    ]
)

This dynamic PluginInterface package deal can produce a .dylib or .so file, quickly there might be a .dll model as properly, primarily based on the working system. All of the code bundled into this dynamic library might be shared between different functions. Let’s make a easy protocol.


public protocol PluginInterface 

    func foo() -> String


Since we’re going to load the plugin dynamically we are going to want one thing like a builder to assemble the specified object. We will use a brand new summary class for this function.


open class PluginBuilder 
    
    public init() 

    open func construct() -> PluginInterface 
        fatalError("You must override this methodology.")
    

That is our dynamic plugin interface library, be at liberty to push this to a distant repository.



Constructing a dynamic plugin

For the sake of simplicity we’ll construct a module known as PluginA, that is the manifest file:


import PackageDescription

let package deal = Package deal(
    identify: "PluginA",
    merchandise: [
        .library(name: "PluginA", type: .dynamic, targets: ["PluginA"]),
    ],
    dependencies: [
        .package(url: "path/to/the/PluginInterface/repository", from: "1.0.0"),
    ],
    targets: [
        .target(name: "PluginA", dependencies: [
            .product(name: "PluginInterface", package: "PluginInterface")
        ]),
    ]
)

The plugin implementation will after all implement the PluginInterface protocol. You’ll be able to prolong this protocol primarily based in your wants, you can too use different frameworks as dependencies.

import PluginInterface

struct PluginA: PluginInterface 

    func foo() -> String 
        return "A"
    

Now we have to subclass the PluginBuilder class and return our plugin implementation. We’re going to use the @_cdecl attributed create operate to entry our plugin builder from the core app. This Swift attribute tells the compiler to save lots of our operate beneath the “createPlugin” image identify.

import PluginInterface

@_cdecl("createPlugin")
public func createPlugin() -> UnsafeMutableRawPointer 
    return Unmanaged.passRetained(PluginABuilder()).toOpaque()


remaining class PluginABuilder: PluginBuilder 

    override func construct() -> PluginInterface 
        PluginA()
    

We will construct the plugin utilizing the command line, simply run swift construct within the undertaking folder. Now you could find the dylib file beneath the binary path, be at liberty to run swift construct --show-bin-path, it will output the required folder. We’ll want each .dylib information for later use.



Loading the plugin at runtime

The core utility may even use the plugin interface as a dependency.


import PackageDescription

let package deal = Package deal(
    identify: "CoreApp",
    dependencies: [
        .package(url: "path/to/the/PluginInterface/repository", from: "1.0.0"),
    ],
    targets: [
        .target(name: "CoreApp", dependencies: [
            .product(name: "PluginInterface", package: "PluginInterface")
        ]),
    ]
)

That is an executable goal, so we are able to place the loading logic to the important.swift file.

import Basis
import PluginInterface

typealias InitFunction = @conference(c) () -> UnsafeMutableRawPointer

func plugin(at path: String) -> PluginInterface RTLD_LOCAL)
    if openRes != nil 
        defer 
            dlclose(openRes)
        

        let symbolName = "createPlugin"
        let sym = dlsym(openRes, symbolName)

        if sym != nil 
            let f: InitFunction = unsafeBitCast(sym, to: InitFunction.self)
            let pluginPointer = f()
            let builder = Unmanaged<PluginBuilder>.fromOpaque(pluginPointer).takeRetainedValue()
            return builder.construct()
        
        else 
            fatalError("error loading lib: image (symbolName) not discovered, path: (path)")
        
    
    else 
        if let err = dlerror() 
            fatalError("error opening lib: (String(format: "%s", err)), path: (path)")
        
        else 
            fatalError("error opening lib: unknown error, path: (path)")
        
    


let myPlugin = plugin(at: "path/to/my/plugin/libPluginA.dylib")
let a = myPlugin.foo()
print(a)

We will use the dlopen operate to open the dynamic library file, then we try to get the createPlugin image utilizing the dlsym methodology. If we now have a pointer we nonetheless must solid that into a sound PluginBuilder object, then we are able to name the construct methodology and return the plugin interface.



Working the app

You might also like

Swift Against Humanity – Hacking with Swift

Introducing MotionBar – the Animated Tab Bar Library

Introducing – AI Utils for macOS

Now for those who attempt to run this utility utilizing Xcode you will get a warning like this:

Class _TtC15PluginInterface13PluginBuilder is applied in each…
One of many two might be used. Which one is undefined.

That is associated to an outdated bug, however fortuitously that’s already resolved. This time Xcode is the dangerous man, since it’s making an attempt to hyperlink the whole lot as a static dependency. Now for those who construct the applying by means of the command line (swift construct) and place the next information in the identical folder:

  • CoreApp
  • libPluginA.dylib
  • libPluginInterface.dylib

You’ll be able to run the applying ./CoreApp wihtout additional points. The app will print out A with out the warning message, because the Swift package deal supervisor is recognizing that you simply want to hyperlink the libPluginInterface framework as a dynamic framework, so it will not be embedded into the applying binary. After all you need to arrange the appropriate plugin path within the core utility.




Source link

Share30Tweet19
learningcode_x1mckf

learningcode_x1mckf

Recommended For You

Swift Against Humanity – Hacking with Swift

by learningcode_x1mckf
April 1, 2023
0
Swift Against Humanity – Hacking with Swift

So that you suppose you already know Swift? Assume once more! Recent from the success of our audiobook launch, Laboratoires TwoStraws is again with an all-new card sport...

Read more

Introducing MotionBar – the Animated Tab Bar Library

by learningcode_x1mckf
March 31, 2023
0
Introducing MotionBar – the Animated Tab Bar Library

In an earlier tutorial, we shared find out how to create a customized tab bar view utilizing SwiftUI to exchange the usual tab bar. If you happen to’ve...

Read more

Introducing – AI Utils for macOS

by learningcode_x1mckf
March 24, 2023
0
Introducing – AI Utils for macOS

⚠️ REQUIRES a FREE OpenAI API key. You will get one utilizing this hyperlink. ⚠️ Improve your productiveness with our AI powered utility application. - accessible...

Read more

Encoding and decoding data using the Hummingbird framework

by learningcode_x1mckf
March 22, 2023
0
Encoding and decoding data using the Hummingbird framework

HTTP is all about sending and receiving information over the community. Initially it was solely utilized to switch HTML paperwork, however these days we use HTTP to switch...

Read more

Hummingbird routing and requests – The.Swift.Dev.

by learningcode_x1mckf
March 17, 2023
0
Hummingbird routing and requests – The.Swift.Dev.

Routing on the server facet means the server goes to ship a response primarily based on the URL path that the consumer referred to as when firing up...

Read more
Next Post
Language I/O Runs React-Based Javascript with Java Backend

Language I/O Runs React-Based Javascript with Java Backend

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Related News

Google expands open source bounties, will soon support Javascript fuzzing too – ZDNet

Senior Java Developer – Centurion/ Hybrid – R1200k PA at e-Merge … – IT-Online

February 4, 2023
Google expands open source bounties, will soon support Javascript fuzzing too – ZDNet

New Visual Studio 17.5 preview adds a spell checker for C#, C++, and Markdown files – Neowin

February 5, 2023
Different server for Google API – JavaScript – SitePoint Forums

JavaScript Scoreboard – add sum of input fields into total result – JavaScript – SitePoint Forums

January 30, 2023

Browse by Category

  • C#
  • C++
  • Java
  • JavaScript
  • Python
  • Swift

RECENT POSTS

  • So why did they decide to call it Java? – InfoWorld
  • Senior Java Developer – IT-Online
  • 4 Packages for Working With Date and Time in JavaScript – MUO – MakeUseOf

CATEGORIES

  • C#
  • C++
  • Java
  • JavaScript
  • Python
  • Swift

© 2022 Copyright Learning Code

No Result
View All Result
  • Home
  • JavaScript
  • Java
  • Python
  • Swift
  • C++
  • C#

© 2022 Copyright Learning Code

Are you sure want to unlock this post?
Unlock left : 0
Are you sure want to cancel subscription?