Sign in Join
Wiki copytemporary

macOS Static Libraries: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: macOS Static Libraries

OldNewLine
1+## Example FPC static library
2+
3+> **Tip:** If you use "cdecl", FPC ensures that your function completely adheres to all ABI requirements (naming, parameter passing, etc). If you don't, then you are on your own.
4+
5+test.pas:
6+
7+``` pascal
8+{$mode objfpc} {$H+}
9+
10+// Note this is a unit and not a library
11+unit test;
12+
13+interface
14+
15+uses
16+ // needed for UpperCase
17+ SysUtils;
18+
19+implementation
20+
21+// library subroutine
22+function cvtString(strIn : string) : PChar; Cdecl;
23+begin
24+ cvtString := PChar(UpperCase(strIn));
25+end;
26+
27+end.
28+```
29+
30+Compile:
31+
32+` fpc test.pas`
33+
34+which produces an object file named `test.o` which we will now convert into a static library archive named `libtest.a` using the `libtool` command line utility:
35+
36+` libtool -static -o libtest.a test.o`
37+
38+## Example FPC application to use FPC static library
39+
40+statlibdemo.pas:
41+
42+``` pascal
43+{$mode objfpc} {$H+}
44+
45+// Link in our static library
46+// - note the prefix (lib) and extension (.a) are not necessary
47+{$LinkLib test}
48+
49+program statlibdemo;
50+
51+// Declare our function
52+function cvtString(strIn : string) : PChar; Cdecl; External Name 'cvtString';
53+
54+begin
55+ WriteLn(cvtString('hello world'));
56+end.
57+```
58+
59+Compile:
60+
61+` fpc statlibdemo.pas`
62+
63+which unexpectedly produces:
64+
65+```text
66+Free Pascal Compiler version 3.3.1 [2020/04/20] for x86_64
67+Copyright (c) 1993-2020 by Florian Klaempfl and others
68+Target OS: Darwin for x86_64
69+Compiling staticlibdemo.pas
70+Assembling (pipe) staticlibdemo.s
71+Linking staticlibdemo
72+Undefined symbols for architecture x86_64:
73+ "_cvtString", referenced from:
74+ _PASCALMAIN in staticlibdemo.o
75+ld: symbol(s) not found for architecture x86_64
76+An error occurred while linking
77+staticlibdemo.pas(11,34) Error: Error while linking
78+staticlibdemo.pas(11,34) Fatal: There were 1 errors compiling module, stopping
79+Fatal: Compilation aborted
80+Error: /usr/local/bin/ppcx64 returned an error exitcode
81+```
82+
83+What happened? Why wasn't our library function `cvtString` found? Let's look for our function in the `test.o` object file by running the `objdump` command line utility:
84+
85+``` asm
86+$ objdump -d test.o
87+test.o: file format Mach-O 64-bit x86-64
88+
89+Disassembly of section __TEXT,__text:
90+_TEST_$$_CVTSTRING$ANSISTRING$$PCHAR:
91+ 0: 55 pushq %rbp
92+ 1: 48 89 e5 movq %rsp, %rbp
93+ 4: 48 8d 64 24 80 leaq -128(%rsp), %rsp
94+ 9: 48 89 7d f8 movq %rdi, -8(%rbp)
95+ d: 48 8b 7d f8 movq -8(%rbp), %rdi
96+ 11: e8 00 00 00 00 callq 0 <_TEST_$$_CVTSTRING$ANSISTRING$$PCHAR+0x16>
97+ 16: 48 c7 45 88 00 00 00 00 movq $0, -120(%rbp)
98+ 1e: 48 8d 55 d8 leaq -40(%rbp), %rdx
99+ 22: 48 8d 75 98 leaq -104(%rbp), %rsi
100+ 26: bf 01 00 00 00 movl $1, %edi
101+ 2b: e8 00 00 00 00 callq 0 <_TEST_$$_CVTSTRING$ANSISTRING$$PCHAR+0x30>
102+ 30: 48 89 c7 movq %rax, %rdi
103+ 33: e8 00 00 00 00 callq 0 <_TEST_$$_CVTSTRING$ANSISTRING$$PCHAR+0x38>
104+ 38: 48 63 d0 movslq %eax, %rdx
105+ 3b: 48 89 55 90 movq %rdx, -112(%rbp)
106+ 3f: 83 f8 00 cmpl $0, %eax
107+ 42: 75 22 jne 34 <_TEST_$$_CVTSTRING$ANSISTRING$$PCHAR+0x66>
108+ 44: 48 8b 75 f8 movq -8(%rbp), %rsi
109+ 48: 48 8d 7d 88 leaq -120(%rbp), %rdi
110+ 4c: e8 00 00 00 00 callq 0 <_TEST_$$_CVTSTRING$ANSISTRING$$PCHAR+0x51>
111+ 51: 48 8b 45 88 movq -120(%rbp), %rax
112+ 55: 48 83 f8 00 cmpq $0, %rax
113+ 59: 75 07 jne 7 <_TEST_$$_CVTSTRING$ANSISTRING$$PCHAR+0x62>
114+ 5b: 48 8b 05 00 00 00 00 movq (%rip), %rax
115+ 62: 48 89 45 f0 movq %rax, -16(%rbp)
116+ 66: e8 00 00 00 00 callq 0 <_TEST_$$_CVTSTRING$ANSISTRING$$PCHAR+0x6b>
117+ 6b: 48 8d 7d f8 leaq -8(%rbp), %rdi
118+ 6f: e8 00 00 00 00 callq 0 <_TEST_$$_CVTSTRING$ANSISTRING$$PCHAR+0x74>
119+ 74: 48 8d 7d 88 leaq -120(%rbp), %rdi
120+ 78: e8 00 00 00 00 callq 0 <_TEST_$$_CVTSTRING$ANSISTRING$$PCHAR+0x7d>
121+ 7d: 48 8b 45 90 movq -112(%rbp), %rax
122+ 81: 48 83 f8 00 cmpq $0, %rax
123+ 85: 74 0f je 15 <_TEST_$$_CVTSTRING$ANSISTRING$$PCHAR+0x96>
124+ 87: e8 00 00 00 00 callq 0 <_TEST_$$_CVTSTRING$ANSISTRING$$PCHAR+0x8c>
125+ 8c: 48 c7 45 90 00 00 00 00 movq $0, -112(%rbp)
126+ 94: eb d0 jmp -48 <_TEST_$$_CVTSTRING$ANSISTRING$$PCHAR+0x66>
127+ 96: 48 8b 45 f0 movq -16(%rbp), %rax
128+ 9a: 48 89 ec movq %rbp, %rsp
129+ 9d: 5d popq %rbp
130+ 9e: c3 retq
131+```
132+
133+Aha! Our function name has been well and truly mangled. It is obvious we need to use the mangled name `TEST_$$_CVTSTRING$ANSISTRING$$PCHAR` (omit the underscore as the linker will automatically add it) rather than the unmangled `cvtString`. Our example application now looks like:
134+
135+``` pascal
136+{$mode objfpc} {$H+}
137+
138+// Link in our static library
139+// - note the prefix (lib) and extension (.a) are not necessary
140+{$LinkLib test}
141+
142+program statlibdemo;
143+
144+// Declare our function
145+function cvtString(strIn : string) : PChar; Cdecl; External Name 'TEST_$$_CVTSTRING$ANSISTRING$$PCHAR';
146+
147+begin
148+ WriteLn(cvtString('hello world'));
149+end.
150+```
151+
152+Compile:
153+
154+` fpc statlibdemo.pas`
155+
156+which again dashes our hopes and produces:
157+
158+```text
159+Free Pascal Compiler version 3.3.1 [2020/04/20] for x86_64
160+Copyright (c) 1993-2020 by Florian Klaempfl and others
161+Target OS: Darwin for x86_64
162+Compiling staticlibdemo.pas
163+Assembling (pipe) staticlibdemo.s
164+Linking staticlibdemo
165+Undefined symbols for architecture x86_64:
166+ "_SYSUTILS_$$_UPPERCASE$ANSISTRING$$ANSISTRING", referenced from:
167+ _TEST_$$_CVTSTRING$ANSISTRING$$PCHAR in libtest.a(test.o)
168+ld: symbol(s) not found for architecture x86_64
169+An error occurred while linking
170+staticlibdemo.pas(11,34) Error: Error while linking
171+staticlibdemo.pas(11,34) Fatal: There were 1 errors compiling module, stopping
172+Fatal: Compilation aborted
173+Error: /usr/local/bin/ppcx64 returned an error exitcode
174+```
175+
176+Unfortunately we are missing the object file for the `UpperCase` function which was pulled in from the FPC SysUtils unit. What to do? Simply add the SysUtils unit to the the Uses clause of the application. Our example application now looks like:
177+
178+``` pascal
179+{$mode objfpc} {$H+}
180+
181+// Link in our static library
182+// - note the prefix (lib) and extension (.a) are not necessary
183+{$LinkLib test}
184+
185+program statlibdemo;
186+
187+// Needed for linking in the UpperCase function
188+Uses
189+ SysUtils;
190+
191+// Declare our function
192+function cvtString(strIn : string) : PChar; Cdecl; External Name 'TEST_$$_CVTSTRING$ANSISTRING$$PCHAR';
193+
194+begin
195+ WriteLn(cvtString('hello world'));
196+end.
197+```
198+
199+Third time lucky, compile:
200+
201+` fpc statlibdemo.pas`
202+
203+Run:
204+
205+``` bash
206+$ ./statlibdemo
207+HELLO WORLD
208+```
209+
210+## Example C static library
211+
212+myfunc1.c
213+
214+``` c
215+#include <stdio.h>
216+
217+void myfunc1()
218+ {
219+ printf("This is my func1!\n");
220+ }
221+```
222+
223+myfunc2.c
224+
225+``` c
226+#include <ctype.h>
227+
228+int myfunc2(int c)
229+ {
230+ c = toupper(c);
231+ return(c);
232+ }
233+```
234+
235+Compile:
236+
237+> **Note:** If you do not specify the minimum macOS version, the C compiler will compile for your current operating system version, but your Free Pascal Compiler will compile for 10.5 (FPC 3.0.4) or 10.8 (FPC 3.2.0 and later) by default.
238+
239+`cc -c -mmacosx-version-min=10.8 myfunc1.c myfunc2.c`
240+
241+which produces object files named myfunc1.o and myfunc2.o which we will now convert into a static library archive named `libmyfuncs.a` using the `libtool` command line utility:
242+
243+`libtool -static -o libmyfuncs.a myfunc1.o myfunc2.o`
244+
245+## Example FPC application to use C static library
246+
247+statlibdemo.pas:
248+
249+``` pascal
250+{$mode objfpc}
251+{$linklib myfuncs}
252+
253+procedure myfunc1; cdecl; external;
254+function myfunc2(c : integer) : integer; cdecl; external;
255+
256+begin
257+ myfunc1;
258+
259+ write('This is my func2 - Before: "b" ');
260+ writeLn('After : ' + '"' + chr(myfunc2(ord('b'))) + '"');
261+end.
262+```
263+
264+Compile:
265+
266+`fpc statlibdemo.pas`
267+
268+Run:
269+
270+``` bash
271+$ ./statlibdemo
272+This is my func1!
273+This is my func2 - Before: "b" After : "B"
274+```
275+
276+If you need to check whether your external routines have been linked into the final application, you can use the `objdump` command line utility:
277+
278+``` asm
279+$ objdump -d staticlibdemo | grep -A13 ^_myfunc
280+_myfunc1:
281+100000830: 55 pushq %rbp
282+100000831: 48 89 e5 movq %rsp, %rbp
283+100000834: 48 83 ec 10 subq $16, %rsp
284+100000838: 48 8d 3d 7f 44 02 00 leaq 148607(%rip), %rdi
285+10000083f: b0 00 movb $0, %al
286+100000841: e8 e6 3d 02 00 callq 146918 <dyld_stub_binder+0x10002462c>
287+100000846: 89 45 fc movl %eax, -4(%rbp)
288+100000849: 48 83 c4 10 addq $16, %rsp
289+10000084d: 5d popq %rbp
290+10000084e: c3 retq
291+10000084f: 90 nop
292+
293+_myfunc2:
294+100000850: 55 pushq %rbp
295+100000851: 48 89 e5 movq %rsp, %rbp
296+100000854: 48 83 ec 10 subq $16, %rsp
297+100000858: 89 7d fc movl %edi, -4(%rbp)
298+10000085b: 8b 7d fc movl -4(%rbp), %edi
299+10000085e: e8 29 3e 02 00 callq 146985 <dyld_stub_binder+0x10002468c>
300+100000863: 89 45 fc movl %eax, -4(%rbp)
301+100000866: 8b 45 fc movl -4(%rbp), %eax
302+100000869: 48 83 c4 10 addq $16, %rsp
303+10000086d: 5d popq %rbp
304+10000086e: c3 retq
305+10000086f: 90 nop
306+```
307+
308+If you don't care for the assembly language, you can also use the `nm` command line utility:
309+
310+``` bash
311+nm staticlibdemo | grep myfunc
312+0000000100000830 T _myfunc1
313+0000000100000850 T _myfunc2
314+```
315+
316+## See also
317+
318+- [[macOS Dynamic Libraries]] for the same FPC library being used as a dynamic library.
319+- [[macOS Frameworks]] - structured directories for dynamic libraries and associated resources.
320+- [[macOS Programming Tips|macOS Libraries]].
321+
322+---
323+*From the Free Pascal wiki, page "macOS Static Libraries", as it stood on 2022-02-04 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history