Thursday, July 4, 2024
HomeIOS DevelopmentDeep dive into Swift frameworks

Deep dive into Swift frameworks


Fundamental definitions

To begin with you must have a transparent understanding concerning the primary phrases. If you happen to already know what is the distinction between a module, package deal, library or framework you may skip this part. Nonetheless in the event you nonetheless have some combined emotions about this stuff, please learn forward, you will not remorse it. 😉

Bundle

A package deal consists of Swift supply information and a manifest file.

A package deal is a group of Swift supply information. In case you are utilizing Swift Bundle Supervisor you even have to offer a manifest file with a view to make an actual package deal. If you wish to study extra about this software, you must verify my Swift Bundle Supervisor tutorial.

Instance: that is your package deal:

Sources
    my-source-file.swift
Bundle.swift

You can even try the open sourced swift-corelibs-foundation package deal by Apple, which is used to construct the Basis framework for Swift.

Library

Library is a packaged assortment of object information that program can hyperlink in opposition to.

So a library is a bunch of compiled code. You may create two sorts of libraries:

From a very easy perspective the one distinction between them is the strategy of “integrating” aka. linking them into your mission. Earlier than I inform you extra about this course of, first we should always discuss object information.

Mach-O file format

To create packages, builders convert supply code to object information. The article information are then packaged into executable code or static libraries.

Whenever you’re compiling the supply information you’re principally making object information, utilizing the Mach-O (MachObject) file format. These information are the core constructing blocks of your functions, frameworks, and libraries (each dynamic and static).

Linking libraries

Linking refers back to the creation of a single executable file from a number of object information.

In different phrases:

After the compiler has created all the thing information, one other program known as to bundle them into an executable program file. That program known as a linker and the method of bundling them into the executable known as linking.

Linking is simply combining all of your object information into an executable and resolving all of the externals, so the system will have the ability to name all of the features contained in the binary.

Static linking

The supply code of the library is actually going to be copied into the applying’s supply. It will lead to a giant executable, it’s going to take extra time to load, so the binary could have a slower startup time. Oh, did I point out that in case you are making an attempt to hyperlink the identical library greater than as soon as, the method will fail due to duplicated symbols?

This methodology has benefits as effectively, for instance the executable will at all times comprise the right model of the library, and solely these elements will probably be copied into the principle utility which can be actually used, so you do not have to load the entire stuff, however it looks like dynamic linking goes to be higher in some circumstances.

Dynamic linking

Dynamic libraries should not embedded into the supply of the binary, they’re loaded at runtime. Because of this apps may be smaller and startup time can considerably be quicker due to the light-weight binary information. As a free of charge dynamic libraries may be shared with a number of executables to allow them to have decrease reminiscence footprints. That is why typically they’re being referred as shared libraries.

After all if the dynamic library shouldn’t be out there – or it is out there however their model is incompatible – your utility will not run or it’s going to crash. However this may be a bonus, as a result of the writer of the dynamic library can ship fixes and your app can profit from these, with out recompilation.

Happily system libraries like UIKit are at all times out there, so you do not have to fret an excessive amount of about this situation…

Framework

A framework is a hierarchical listing that encapsulates shared assets, akin to a dynamic shared library, nib information, picture information, localized strings, header information, and reference documentation in a single package deal.

So let’s make this easy: frameworks are static or dynamic libraries packed right into a bundle with some further belongings, meta description for versioning and extra. UIKit is a framework which wants picture belongings to show among the UI parts, additionally it has a model description, by the way in which the model of UIKit is identical because the model of iOS.

Module

Swift organizes code into modules. Every module specifies a namespace and enforces entry controls on which elements of that code can be utilized exterior of the module.

With the import key phrase you’re actually importing exterior modules into your sorce. In Swift you’re at all times utilizing frameworks as modules, however let’s return in time for some time to grasp why we would have liked modules in any respect.

import UIKit
import my-awesome-module

Earlier than modules you needed to import framework headers immediately into your code and also you additionally needed to hyperlink manually the framework’s binary inside Xcode. The #import macro actually copy-pasted the entire resolved dependency construction into your code, and the compiler did the work on that vast supply file.

It was a fragile system, issues might go fallacious with macro definitions, you would simply break different frameworks. That was the explanation for outlining prefixed uppercased very lengthy macro names like: NS_MYSUPERLONGMACRONAME… 😒

There was an different situation: the copy-pasting resulted in non-scalable compile occasions. With a purpose to remedy this, precompiled header (PCH) information have been born, however that was solely a partial resolution, as a result of they polluted the namespace (you recognize in the event you import UIKit in a PCH file it will get out there in in every single place), and no-one actually maintained them.

Modules and module maps

The holy grail was already there, with the assistance of module maps (defining what sort of headers are a part of a module and what is the binary that has the implementation) we have encapsulated modular frameworks. 🎉 They’re individually compiled as soon as, the header information are defining the interface (API), and the (routinely) linked dylib file accommodates the implementation. Hurray, no have to parse framework headers throughout compilation time (scalability), so native macro definitions will not break something. Modules can comprise submodules (inheritance), and you do not have to hyperlink them explicitly inside your (Xcode) mission, as a result of the .modulemap file has all the knowledge that the construct system wants.

Finish of the story, now you recognize what occurs beneath the hood, if you import Basis or import UIKit.

Command line instruments

Now that you recognize the logic behind the entire dynamic modular framework system, we should always begin inspecting the instruments that make this infrastructure attainable.

All the time learn the person pages, aka. RTFM! If you happen to do not wish to learn that a lot, you may obtain the instance mission from GitLab and open the makefiles for the essence. There will probably be 3 principal classes: C, Swift and Xcode mission examples.

clang

the Clang C, C++, and Goal-C compiler

Clang is a compiler frontend for C languages (C, C++, Goal-C). When you have ever tried to compiled C code with gcc throughout your college years, you may think about that clang is kind of the identical as gcc, however these days it might do much more.

clang -c principal.c -o principal.o #compiles a C supply file

LLVM: compiler backend system, which might compile and optimize the intermediate illustration (IR) code generated by clang or the Swift compiler for instance. It is language impartial, and it might accomplish that many issues that might match right into a guide, however for now as an example that LLVM is making the ultimate machine code to your executable.

swiftc

The Swift compiler, there is no such thing as a handbook entry for this factor, however don’t be concerned, simply fireplace up swiftc -h and see what can provide to you.

swiftc principal.swift #compiles a Swift supply file

As you may see this software is what truly can compile the Swift supply information into Mach-O’s or remaining executables. There’s a brief instance within the connected repository, you must verify on that if you would like to study extra concerning the Swift compiler.

ar

The ar utility creates and maintains teams of information mixed into an archive. As soon as an archive has been created, new information may be added and present information may be extracted, deleted, or changed.

So, in a nutshell you may zip Mach-O information into one file.

ar -rcs myLibrary.a *.o

With the assistance of ar you have been capable of create static library information, however these days libtool have the identical performance and much more.

ranlib

ranlib generates an index to the contents of an archive and shops it within the archive. The index lists every image outlined by a member of an archive that may be a relocatable object file.

ranlib can create an index file contained in the static lib, so issues are going to be quicker if you’re about to make use of your library.

ranlib myLibrary.a

So ranlib & ar are instruments for sustaining static libraries, normally ar takes care of the indexing, and you do not have to run ranlib anymore. Nonetheless there’s a higher choice for managing static (and dynamic) libraries that you must study…

libtool

create libraries

With libtool you may create dynamically linked libraries, or statically linked (archive) libraries. This software with the -static choice is meant to interchange ar & ranlib.

libtool -static *.o -o myLibrary.a

These days libtool is the principle choice for increase library information, you must undoubtedly study this software in the event you’re into the subject. You may verify the instance mission’s Makefile for more information, or as normally you may learn the manuals (man libtool). 😉

ld

The ld command combines a number of object information and libraries, resolves references, and produces an ouput file. ld can produce a remaining linked picture (executable, dylib, or bundle).

Let’s make it easy: that is the linker software.

ld principal.o -lSystem -LmyLibLocation -lmyLibrary -o MyApp

It could hyperlink a number of information right into a single entity, so from the Mach-O’s you can make an executable binary. Linking is critical, as a result of the system must resolve the addresses of every methodology from the linked libraries. In different phrases, the executable will have the ability to run and all your features will probably be out there for calling. 📱

nm

show identify checklist (image desk)

With nm you may see what symbols are inside a file.

nm myLibrary.a
# 0000000000001000 A __mh_execute_header
#                  U _factorial
# 0000000000001f50 T _main
#                  U _printf
#                  U dyld_stub_binder

As you may see from the output, some type of reminiscence addresses are related for a few of symbols. Those who have addresses are literally resolved, all of the others are coming from different libraries (they don’t seem to be resolved but). So which means they will be resolved at runtime. The opposite choice is that you need to hyperlink them. 😅

otool

object file displaying software

With otool you may look at the contents of Mach-O information or libraries.

otool -L myLibrary.a
otool -tV myLibrary.a

For instance you may checklist the linked libraries, or see the disassembled textual content contents of the file. It is a actually useful software in the event you’re aware of the Mach-O file format, additionally good one to make use of for reverse-engineer an present utility.

lipo

create or function on common information

With the assistance of the lipo software you may create common (multi-architecture) information. Often this software is used for creating common frameworks.

lipo -create -output myFramework.framework units.framework simulator.framework

Think about the next situation: you construct your sources each for arm7 and i386. On an actual system you’d have to ship the arm7 model, however for the iOS simulator you may want the i386 one. With the assistance of lipo you may mix these architectures into one, and ship that framework, so the top consumer do not have to fret about this situation anymore.

Learn on the article to see the way it’s performed. 👇

Xcode associated instruments

These instruments may be invoked from the command line as effectively, however they are much extra associated to Xcode than those earlier than. Let’s have a fast walk-through.

xcode-select

Manages the lively developer listing for Xcode and BSD instruments. When you have a number of variations of Xcode in your machine this software can simply swap between the developer instruments supplied by the induvidual variations.

xcode-select --switch path/to/Xcode.app

xcrun

Run or find improvement instruments and properties. With xcrun you may principally run something that you could handle from Xcode.

xcrun simctl checklist #checklist of simulators

codesign

Create and manipulate code signatures

It could signal your utility with the right signature. Often this factor failed if you have been making an attempt to signal your app earlier than computerized signing was launched.

codesign -s "Your Firm, Inc." /path/to/MyApp.app
codesign -v /path/to/MyApp.app

xcodebuild

construct Xcode tasks and workspaces

That is it. It will parse the Xcode mission or workspace file and executes the suitable buid instructions primarily based on it.

xcodebuild -project Instance.xcodeproj -target Instance
xcodebuild -list
xcodebuild -showsdks

FAT frameworks

Find out how to make a closed supply common FATtened (multi-architecture) Swift framework for iOS?

So we’re right here, the entire article was made for studying the logic behind this tutorial.

To begin with, I do not need to reinvent the wheel, as a result of there’s a fantastically written article that you must learn. Nonetheless, I might like to present you some extra detailed rationalization and a bit of modification for the scripts.

Skinny vs. FAT frameworks

Skinny frameworks accommodates compiled code for just one structure. FAT frameworks alternatively are containing “slices” for a number of architectures. Architectures are principally referred as slices, so for instance the i386 or arm7 slice.

This implies, in the event you compile a framework just for i386 and x86_64 architectures, it can work solely on the simulator and horribly fail on actual units. So if you wish to construct a very common framework, you need to compile for ALL the prevailing architectures.

Constructing a FAT framework

I’ve a excellent news for you. You simply want one little construct part script and an mixture goal with a view to construct a multi-architecture framework. Right here it’s, shamelessly ripped off from the supply article, with some further modifications… 😁

set -e
BUILD_PATH="${SRCROOT}/construct"
DEPLOYMENT_PATH="${SRCROOT}"
TARGET_NAME="Console-iOS"
FRAMEWORK_NAME="Console"
FRAMEWORK="${FRAMEWORK_NAME}.framework"
FRAMEWORK_PATH="${DEPLOYMENT_PATH}/${FRAMEWORK}"

# clear the construct folder
if [ -d "${BUILD_PATH}" ]; then
    rm -rf "${BUILD_PATH}"
fi

# construct the framework for each structure utilizing xcodebuild
xcodebuild -target "${TARGET_NAME}" -configuration Launch 
    -arch arm64 -arch armv7 -arch armv7s 
    only_active_arch=no defines_module=sure -sdk "iphoneos"

xcodebuild -target "${TARGET_NAME}" -configuration Launch 
    -arch x86_64 -arch i386 
    only_active_arch=no defines_module=sure -sdk "iphonesimulator"

# take away earlier model from the deployment path
if [ -d "${FRAMEWORK_PATH}" ]; then
    rm -rf "${FRAMEWORK_PATH}"
fi

# copy freshly constructed model to the deployment path
cp -r "${BUILD_PATH}/Launch-iphoneos/${FRAMEWORK}" "${FRAMEWORK_PATH}"

# merge all of the slices and create the fats framework
lipo -create -output "${FRAMEWORK_PATH}/${FRAMEWORK_NAME}" 
    "${BUILD_PATH}/Launch-iphoneos/${FRAMEWORK}/${FRAMEWORK_NAME}" 
    "${BUILD_PATH}/Launch-iphonesimulator/${FRAMEWORK}/${FRAMEWORK_NAME}"

# copy Swift module mappings for the simulator
cp -r "${BUILD_PATH}/Launch-iphonesimulator/${FRAMEWORK}/Modules/${FRAMEWORK_NAME}.swiftmodule/" 
    "${FRAMEWORK_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule"

# clear up the construct folder once more
if [ -d "${BUILD_PATH}" ]; then
    rm -rf "${BUILD_PATH}"
fi

You may at all times look at the created framework with the lipo software.

lipo -info Console.framework/Console
#Architectures within the fats file: Console.framework/Console are: x86_64 i386 armv7 armv7s arm64

Utilization

You simply should embed your model new framework into the mission that you just’d like to make use of and set some paths. That is it. Nearly…

Delivery to the App Retailer

There is just one situation with fats architectures. They comprise slices for the simulator as effectively. If you wish to submit your app to the app retailer, you need to minimize off the simulator associated codebase from the framework. The explanation behind that is that no precise actual system requires this chunk of code, so why submit it, proper?

APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"

# take away unused architectures from embedded frameworks
discover "$APP_PATH" -name '*.framework' -type d | whereas learn -r FRAMEWORK
do
    FRAMEWORK_EXECUTABLE_NAME=$(defaults learn "$FRAMEWORK/Information.plist" CFBundleExecutable)
    FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
    echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"

    EXTRACTED_ARCHS=()

    for ARCH in $ARCHS
    do
        echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
        lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
        EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
    performed

    echo "Merging extracted architectures: ${ARCHS}"
    lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
    rm "${EXTRACTED_ARCHS[@]}"

    echo "Changing unique executable with thinned model"
    rm "$FRAMEWORK_EXECUTABLE_PATH"
    mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"

performed

This little script will take away all of the pointless slices from the framework, so you can submit your app by way of iTunesConnect, with none points. (ha-ha-ha. 😅)

You must add this final script to your utility’s construct phases.

If you wish to get aware of the instruments behind the scenes, this text will allow you to with the fundamentals. I could not discover one thing like this however I wished to dig deeper into the subject, so I made one. I hope you loved the article. 😉

RELATED ARTICLES

Most Popular

Recent Comments