HomeiOS DevelopmentConstructing static and dynamic Swift libraries utilizing the Swift compiler

Constructing static and dynamic Swift libraries utilizing the Swift compiler


This tutorial is all about emitting numerous Swift binaries with out the Swift package deal supervisor, however solely utilizing the Swift compiler.

Swift


What the heck is a library?


A library is a group of Swift elements that different purposes can use.


Think about that you’re making a easy utility to pluralize a string. It really works nice, you end the app and also you begin working in your subsequent one. In your subsequent utility, you face the very same subject, you must print countable objects (e.g 2 bananas). What would you do? 🤔


The very first thing that may cross your thoughts is to repeat all of the supply code from the primary utility into the second. Effectively, this might work in fact, however what occurs in the event you uncover a bug within the pluralization part? Now you must repair the difficulty at two locations, since you have simply duplicated your complete stuff. There have to be a greater manner… 🧠


Luckily laptop programmers confronted the very same subject, in order that they invented shared libraries. A shared library is a particular type of binary part that you should utilize in your foremost utility. This manner you’ll be able to outsource Swift code right into a separate file (or bunch of information), throw in some entry management to permit different apps to make use of public strategies and name features out of your library and right here we go, we simply shared our frequent code between our purposes.


Oh wait, there’s a bug within the lib, how can I repair it? Effectively, that is the place issues get a bit difficult, however don’t be concerned an excessive amount of, I will attempt to clarify the way it works. So, final time, , after we talked concerning the Swift compiler and linker, I discussed, that they will resolve dependencies in your program. While you use a library you’ll be able to select between two approaches.

  • static linking
  • dynamic linking

Static linking signifies that the supply code contained in the library shall be actually copy-pasted into your utility binary. Dynamic linking alternatively signifies that your library dependencies shall be resolved at runtime. By the best way, you must determine this upfront, since you must construct both a static or a dynamic library. Huhh? Okay, let me do that once more… 🙃


The static library strategy is extra easy. You may simply construct a static library utilizing the compiler (you may see learn how to make one afterward), then you’ll be able to import this library inside your utility supply (import MyLibrary). Now whenever you compile the primary app, you must inform the compiler the situation of your static (binary) library, and the publicly accessible objects (headers or module map) which can be out there to make use of. This manner when your app consists the symbols from the lib (courses, strategies, and many others) may be copied to the primary executable file). While you run the app, required objects shall be there already contained in the binary file, so you’ll be able to run it as it’s.



The principle distinction between a static and a dynamic library is that you do not copy each required image to the executable utility binary whenever you use a dylib file, however a number of the “undefined” symbols shall be resolved at runtime. First you must construct your library as a dynamic dependency utilizing the Swift compiler, it will produce a dynamic (binary) library file and a module map (header information). While you make the ultimate model of your app, the system will put references of the dynamic library to your executable as a substitute of copying the contents of the dylib file. If you wish to run your utility you must be sure that the referenced dynamic library is obtainable to make use of. The working system will attempt to load the generated dylib file so the appliance resolves the symbols primarily based on the reference pointers. 👈



Ought to I select dynamic or static linking?

Effectively, it is dependent upon the atmosphere. For instance the Swift Package deal Supervisor prefers to make use of static linking, however Xcode will attempt to construct SPM packages as dynamic dependencies. You may also explicitly inform SPM to construct a static or dynamic library, however in many of the instances you need to stick to the automated worth, so the system can construct the precise module dependency for you.



import PackageDescription

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


By the best way if you’re confused sufficient, I’ve an article for newbies about Swift packages, modules, frameworks and the instruments that makes this entire dependency administration attainable. It’s best to undoubtedly have a look, it is a some type of a deep dive into FAT frameworks, however the first a part of the article is filled with helpful definitions and introductions to varied instructions.


Again to the unique query: static vs dynamic? Do you bear in mind the bug within the library that we now have to repair? In case you use a static library you must rebuild all of the apps which can be relying on it (they have to be linked with the fastened library in fact) with a purpose to make the difficulty disappear. 🐛

Since a dynamic library is loaded at runtime and the symbols will not be embedded into the appliance binary, you’ll be able to merely construct a brand new dylib file and exchange the outdated one to repair the bug. This manner all of the apps which can be referencing to this dependency could have the repair without cost. There isn’t any must recompile everyting, besides the defective code within the framework itself. 💪


Additionally it is price to say that the ultimate app dimension is smaller whenever you use a dylib.


Okay, however why ought to I ever use static linking if dylibz are so cool? The reality is that typically you need to encapsulate every thing right into a single binary, as a substitute of putting in a number of different dylib information into the system. Additionally what occurs if one thing deletes a dylib that your app would require to work flawlessly? That’d suck for positive, particularly if it’s a mission-critical script on a server… 😳


Hopefully, I over-explained issues, so we will begin constructing our very first static library.



Compiling a static Swift library

Do you continue to have that little Level struct from the earlier tutorial? Let’s construct a static library from that file, however earlier than we accomplish that, we now have to explicitly mark it as public, plus we’d like a public init methodology so as to have the ability to create a Level struct from our utility. You realize, in Swift, entry management permits us, programmers, to cover particular components of a library from different builders.


public struct Level {
    public let x: Int
    public let y: Int

    public init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }
}


Now we’re able to construct our static library primarily based on this single level.swift supply file. As I discussed this earlier than, we’d like a binary file and a module map file that comprises the publicly accessible interface for the lib. You should use the -emit-library flat to inform the Swift compiler that we’d like a binary library file plus utilizing the -emit-module parameter will produce a Swift module information file with all of the API and docs wanted for different modules. By default the compiler would emit a dylib (on macOS a minimum of), so we now have to make use of the -static flat to explicitly generate a static dependency. 🔨


swiftc level.swift -emit-module -emit-library -static


The command above ought to produce 4 new information:

  • libpoint.a – The binary static library itself
  • level.swiftdoc – Documentation for the module (binary format)
  • level.swiftmodule – Information concerning the module, “Swift header file”
  • level.swiftsourceinfo – Supply data file


Transfer these information inside a lib folder, so it will be less difficult to work with them. That is actually it, we have simply created a working static library, however how can we use it to hyperlink them in opposition to our foremost utility? 🤔


To begin with, we now have to import our newly created module contained in the foremost.swift file if we need to use the objects (in our case the Level struct) from it. By the best way you’ll be able to add a customized module identify to your library in the event you use the -module-name [name] argument with the earlier swiftc command.

import level

let p = Level(x: 4, y: 20)

print("Good day library!", p.x, p.y)


So, all of our library information are positioned in a lib folder, and our default module identify is level (primarily based on our single enter file). We will use the swiftc command once more, to compile the primary file, this time we use the -L flag so as to add a library search path, so the compiler can find our binary libpoint.a file. We additionally need to set a search path for imports, the -I property will assist us, this manner the general public API (headers) of the module shall be out there in our supply file. The very last item that we now have to append to the top of the command is the -l[name] flag, this specifies the library identify we wish to hyperlink in opposition to. Watch out, there is no such thing as a area in between the -l and the identify worth! ⚠️


swiftc foremost.swift -L ./lib/ -I ./lib/ -lpoint


./foremost


Voilá, we have simply separated a file from the primary utility through the use of a static dependency. 👏




Compiling a dynamic Swift library

In idea, we will use the identical code and construct a dynamic library from the level.swift file and compile our foremost.swift file utilizing that shared framework. We simply drop the -static flag first.


swiftc level.swift -emit-module -emit-library


This time the output is barely totally different. We have got a libpoint.dylib binary as a substitute of the libpoint.a, however all the opposite information look equivalent. Extension my range per working system:

  • macOS – static: .a, dynamic: .dylib
  • Linux – static: .so, dynamic: .dylib
  • Home windows – static: .lib, dynamic: .dll

So we now have our dylib file, however the true query is: can we construct the primary.swift file with it?


swiftc foremost.swift -L ./lib/ -I ./lib/ -lpoint


./foremost


Now rename the libpoint.dylib file into libpoint.foo and run the primary app once more.


./foremost





Whoops, looks as if we now have an issue. Don’t fret, that is the anticipated output, since we renamed the dynamic library and the appliance cannot discover it. When the loader tries to get the referenced symbols from the file it appears up dynamic libraries at a number of totally different locations.

  • The listing you specified via the -L flag (./lib/).
  • The listing the place your executable file is (./)
  • The /usr/lib/ or the /usr/native/lib/ directories

Because the /usr/lib/ listing is protected by the well-known SIP “guard”, you need to ship your dylib information subsequent to your executable binary, or alternatively you’ll be able to set up them below the /usr/native/lib/ folder. Sadly, this lookup technique can result in all type of points, I actually do not need to get into the main points this time, however it might probably result in compatibility and safety points. 🤫


The excellent news is that now in the event you change one thing within the dylib, and also you merely rebuild & exchange the file then you definately run the ./foremost once more (with out recompiling), the altered dynamic library shall be used. Simply attempt to put a print assertion into the init methodology of the Level struct…





Abstract

Truthfully, I would slightly go along with a static library in many of the instances as a result of utilizing a static library will assure that your utility has each mandatory dependency embedded into the binary file.


In fact dynamic libraries are nice if you’re the writer of a generally used framework, such the Swift commonplace library, Basis or UIKit. These modules are shipped as shared libraries, as a result of they’re enormous and nearly each single app imports them. Simply give it some thought, if we would hyperlink these three frameworks statically that’d add lots to the scale of our apps, plus it would be manner more durable to repair system-wide bugs. That is the explanation why these packages are shipped as shared libz, plus Apple can offers us a promise that these elements will at all times be out there as a part of the working system. 😅


In any case, there are some instruments that you should utilize to change library loader paths, I will let you know extra about this subsequent time. It’ll be a extra superior subject together with totally different languages. I will present you learn how to construct a library utilizing C and learn how to name it utilizing Swift, with out SPM. 🤓



RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments