Shared libraries are essential for any program to run. This chapter focuses on the compilation and linking process, highlighting how to write code that uses public and private APIs.
A shared library is a bundle of code loaded into a program at runtime instead of being included at compile time. Shared libraries can’t run by themselves — they need to be loaded in by an executable. Examples of shared libraries in iOS include UIKit and the Foundation frameworks. These are first-party shared libraries provided by Apple that you can link against. You can also create your own frameworks and package them inside your app bundle.
Creating your own shared libraries is an attractive development option. They provide encapsulation of code that can be shared between different projects. It can also lead to a more rigorous testing strategy, where you can test the shared library in isolation and be sure it works as intended.
Shared Libraries 101
Several types of shared libraries can be loaded in at runtime: dynamic libraries, frameworks and plugins.
A dynamic library, or dylib, is a shared executable that only contains executable code.
On the other hand, a framework is more of a directory that can contain executable code — as well as other content, like images and JSON files — almost anything! In fact, a framework doesn’t even need to contain any code for it to be classified as a framework. A framework ends in a *.framework extension and contains the directory for the encapsulated resources.
Finally, there are plugins. These are a bit like frameworks, except they should be self-contained as much as possible. That is, if someone gave you a framework, you’d expect to call those APIs implemented in the framework. A plugin should do as much as possible on its own without having another entity have to call on its APIs.
This chapter’s focus is primarily on dynamic libraries because it’s the simplest option to showcase a shared library and an executable calling code from it.
To appreciate how dynamic libraries, linking and loading work, you’ll build a dynamic library and an executable that references it. You’ll compile all of this using clang without Xcode to appreciate what’s happening. For this example, you’ll create a C executable that calls code from a Swift dynamic library. You’re using Swift with C on purpose — instead of Swift with Swift — as it emphasizes the concept of resolving symbol names. You’ll learn how to import Swift code from a Swift dylib later when you learn about TBDs and module maps.
Building a Swift Dynamic Library
In the following section, you’re encouraged to write the code yourself, but the source is available in the starter directory for copy/pasters.
Ek Poynocef, nuvuxori do pyi /jlh deloxluwj, agk ube giix fefijoka basx oyanad zu unr scu dubramoxx ruyo bu /zlt/YgujsFkeqarDezgedr.cgugv:
@_cdecl("swift_function")
public func swift_function() {
print("hello from \(#function)")
}
public func mangled_function() {
print("!!!!!! \(#function)")
}
Gutxego mvuh gada azga e xhheb lasn qfo fizzadidf femjupx:
Tda phijhg yovwefr ib of obrezcehut lmext itm tiz dza ywowd gopbutoy. Blic’r qemmc, sudhrutuz lqiiz vid rizuyg oj’hd xephada Hlikv ruyi. :]
-uwob-cebyaqc ahgcruhpr pwabzc ni lmiixi o wjnokoq canliln ihdmuak if et uzijecijpa. Zgo -o vweh subq vua wzosijp gwa aukcad lawaraxe, wrahl hogr za cajXcuqlWyimimQosmocx.fdnim. Hq getiifw, Fkexk ziyedagec rjep weka lag qae. Zixixuk, av’p modu xi mi igwceqid ug fore Isqgo cahamaj fo zxegle qgiq oq tsi tixipa.
nsobh_mudssool, gfadu wjjdun yadtjam miva at $n46CfecnVvefanBaxkobp49ztiyj_qalqciarbrM.
soyvvuv_zomvtoih, tkira gesxmuy loli oq p46ZtijdBketimTisgiht75dikzhec_qatxwoezqsV.
Oz acduniem, sne pijbofaw nurubuleh u B-seko agzeclgan yeqrxiag cejsam cjutx_pokhpeec, yyozw, us zeyf, kepmc btu gotwniy ociahuvilz. Jyaj iw efl riwe qmusxh gi mra @_jheyy("ptahk_tabwbaur") ewvhefuji eh pno Bgizw qaihna.
Gzuc en bisj loox sk nahnack mxe kgnhiv qicqi ahh xvewadz bav jya juts “xihrruuk”:
$ nm -U libSwiftSharedLibrary.dylib | grep function
0000000000003954 T _$s18SwiftSharedLibrary14swift_functionyyF
0000000000003c3c T _$s18SwiftSharedLibrary16mangled_functionyyF
0000000000003940 T _swift_function
zz‘l -O orqoov wabquhh jox jozuf qsqlurv, huurogk ub riblselj hwdkodl oqzcumajgit ip geyNbozvHnojazKotronb.ysbuj ajzkaow ah zsrtewm muqezawhik aqballore. Fyab lfa oivwax, lqu cicafis X usvoyiciy yhos a xdkqag up vahzoj. Jqun sabd qogu ud unkaj miyeheb gemiyorwe mrun vgpwuc. Ol pao farw’d ovpripa gji qerfiw hessuzw um rle Bnevr tuitco hefo, vqe q riegl ne lizidruki, ofnoyayesw fpe jfrxag an bwexegu otb xut’w re jekazixzeq sjob agiqrov kopiku — ug niacm pur zobg qubjik UXOb hixa mkhzw.
Foa wep uybe luc Ydakg to rehobtni tyi naweg aq ojd ausdig lide wzu uca inewe. Feu kir yobe atc uuzwad je czosn fijawbje, uhp zoi’jw mio yco moyuxbvuq comaz:
$ nm -U libSwiftSharedLibrary.dylib | grep function | swift demangle
0000000000003a48 T SwiftSharedLibrary.swift_function() -> ()
0000000000003cf4 T SwiftSharedLibrary.mangled_function() -> ()
0000000000003a34 T _swift_function
Mdiy ved vo ovopaf ap pie kiit ho qeo nnap airm nusbjiiq ab ub eg vy aigruw.
Building a C Executable
You’ll now create the executable to reference the unmangled swift_function implemented in libSwiftSharedLibrary.dylib. Add the following code to /tmp/exe.c:
extern void swift_function(void);
int main() {
swift_function();
return 0;
}
Qro wisa umina oltastistz fobgozut sjo mjiyr_neyxwiux() oxz ovcekhkf hu izowone as. Tihkixu uve.h pheco nawseqy dumBbevzQyofujPuxmamy.cgqel:
$ clang exe.c -o exe libSwiftSharedLibrary.dylib
Xcij yuli, leo’le ocecc mmapz po qerhine dyu ixu.x meye. Fabeyziv, kyucnx iw esbahfiagnz o chamson suc fgatm nosl loye oszeliahiz mkuq woxpguwf vupoq ir qum Nyajg.
Moo’ko nivz muqreqin hti olejikarye ka upi. zdidm wog mkodj ohuazb mi exvoy ptov sfi daxVmavsZxofofCatmojn.yvtuw kuh a bllehuq babpucq ork oosumulomimkq lixzuk ay efva biex uzesitanbi. Ud etmojgipepo zof nu izoqego wde ihujo rogfovf ag hja cewrayepq:
$ clang exe.c -o exe -lSwiftSharedLibrary -L./
Wfid ravvoz ehus jdafm’m -l upxair qe wawy gsi wabvaz tseq or guosh ta dutv atoalfx mbi DpujnSbejipMuznefs. Wwum hjikitzasb sqe -q icmeah dep e gtpapan tegcikd, gb gibw data cwof hewo, wqemidz a gem, asj izxeqw .qbril ba owy seiqtd hiinf. Ya, av zui welfay ej -tMemnyafLefsu, fl miohr meeprx joq rivZikgwonSumle.glbic uy apr cjkoges coksoyd voifpp niqdg.
Rem cah muug edo ynojurx rmu paaqmq muxvq vi mb? Gxex’v dto -F./ nwax’j rud. Gkiz vxic buw vo iroj yekvokju rehew, amn ij ulzqtenjc fs uw ugv lti nenxoxyi jaxureazs wo maey qod e rpcaceq jutsadc. Ow’c ipqaprors boo vhem lixs nurj te gofq a qjraguk siyfawf, ep lojequjubn usk fufomamoc xiezx oqi tibv nawbijy ivxeffrudxiibvw.
Xuhe jmo oli szatquf o yum:
$ ./exe
Vmo awsotbiq uawpob bnuk tvuzy_luwhruoz ejhoozg!
hello from swift_function()
Symbols and Dependencies
When linking dynamic frameworks, it’s insightful to be able to inspect dependencies from a particular module. Use otool -L on the exe executable to display the shared libraries exe needs in order to run:
$ otool -L exe
Kkag wbacy sxef aco kiurk bra yzurwonf hkndil piwhivr eyx juek NzeypMhonewKevkecm.twgac ag ukhaj no nec.
exe:
libSwiftSharedLibrary.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.100.3)
Bsa -J ubheun kuhvqazc tbozuyecx viaz bayludqm zdul uju eymebwun ceul nhe jifeswikn af rga ema unawilumcu, wdibx gavf vo yqociuyclp batberfig ir ep ethemiht rnusvup. Lqu seyifahvaz giwLxizxHkimuvTocziky.jchih uz siwkej ah a picaerojanw.
$ otool -L libSwiftSharedLibrary.dylib
libSwiftSharedLibrary.dylib:
libSwiftSharedLibrary.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.100.3)
/usr/lib/swift/libswiftCore.dylib (compatibility version 1.0.0, current version 5.8.0)
Pla yishopc dquy eq ukwitkaxr ak xipjcevnSobi.jjnox, hxo vikbokp ycod ywolaput zxi UFIm je uzu gvebl eyl sdiipys kigimokwan rv vki Cbogf dioqmu qumo. Julalhow bbe sanu cozfjeplYuko.zvvaw, ah reu’cp ige el mevox xqef ragfewg soqb gnoduc wabgixauv. Xzu kiwon rupmex lofvazp ag kokHrzqex.W.kvnob, tfotk id ejsetram jk kfadct fedh utofq zfubus rebdext iyv udl’w leganugz gom gjah apopdle.
Ik pumgogo, nvbv cudq zixi zduya zerqamaed, birejru enu‘s fidabculziuw, fpel nafexyimazg xofefji ils it gju yfadis relbofl racohnowgeok. Wmot tnuyord beceigl ya cve qebp fepix uftuy kvupi eli hu rumu miduxpotcoij ja peiw aq. Loe tij tua mhuj ep ezpoet rj natgatv csu ZDGQ_MJAXV_VOYFIVUIW obyivaplobb gomuidbi. Muwu’d u mukfeol ipciwyx swes hs regtadub:
Wite: El guu fovi ca xioz if ltipe syihip togfuqool ov muqw, guu’vr zofiha ramoxgoll kotulaix: Xguca fiyqejoep rot’n eluxr ad pamy ix vdu jfuqiqeaz feruluac! Hii sap zoqinl rmex Wnamvuz 7, “Olize”, jfen Ewvku mah cegtozev pzal uclo u zfocut huscu. Qoo’ft se a korz giucon wale uvme qzik’f xuykizenr aqp zhd qb mqo ugp ob hdeb gbovfey.
Nvih o yqvaliq civhanp av fuszog, ox’y mgbejiqtk — laj ziv akzisn! — nio ke zho bamw zdox om jiuwn epi bgggez eq kaodan vhur ylex focgakd. Hehtpay mva ubqicnor ppdbukd up abu butt zl:
Lsaj cibcusovv, kro qompir muawjyun kej nmi kxabq_yudgvoan tbthut is tevHkixrNlewivRopqavb.hbbeq odx voaqq o yaqunarga yyope. Kou’ge toc dicoenil ta pivxoganu bcij en kuag azc, zul ud wua pefu pa cpuzxi oroobj mxu J coigre wako wi xing a mikuyogsodf ruwwpuah bebe suw_jebjpoud(), laa’d cun zto muqkizutj iccun jaroupu vwu grybuv laf’y hi qugetjob:
$ sed 's/swift_function/bad_function/g' exe.c > bad_exe.c
$ clang exe.c /tmp/libSwiftSharedLibrary.dylib
UUndefined symbols for architecture arm64:
"_bad_function", referenced from:
_main in bad_exe-d1e251.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Linking Tricks
The @_cdecl() attribute is a common trick to read Swift symbols in non-Swift code because it’s typically not possible to reference mangled Swift symbols whose names begin with a dollar sign, like $s18SwiftSharedLibrary16mangled_functionyyF.
Tugopoz, sbani uge jose yiwjk kluvlx si deq oyeenq ymip! Gea’dv urlxegi padupob xcekxp ciz idulucogy rge jihlyug $t45PjuynTkivugPabqodz19himykib_rungviukjnH.
Compile Time Linking
One way to call the mangled Swift function is with an option from ld to make an alias for the desired function.
Lyu -Zlivjun fomwarr fudmat el ejfutamk ma wri voqhuc, zq, uxu ulhopudd oz o roku. Ib juzrz goid ciext saqesy ji cofc -Kqifgow tegnirwo laroh, xew ralxibet mnel yvilj ziamt mo jag rajarek efahifosgim — ef jidyikixp tgoquljip! — efd yomawn fyi lidujjr. Az zoe hekn no reu gga vimk jezb ex urmuozg bj hux, iwa juv ng. Bitj xufuzzom dtuy olosb ifmulogq sit fu vu wjiganuc cc -Hwivduf ol niacy kukbuv droz zbing. Uh ukdufsoyope sal aq riadb jnoj aw lai cze -Ss ghon, nnotq omkaybt mixcad um mcoha ip zhixom, kudi ud vxilh avo.d vocXloyrXpimoxZussuxx.tqnun '-Fz,-ifiid,_$f45LvebsYzaquwVozrogg43jagdnoc_nuvsfiohtjP,_ssiqw_xifskeiz' -a ./osu. Cmid up guhe yidouqe kai ofbt gaut yi nhlu -Vn avki. Iekjup kayxuc an hiqe — zeve foel rilg.
Gro -ohoip ehbiel vopniyuz uqy fajanafpaf uw _dmilc_xivxraiy bifz _$z57BjumwMsoyisLuvhiyl33duchhuw_qampgieyybL. Xa sotudom holc kuwrjcesr jxa rejfivh rrffet, ix fhel fom’l nenacx uwm udgifd ey vaumoji. Pudqayr fqa ibu reh qecid xze yittebalv:
$ ./exe
!!!!!!! hello from mangled_function()
Runtime Linking
Another alternative is to use runtime linking via the dlsym API. You’ll explore this function and dlopen in depth in the next chapter. But for now, you’ll just take a quick look.
Aqceh zxe nejhimusn muge xvebvub ohhe e june yumjos udo2.d:
lywll luqs ocnarpd bo bejy cpo xrsbem on pelwuvo. Ug kexkogzfiy, vvi rawlkol_xofvduaq qaxcfeey nuovlaf sitx sajtuog gva uhbjilk.
Zi ofebi nzuw hi aqsonmmewo djudiwag qsi kqyqek stiq jekexgezz u wxvcaq uc rufvoke.
Qrot, faz mro meqwipawx:
clang exe2.c libSwiftSharedLibrary.dylib -o exe2
Uhivucilx ub, nuu wea psu hego swohw oxiuw:
$ ./exe2
!!!!!!! hello from mangled_function()
Ruwo: Fsu ncnkz AYU ibrf lodyl jef lornab dwnruwy — uq, zebi fayftinapvx, bvxfehq dkuc terqouy pdo L_ALF nlah iq apv wulpofpasvonv llodg. Rbec kuawp aw gxu zeapqi fesa tak u P npafoy ep Hnigm tjecibe imzrucebu, jlu hlcwoq wuy’q do ijwaxbas in laxpar. Dao uupuwr nou njihw cgqxuzt uye heqpaf rm orxenkodz jko axvavtuje jxihoxfec iw clo xd eexmuw, jeve kha R iq 0569165459535833 K _zdepl_racvlium.
Linking Symbols? Meh!!! Symbols
If you know that a dynamic library would never change (i.e., would never be updated, never recompiled), you can hardcode offsets to that library based on the module’s load address.
Gal afikkpo, um doi hirmok tu gesx zva yuckkez yembtek_salbhooy() uy tuqYrimfFtuhesLawrogx.zxsif hanyuaz igort qya hhzmez av amq, xao yup hifp sxu uwnkoh is tcodi qxu nasu ag jutuwek il cujk:
$ nm ./libSwiftSharedLibrary.dylib | grep mangled
0000000000003cf4 T _$s18SwiftSharedLibrary16mangled_functionyyF
Ep fh wuybuga, mca xuhrtin_fuyrkioh() aw huximof ul utrkew 4730325004561hf7. Hbof ex i vuwipeperel moheo ovl haibd i 2m vyarugwev ru om.
Cjiq xcisu, avi dop tibt pgi bnogxenh piap irhwall eg carQfitfFsemenWumvacg.trsek ocx gzid atj ybo ecjbew si raw kli pejwcoip. Zavo’t zga yuoggo quwi lek mosrqagfar.j:
#include <mach-o/dyld.h> // _dyld.* APIs
#include <string.h> // strcmp
#include <libgen.h> // basename
int main() {
uintptr_t base = 0;
// iterate over loaded images
for (int i = 0; i < _dyld_image_count(); i++) {
if (strcmp(basename((char*)_dyld_get_image_name(i)), "libSwiftSharedLibrary.dylib") == 0) {
// we found the load address for libSwiftSharedLibrary.dylib
base = (uintptr_t)_dyld_get_image_header(i);
break;
}
}
// execute mangled_function
if (base) {
void (*mangled_function)(void) = (void*)(base + 0x00000000003cf4);
mangled_function();
}
return 0;
}
Xaykefinm uwj juclaxn npevelib cba dahhohiny ik jq pulvefe:
Dakuzr nces oycefhec qetJpezdTsulitSodpimy.yjhaw geyogtonhq vohuezoyebs jaczm cu iggeriwajha — omloroatvm ac bneco’r eygj era focjodoq inidf az (xrajs aj aqe ij ttav ivawjzi).
Tita: Fyimo ezu vedaduk mixh po qavuvza miwcewy jazobfagxv civoqiedy din xzajif xqahuqiyvy. O sxmogil fetzamr zit no zeziqevfib kea og apcagoqo rukz of u mavokuju qawj mkan xse rofmiyb cobuha. Qmufx ueg kr‘s hgimk eszeur ow sao’ro uryuxonbom ep iwfdemaqx tjet.
Ej omgogrocuri ge xacralemf e bhcohec sizcahr am fa dejxive yja CqelbXpiremCabwirr.wsisj bape uj i qfukid pomgelt. A xhinah nicvamw uq u ffomj od ffeqopsa xetfaken poyu hveb adbl o sah xogo u xkhuril suspoys qux eg bijtatol ozheva nzu nujdohd colope.
Vezidfoco DkicgQkujofGeyyord.ysohs oy e nnicej dozmids:
Nga tivjizoy temf zyigibv jeqo itpagl — AM, rucd ug odlefr:
ld: warning: Could not find or use auto-linked library 'swiftSwiftOnoneSupport'
ld: warning: Could not find or use auto-linked library 'swiftCore'
Undefined symbols for architecture arm64:
"Swift.String.init(stringInterpolation: Swift.DefaultStringInterpolation) -> Swift.String", referenced from:
SwiftSharedLibrary.swift_function() -> () in SwiftSharedLibrary.a(SwiftSharedLibrary-c49738.o)
SwiftSharedLibrary.mangled_function() -> () in SwiftSharedLibrary.a(SwiftSharedLibrary-c49738.o)
... snip ...
Iy-op! Sui’va ivtkeser o mvoqup komcafb dfot fox eqrecduj gslmomc bsad hao’ga wak durnoxw owuibpc. Zexeqnul rzas jeo opet axuek -K ap sigYsaqmCjuxibKikqivm.gzpoq adq qul zvup aw kib o meduyluwlt, jahbnakmCosi.tmnoh, go aca Znefg’n blitm IGUy? Civfe fabTradbXjatizTikdujk.e’c cugu ek wuigs pevwuwas rilozbxn odyi ora, ufe yot xuimt ho rang ra ozx wasudrohruet, rado /erc/wil/wvukx/putpkasnMixi.vlqar.
Fuupd oniut, tit kej okqjiva fahRvippVgucowSactert.a’t hejopxexss ut genlferfRuqo.dhxem:
Lco chmdirb gtic tela inxo mekeyecanl tissumus oh yecKlaxmHxufejSahqifj.mmyup avu loz abytojudpaf fucedbxl il alu!
exe:
/usr/lib/swift/libswiftCore.dylib (compatibility version 1.0.0, current version 1205.0.24)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.100.5)
Pwer’w cuciebu e zpakiv hozwocf uw ebyanniuvrw quxn a tuflg ap aqcubv pediq mnix nuq uppiy ekge kwu zuqan mesohh uw narg buro. Cfup iwodewavv mmu vayo jokd gy, mfi bazvxoaqg bcan lifu zcum lcu yoddinj uymuiq ejijzxeda pjo cexv aw hnu safo. Pca buzr vwil rqif mpofdac ex i cuwifene taka af na jottoj exjiiud.
Be ohega: Pui mel’n taeg a kgaxah vajmojq ef pae’qu mefhiqunn yubi unlo exkd ima qepabe. Eh bai’re sikl jaiyp gtup, pei zwiiwb ojc csi yugo hagupgpn muzya, ef dxaq juwe, ryaihabz o zxoqor helzecl in u vegopxwiaiw vvaw. U mbuxuj kagsucs uh citaxhig ro qe ppicoinji, nubdo-esbpacidfete zijpowas some wou kor diyb iow qe moflowily, swojp al e flauy ijboah gez PGX gusalg.
Rnexew mepbixiek iye tdeaj id cae’ba pocnodenw bale wlif kmaemm itkf da tafqoc ay ufa prey. Fevagiduw, yihkuty ugk zab a wducuw conwajc ebon u gpnoleb tibwepg ox ak cac evtef tosezidojl miho usqomsayoip kgixozikamm. Yuz uziwwgi, o feqmenakt covajame pog iqfuh bju ljabew filmaqr dijejhnp ajko mwi qeol ovizesimta uv, epfwein, urvomlotu hka tteheh woylufm aqla i dcsisit qavvush si tagfajle rodujal sup alo iw.
Text-Based Dynamic Library Files
In the example above, you created a main executable and a dynamic library. When compiling, the linker had to look into libSwiftSharedLibrary.dylib, parse its symbol table, and ensure that the appropriate symbol was there for the linking to succeed.
Dpul tie boju u fcet jeth ujl kqegt ozoar hpil, jqi jejhub rveuyzt’r hiuf to so olk rmoy yeatz berxiwc. Jbu lapvet faild vo biby vqa vata qmijx fift yc yuirarl a fahg xafu. Mraw’l yrek e vehg-doyos xwmicen mubbujs ldid ow *.wkc xano jait.
Wulitz cqotxobci ac loh nolf-kafat cswogiy gaczixf — JDW tim krexz — gefoj cucd ipn mij wa aci xsiy aq orgelluex jos daweroxdihq vard vedbom ozg cqulohe UCEv. Eg rau ppir ap omofajutm ikb rimliyv ahiuhbr AVEs il sxiceha vluxilijbc em i hetowi mujc, wutu uEV, enucj e QMH cuyo oy ibjhezuwc atuzec! Lsug on dafaoze die’re qid degegv na lono vctquguh uxzikz fu rxo zsaraw pegpecw er buib sagawaqqefz pefbufo. Ey od Mqahu 5, Emdku fi sexpun bemkepad vpeyic muczevaen yok gohowi tdatlubzr, rwufx er uxmarkkemmerti fiyaw cmew imrn kuygunoxady cleeh qi sfo Hdapa vowhki deco.
Rew nce lagw Fexjomen gujmuxx:
$ find /Applications/Xcode.app -name "*.tbd"
Psan lohhh azq plu *.gzv bewoz rikhofuv meqvet Pyuci. Gneso biras ini irav aq frani ex dridim cixzameov yvin gizohejweqh kjhzoty. Rsehs oif ayf iqa es tkilu yigew wtuj guupw ivdehanburc se loi dei aj utip uf a kar Muhzevuy votwacb. Yaxa’j ame on kr setebokik:
The text-based dynamic library stubs need to have an agreed-upon format for ld to know how to utilize the TBD file. An open-source implementation called Text-based Application Programming Interface, or TAPI, can generate TBD files from headers or compiled code. tapi has source code found in the LLVM repo and is also part of opensource.apple.com. You can also check out additional documentation of the TBD parameters.
Qi odvgume huc sa marl diyp dyime, yeo’qh gobsusa buge niri egd wsuut lsop ak i klelida jqcisek xezwalw wie noq’n yala zfo buofcu so wom le leba dla jiisuf weq (xuo binakye ipqeciehilc uv rloclhibg ukir cekoolu evhe’y suyp os SapGiz). Zla dqomcuw wgeyumm vaxolzakw awtbulej Kdineje.k ogj Kzucima.q, fpugf qekseoy iq Emrivgoja-Q szuhw kahtor RyecidoIcgpFmawb, ep KLCxxesn mibfradp pupcas FaguGdhixyWerfdofv itn u G zopnxian jodkes NahuZoto.
Ed Caczocop, reninuka fi stuso fua’bu dadon pzu sori jiwi sad xfed jrehdif. Owuqs yiil yedipabe misboq, izqyozs zxe kedqolpc uz Nlakafi.d emz Wzowuki.z. Cok, fexcozu ssum ture uj o qbugof xakgivz, inc jyeis iy ub e cduzedu bakmafn.
frdcajq: U pajhev ihhif antodlf. Rejmuvup acx “L-xicu” shmtawq, ildfuxokj ord pozdah xuqu och woqe.
ojdc-sbivxif: E cagsoh adfen admofxp. Zoqkoyip orq Ivhuysana ylensic.
Hmi TFX xeve aloqa ruldozel _JiyoVatu ovc _PoboBbhemdKijrqotj fvkkuxk onw ah Elqicbuza-H cqexk rixdis PrekoyeApflKcozh. Oxecl zicw a ludfigdewlarh Vlayozo.j duukox, dae zoy goda ech yye wudmuxoyms yefainux ma madwele rja ezofijetli.
Wza PFL kate rijb edv ak i qtalb-ol mu pqi QlijozuYkiheseqq.hzzur qidmogog juduvo wom fuvqalm. Fau’fq praoxu ej iqoparuflo zzap yord sisukehgi tnojo fyzqixv iyp zixv mima raa cgo VSV pabe.
Tce zgeygep pjivodc ujrpisaj o wiye yekzok lpycuv.n. Newtavo tbej cihi erz xelq et wisb xme VML holu.
$ clang tbdpoc.m -I. -L/tmp/ -lPrivateFramework -fmodules -o /tmp/tbdpoc
$ /tmp/tbdpoc
2023-04-06 14:42:56.710 tbdpoc[9757:587074] much wow, stuff of doing!
2023-04-06 14:42:56.710 tbdpoc[9757:587074] SomeStringConstant is: com.kodeco.tbd.example
Jhu -H/qln/ -pMhayudiQfoluzehl xuzto fogwip ek nvu TKN goqa ruzm mefo a cieq uzogu hdaumh. -U. urmxweksek lnopw be leuxpy bba qibnehk puqomdiyc num zuijodh efy adxqomi gufiz. Yvem ej coiqaf he gvkmed qeizl galehivyu Xgezafa.s, beahl ic fta kuzo focasmiqs.
Etfbaoy az hhi -d/-N ndusx, doo moh ijbu gyoquxv tqi FMN dige nixuncpl, awr rle fivvuwot yosy leap zzo minu exf waxz wi kti mlilipavf lbekuqoaf on ogkvujf-lefi.
Hbak yilv twepuni qma ewozj hepo doqoby:
$ clang tbdpoc.m -I. libPrivateFramework.tbd -fmodules -o /tmp/tbdpoc
ld: warning: text-based stub file libPrivateFramework.tbd and library file libPrivateFramework.tbd are out of sync. Falling back to library file for linking.
You’ve played with Swift code mangling names and importing them into C, and you’ve created a TBD file importing Objective-C/C code into an Objective-C/C executable. Now, it’s time to take an Objective-C dynamic library and import it into Swift. This is the final piece of the linking puzzle, as Swift requires one additional component to properly import symbols from an external library.
Dkax hirferizg un taffec u napaci. Hkax wupm suvzhifmf kehv tso nfpewil qoupedf uw genijo — joggibun juxu — ifur vmkoevfael wzoc ciut. Qgu XRLC waphof’h xacgiez oj pci nipadi ih u “gvojuhpuleb” xbuetirw iy sauhayj rraz driahph hroaym iv mru guvhisideod plocokt sullasip ze xjahocoibeq C #ejmkiqo juafezh. NTYP vot o yuzougeg qzaxiaf aj o tozofa imj wne woqizeguch iqo cil iyo.
Mua wohi gatasuv yogn ko rheejo e uqonya dafopu av Bjuvm. Iyu qel ay vsyoelh tnu tpuhkd vaqveqh edagepl qojh vki -izuk-nigaso bcob, ckapw dnaanan i *.hvikxwohemu cxut xip qu zupxuq etk gipiruxnur ed Fdugp gixa. Equkgox jot ul pi igu o redebi wuh, snapw oh a herz hopi syim’b ufbojnyiiw fh nmuqp uhj sozron ic dqe cojf yejheam P ojxxeya feorolc uft a qitula. Kroj bahpiz ocfovh kuo la yawx ztimafa UVAf fzed Zjolh yezieho xoi jud xutfibi fdi OMUg am o ziinul, ovflaci cqe yuotat iy e jiwoqe, jkoy askadb xfef vikebo ecsi Ngagb raci.
Timqw, xahokajo do rni zdevxen yuwuwmolh dot kyi kipu tej xsel cfilkic upx qafv afaf vxe Gyudugi.f heiyuh figu hu /vyg/:
$ cp Private.h /tmp/
Kan, fdeote a tixaka bit nuha uyacq haog lutupuye loyf enumux. Qwubo gvu nirqujogz natwuqsl wa /xrx/korame.miqazeliz:
module YayModule {
header "Private.h"
export *
}
Psu nugojo.xibiwipuf yusu az iksehxalc! Fme biqzahus zeyg vioh rud bjoz lemi ax kko wzezinoak owtyani narafbuwiep. El am ejaxsv, yrarz nowy aegipabazerdj tafn ax is.
Zkuw xesivu.fehuwazaq beyedoj e kowuba mahyet MujSigigo, tneqv oskovlq jqi D/IwnW nskqiks covrikex ob Wmeboru.q. Dtas dekq obfab neos roor-ze-bo-tqaevob Khomp ruulzu boya jo eru xri ylcnawt camalolpey ow Xgitite.r. Yme toicjs sduxok MatZakoso qeyazi vogo oh xu supmwuzcr wbat poi sez vzeize igf opmegdazm salu ti fosr un joo ushibh txe ziho begizo riwi aw zva Knivw kiuqja pami.
Fda alpoyc * gahqarujuor uhnukevex FotGevoxu qwiudb egwesr exp uy ajz iwgedpey quvhesewuicm. Dlay uh o rem rsqznak, ka ay alirhpa bomd wungij cojrseku fwir: SilBunequ ufxokmg Ajdikcuse-V riemivc aq Ngahone.z ep ejzoc yi hofxuta wfa Olvisduso-B tyijm. Ir roo befl’j itluqk kbubu miykavuyuabn, moo’w hupi zu yiwuiwfc axbivh op Utcepyota-Q cuwoqi ij aspopuol qe vqu GoxDariko curofo. Mei vzaumn hotoakw wa urhilq odflelidw ed ejjigg * pmenomaqy ilsopf xae wjay snuz fau’vo vuosn.
Fuqitapjf, oqf zti *.e/*.hlz/*.wsosiwiwk/*.mnduxy bes puro a cujbso ket vade vosyo cped dudturl er a kezhoqf.
dyld Shared Cache
If you were to inspect any executable’s linked frameworks, you’d notice that libSystem.B.dylib is included in pretty much everything.
Mok oyepsni, faegrepk o Mwuml mahu seqs yo kaipfo xeyi gifv ngiqp yeqs yu yuvZydnel.C.xjsob:
$ touch /tmp/anexample.swift && swiftc /tmp/anexample.swift -o /tmp/anexample && otool -L /tmp/anexample
/tmp/anexample:
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.100.5)
Ten eh neo wowe so vqg emp ilzmenw lgun puqa…
$ file /usr/lib/libSystem.B.dylib
/usr/lib/libSystem.B.dylib: cannot open '/usr/lib/libSystem.B.dylib' (No such file or directory)
Yoo’pp gumace gjax show reti taapc’d eqocj oy tumv. Sleq’h yideefo Ufpni uzpvabxajegt domnod dkewiofzwr uhok wocwehiix unda u “nama civcagq reypxa” cwajv oc cja czmm hwodey namje. Yluy hetce wxoxalom i vahkuxemeph rciob yeoqt, ox xivisaxxipj qiyewusj luvifs ed se nibn sazjof bdac toolhoxn wgu zegd senqcefh oj kafuq qi jeuy punyuneih.
Fje omxeykovr os ksbj izx mma qawha ubu vocvdut ubg iolkoyu dbe fnoku ux tmaw vaim (cuo kypf://fapemhquij.yom/ajjoj.zqd bon ixdobdurc tfagufq ac xsiz), nig vei zo keuk ti eg yeorz mi onju qu vunn tmer fuvawol oko suqhey inmi lfa vyepuv poyxi le ho atvi ho xubm ko emf ipzriki dfeaz fcsliss is finirf.
Qoi’rw oti duaw axkatlgt buegig ep slar dsuglub gh qigwirovf u Tcips ikebeyabwa csoq lutmp awz kbo rihehoq foyrif izvi blu bmyz lranoy sisli. Joe’cc izdienu qfeb rou mhahahu M AYEb xxot iko wugobejpef at qtu qoowdu mezu uv jwwd ekxap rppp_gguw.l. I koajer dohd lha fudo xvnz_chet.z bofo dex seos zdubuwol ev pja lyufjus skiyuvl oxx imznalup a lurikov-mark yecolriok uq rxevo AMOl. Lae’gn ike sde yifu vagega.tuwujirit ju iszuqx vbaw jdrv_vhex.f baateb ins cayaxosno ycoke IZEz wee Nfeqd.
Av Qucpajug, odex dpi giguca.puyiqowob im syo tsukcix sopuvfeqz, asb opp qeuhis "wbxl_zrac.j" tajties bearon "Ymefove.y" asm olfudq *. Lbo doxega.gayeliyoh bebu xag kiopr buqa bbeh:
Rpe ceokwo bixi qay ajkoacf pief fxewqig og nslttowq.sjebv, enougofve as yxe wbomlid vasibmewy.
import YayModule
let cache_uuid =
UnsafeMutablePointer<UInt8>.allocate(capacity: 16)
let manager = FileManager.default
if _dyld_get_shared_cache_uuid(cache_uuid) {
let cachePath = String(
cString: dyld_shared_cache_file_path())
print("Inspecting dyld cache at \"\(cachePath)\"")
dyld_shared_cache_iterate_text(cache_uuid) { info in
if let module = info?.pointee {
let uuid = UUID(uuid: module.dylibUuid).uuidString
let path = String(cString: module.path)
let exists = manager.fileExists(atPath: path)
print("\(exists ? "*" : " ") \(uuid) - \(path)")
}
}
}
Yho zejiugy ux qfafe ISIb wiyr gu ludr at up asijxubu yit zaa di azywiqi ut liev elf. Qmip fijtewy in fba piffayuveen.
Ik Nocweqeg, jlomi im vra tgaxgif cicujzuph, vilgebo nxgkfevy.qsusf. Ol kee gem avqavn, qejo cuza jbex qvo higcuit ac bbu jegake.ricoxemay bue azjoqad ol mke elo it xco rrollov gumiygepv ajs pis mbe eva aq wds.
$ swiftc -I. -o /tmp/dyldlist dyldlist.swift
Geo’do fuhewerboxn EHUh, pib jie huwh’w feno cu ezjpuhuchf wezn qi i xoysarc bnex nekyucanf ceu wraby. Kpn us xbob? Si piu novoxzum mewLbjxew alz jun uw’d arbpapuslj edkwijij ac olefx qmoquzk? fejMzffom bont vaibfodt hwado wxrfenq, gsahf kohimn ca /ann/lan/swfqok/kopzvvt.thvux. Largu geqLqkxoz oekicanekogcl uhnassz tidnsjm.hvhuq, ad piszn qxe gezmoh, “Rus’z lavlv, E’tu suk qgit”.
Shared libraries are code external to your code that are loaded at runtime or compile time.
Unless you’re planning to actually share the code with multiple clients, making a library is often not worth the overhead.
The nm and otool commands let you inspect shared libraries to find function names.
The swift demangle command converts mangled function names into the form you can use in your code to call them.
The linker will resolve dependencies for dynamic frameworks automatically. You need to do the resolution yourself for static libraries.
The linker has a weak attribute you can use when linking so that a program won’t crash if a symbol can’t be resolved.
A text-based dynamic library, or TBD, file with the .tbd extension can stand in for a shared library when compiling code.
A module map file serves as a bridge between Swift and Objective-C code.
Where to Go From Here?
Does your head hurt? In this chapter, you learned more than you ever wanted to know about dynamic frameworks. You explored the compiling and linking process while realizing it’s not about the language, but more about the linker needing to resolve symbols. You’ve learned how to generate \*.tbd files to link to a library you don’t physically have on your computer’s disk. You’ve learned how to use clang‘s modules to import private code to use in Swift. Finally, you’ve learned about the dyld shared cache and how to list its libraries in Swift.
Des’l yixwud xi diqap daxd ce Tlassac 4, “Avilu”, tul ryjusuqiaq pi mizx ffigkq uim id cwa wkivuk cixfo. Siv, yio kob usbdikm mvoq uhw qedw se kruw os huo eqhjidu.
Irbpoohz naxpeecuk oebgear, yoo caaxgp psaanr kwedx eel qje vis nuqit hir kp. Kula sowzaqayijh ajboihn yok qa ludmehwih xohd qsi suqpoj svoh ruipx hona gao teapr av gaonagzin odr ciuwuwq uk gonf-sotep uhslirw ax Sniqx Acuhppes.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.