{"id":1565,"date":"2014-04-02T22:04:40","date_gmt":"2014-04-02T20:04:40","guid":{"rendered":"http:\/\/blog.benny-baumann.de\/?p=1565"},"modified":"2014-04-02T22:06:23","modified_gmt":"2014-04-02T20:06:23","slug":"statische-freepascal-bibliotheken-mit-gcc-verwenden","status":"publish","type":"post","link":"https:\/\/blog.benny-baumann.de\/?p=1565","title":{"rendered":"Statische FreePascal-Bibliotheken mit GCC verwenden"},"content":{"rendered":"<p>Nachdem Martok nach <a href=\"http:\/\/stackoverflow.com\/help\/badges\/63\/tumbleweed\">Erhalt des Tumbleweed-Awards<\/a> bereits drohte, <a href=\"http:\/\/stackoverflow.com\/questions\/22770389\/create-a-statically-linkable-library-in-freepascal\">auf dessen goldene Ausf\u00fchrung zuzusteuern<\/a>, und ich f\u00fcr <a href=\"https:\/\/github.com\/BenBE\/mod_gnutls\">eines meiner Projekte<\/a> eh noch mal etwas Unterst\u00fctzung brauchte, habe ich mich mal des Cases angenommen, um zu schauen, wie man Code von FreePascal statisch in sein C-Programm eingebunden bekommt. War auch &#8211; ehrlichgesagt &#8211; nicht ganz uneigenn\u00fctzig, da die betroffene Bibliothek durchaus f\u00fcr eigene Projekte bereits ins Auge gefasst wurde, nur wegen &#8222;falsche Programmiersprache&#8220; bisher noch nicht n\u00e4her betrachtet wurde.<!--more--><\/p>\n<p>Aber zur\u00fcck zum Thema. Alles fing damit an, dass sich Martok dar\u00fcber beschwerte, dass das Linken von FreePascal-Code zwar zu dynamischen Libs funktioniert, nicht aber das bauen statischer Bibliotheken. Das Linken dynamischer Bibliotheken ist dabei ein simples <\/p>\n<pre lang=\"bash\">fpc example.lpr<\/pre>\n<p>um die passende libexample.so zu erhalten, aber der Versuch eine zugeh\u00f6rige example.a f\u00fcr die Weiterverwendung zum statischen Linken zu erhalten bedarf etwas mehr Kreativit\u00e4t. Also schlage man die zugeh\u00f6rigen Manpages um eine Reihe von Optionen zu erhalten und werfe wahlos gefundene Optionen in die n\u00e4chstbeste Shell. Direkt ins Auge springen hierbei:<\/p>\n<ul>\n<li><strong>-a<\/strong>: Behalte mal alle Assembler-Zwischenergebnisse. Man wei\u00df ja nie, wof\u00fcr man die mal brauchen k\u00f6nnte &#8230;<\/li>\n<li><strong>-al<\/strong>: Und wenn Du schon mal dabei bist, schreib mal paar Zeilennummern mit raus.<\/li>\n<li><strong>-an<\/strong>: Node-Information k\u00f6nnen ja nie schaden. Hau eifach mal mit rein. Egal wof\u00fcr die dann gut sind!<\/li>\n<li><strong>-ar<\/strong>: Register Allocations sind <strong>immer<\/strong> interessant. Her damit!<\/li>\n<li><strong>-at<\/strong>: Auch die tempor\u00e4ren wollen wir wissen.<\/li>\n<li><strong>-AAS<\/strong>: Als Ausgabe bitte irgendwas, was die binutils verstehen &#8230;<\/li>\n<li><strong>-Cg<\/strong>: F\u00fcr statische Bibliotheken m\u00f6chte man PIC haben. Also nehmen wir PIC.<\/li>\n<li><strong>-CD<\/strong>: Dynamisch oder statisch. Das sagt was von Bibliothek, kann also nicht falsch sein!<\/li>\n<li><strong>-Cn<\/strong>: Und der Scherz am statischen Linken ist, dass man nicht linkt. Also bitte den Linker rechts liegen lassen. Danke.<\/li>\n<li><strong>-g<\/strong>: Generier mal bissl Debugger-Infos. Vielleicht m\u00fcssen wir ja nochml mit nem Debugger dran (oder auch nicht)<\/li>\n<li><strong>-gv<\/strong>: Wenn wir grad mal dabei sind, dann kann ein wenig Info f\u00fcr Valgrind nicht schaden<\/li>\n<li><strong>-s<\/strong>: Assemblieren wird eh \u00fcberbewertet. Au\u00dferdem f\u00e4llt dann wenigstens raus, was der da im Hintergrund treibt.<\/li>\n<li><strong>-XS<\/strong>: Statisches Linken &#8230; k\u00f6nnte funktionieren.<\/li>\n<li><strong>-Xt<\/strong>: Wil so sch\u00f6n war. Warum auch nicht doppelt; h\u00e4lt ja bekanntlich besser &#8211; von wegen -static und so \ud83d\ude09<\/li>\n<li><strong>-Rintel<\/strong>: Ich will keine -RATTen bei mir. Dann schon lieber Assembler, den man auch lesen kann. Hab schlie\u00dflich nen Intel(R) drin.<\/li>\n<li><strong>-Sc<\/strong>: Warum nicht. Soll ja eh mal in C verwendet werden.<\/li>\n<li><strong>-Si<\/strong>: Inlining kann NIE schaden<\/li>\n<li><strong>-Sm<\/strong>: Und warum sollte ich auf C-Makros verzichten, die haben mir eh IMMER schon gefehlt!<\/li>\n<li><strong>-us<\/strong>: Gegen die US sollte man immer sein. Und mit ner System-Unit erspart man sich da paar Dinge.<\/li>\n<\/ul>\n<p>Nat\u00fcrlich brauchen wir jetzt noch etwas Source als Grundlage. Nehmen wir also einfach mal folgende Dateien:<\/p>\n<ul>\n<li>Makefile\n<pre lang=\"bash\">\r\n.PHONY: all\r\nall: test.a static\r\n\r\ntest.a: test.o\r\n\tar cru test.a test.o\r\n\r\ntest.s: test.lpr\r\n\tfpc -a -al -an -ar -at -AAS -Cg -Cn -g -gv -s -XS -Xt -Rintel -Sc -Si -Sm -us test.lpr\r\n\r\ntest.o: test.s\r\n\tas --64 -o test.o test.s\r\n\r\nstatic: static.o\r\n\tgcc -o static static.o test.a\r\n\r\nstatic.o: static.c\r\n\tgcc -c -o static.o static.c\r\n\r\n.PHONY: clean\r\nclean:\r\n\t-rm -f *.s\r\n\t-rm -f *.o\r\n\t-rm -f *.a\r\n\t-rm -f *.ppu\r\n\t-rm -f static.o\r\n\t-rm -f static\r\n\t-rm -f lib*.*\r\n\t-rm -f ppas.*\r\n<\/pre>\n<\/li>\n<li>test.lpr\n<pre lang=\"delphi\">\r\nlibrary test;\r\n\r\n{$mode objfpc}{$H+}\r\n\r\nuses\r\n    ctypes;\r\n\r\nfunction GetAnswer: cint; stdcall;\r\nbegin\r\n    Result:= 42;\r\nend;\r\n\r\nexports\r\n    GetAnswer;\r\n\r\nend.\r\n<\/pre>\n<\/li>\n<li>static.c\n<pre lang=\"c\">\r\n#include <stdint .h>\r\n#include <stdio .h>\r\n\r\n\/\/Import from FreePascal\r\nextern uint32_t GetAnswer();\r\n\r\nint main( int argc, char** argv ) {\r\n\tuint32_t answer;\r\n\r\n\tanswer = GetAnswer();\r\n\tprintf(\"%d\\n\", answer);\r\n\r\n\treturn answer;\r\n}\r\n<\/stdio><\/stdint><\/pre>\n<\/li>\n<\/ul>\n<p>Erster Anlauf war nat\u00fcrlich auch gegen die test.lpr vom Kumpel und wie zu erwarten knallte das auch gleich:<\/p>\n<pre lang=\"text\">\r\nfpc -a -al -an -ar -at -AAS -Cg -Cn -g -gv -s -XS -Xt -Rintel -Sc -Si -Sm -us test.lpr\r\nas --64 -o test.o test.s\r\nar cru test.a test.o\r\ngcc -c -o static.o static.c\r\ngcc -o static static.o test.a\r\ntest.a(test.o): In Funktion `P$TEST_main':\r\n\/mnt\/home\/Projekte\/tmp\/fpc-static\/\/test.lpr:16: Nicht definierter Verweis auf `FPC_LIBINITIALIZEUNITS'\r\ntest.a(test.o):(.fpc+0x0): Nicht definierter Verweis auf `FPC_LIB_EXIT'\r\ntest.a(test.o):(.data.rel+0x10): Nicht definierter Verweis auf `INIT$_SYSTEM'\r\ntest.a(test.o):(.data.rel+0x20): Nicht definierter Verweis auf `INIT$_CMEM'\r\ntest.a(test.o):(.data.rel+0x28): Nicht definierter Verweis auf `FINALIZE$_CMEM'\r\ntest.a(test.o):(.data.rel+0x38): Nicht definierter Verweis auf `FINALIZE$_OBJPAS'\r\ntest.a(test.o):(.data.rel+0x44): Nicht definierter Verweis auf `THREADVARLIST_SYSTEM'\r\ntest.a(test.o):(.data.rel+0x4c): Nicht definierter Verweis auf `THREADVARLIST_CMEM'\r\ntest.a(test.o):(.data.rel+0x54): Nicht definierter Verweis auf `THREADVARLIST_OBJPAS'\r\ntest.a(test.o):(.data.rel+0x5c): Nicht definierter Verweis auf `THREADVARLIST_UNIXTYPE'\r\ntest.a(test.o):(.data.rel+0x64): Nicht definierter Verweis auf `THREADVARLIST_CTYPES'\r\ncollect2: error: ld returned 1 exit status\r\nmake: *** [static] Fehler 1\r\n<\/pre>\n<p>Sieht ja schon mal nicht schlecht aus, aber warum brauch der die zus\u00e4tzlichen Symbole f\u00fcr die Initializer und Finalizer? Und \u00fcberhaupt: Warum definiert der da ne main? Das soll der gar nicht!!! Na gut, probieren wir das (neben zahlreichen anderen Dingen, die ich dem Leser an dieser Stelle einfach mal erspare, weil sie eh nicht funktionieren und nicht zielf\u00fchrend sind) was statische Lib-Archive im Gegensatz zu Projekt-Dateien, die fertige Programme darstellen. Was wohl passiert, wenn man ihm statt der Project-File wohl eine Pascal-Unit zum Fra\u00df hinwirft? Naja, probieren wir mal. \u00c4ndern wir hierzu die test.lpr durch etwas \u00c4ndern von Compiler-Direktiven in eine Unit um, was dann so in etwa wie dies hier aussieht:<\/p>\n<pre lang=\"pascal\">\r\nunit test;\r\n\r\n{$mode objfpc}{$H+}\r\n\r\ninterface\r\n\r\nuses\r\n  ctypes;\r\n\r\nfunction GetAnswer: cint; stdcall;\r\n\r\nimplementation\r\n\r\nfunction GetAnswer: cint; stdcall;\r\nbegin\r\n  Result:= 42;\r\nend;\r\n\r\n\/\/exports\r\n\/\/  GetAnswer;\r\n\r\nend.\r\n<\/pre>\n<p>und ersetzen im Makefile mal die Vorkommen von test.lpr durch test.pas, was uns folgendes Makefile beschert:<\/p>\n<pre lang=\"bash\">\r\n.PHONY: all\r\nall: test.a static\r\n\r\ntest.a: test.o\r\n\tar cru test.a test.o\r\n\r\ntest.s: test.pas\r\n\tfpc -a -al -an -ar -at -AAS -Cg -Cn -g -gv -s -XS -Xt -Rintel -Sc -Si -Sm -us test.pas\r\n\r\ntest.o: test.s\r\n\tas --64 -o test.o test.s\r\n\r\nstatic: static.o\r\n\tgcc -o static static.o test.a\r\n\r\nstatic.o: static.c\r\n\tgcc -c -o static.o static.c\r\n\r\n.PHONY: clean\r\nclean:\r\n\t-rm -f *.s\r\n\t-rm -f *.o\r\n\t-rm -f *.a\r\n\t-rm -f *.ppu\r\n\t-rm -f static.o\r\n\t-rm -f static\r\n\t-rm -f lib*.*\r\n\t-rm -f ppas.*\r\n<\/pre>\n<p>Und wenn man dann kurz neu baut, f\u00e4llt einem ein kleines Binary entgegen:<\/p>\n<pre lang=\"bash\">\r\nfpc -a -al -an -ar -at -AAS -Cg -Cn -g -gv -s -XS -Xt -Rintel -Sc -Si -Sm -us test.pas\r\nFree Pascal Compiler version 2.6.2-5 [2013\/07\/25] for x86_64\r\nCopyright (c) 1993-2012 by Florian Klaempfl and others\r\nTarget OS: Linux for x86-64\r\nCompiling test.pas\r\nClosing script ppas.sh\r\n23 lines compiled, 0.0 sec \r\nas --64 -o test.o test.s\r\nar cru test.a test.o\r\ngcc -c -o static.o static.c\r\ngcc -o static static.o test.a\r\n<\/pre>\n<p>Bliebe nur noch die Antwort auf die entscheidende Frage abzuwarten:<\/p>\n<pre lang=\"bash\">$ .\/static\r\n42<\/pre>\n<p>Geht doch!<\/p>\n<p>Na gut. Windows ist mal wieder die Ausnahme, weshalb Martok auch noch daruaf hinwies, dass man im Pascal-Teil vermutlich eher folgendes Nutzen m\u00f6chte:<\/p>\n<pre lang=\"pascal\">\r\nconst\r\n{$IFDEF WIN32}\r\n  prefix = '_';\r\n{$ELSE}\r\n  prefix = '';\r\n{$ENDIF}\r\n\r\nfunction GetAnswer: cint; cdecl; public name prefix+'GetAnswer';\r\n<\/pre>\n<p>Problem gel\u00f6st, und jetzt wieder zur\u00fcck ans Debugging \ud83d\ude09<\/p>\n<p class=\"wp-flattr-button\"><a href=\"https:\/\/blog.benny-baumann.de\/?flattrss_redirect&amp;id=1565&amp;md5=14f624f75907d9c44f20511de65b1d5f\" title=\"Flattr\" target=\"_blank\"><img src=\"http:\/\/blog.benny-baumann.de\/wp-content\/plugins\/flattr\/img\/flattr-badge-large.png\" srcset=\"http:\/\/blog.benny-baumann.de\/wp-content\/plugins\/flattr\/img\/flattr-badge-large.png\" alt=\"Flattr this!\"\/><\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>Nachdem Martok nach Erhalt des Tumbleweed-Awards bereits drohte, auf dessen goldene Ausf\u00fchrung zuzusteuern, und ich f\u00fcr eines meiner Projekte eh noch mal etwas Unterst\u00fctzung brauchte, habe ich mich mal des Cases angenommen, um zu schauen, wie man Code von FreePascal statisch in sein C-Programm eingebunden bekommt. War auch &#8211; ehrlichgesagt &#8211; nicht ganz uneigenn\u00fctzig, da [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[29],"tags":[14,98,347,342,13,41],"class_list":["post-1565","post","type-post","status-publish","format-standard","hentry","category-software","tag-bugs","tag-developement","tag-fun","tag-pascal","tag-patch","tag-spas"],"_links":{"self":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/1565","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1565"}],"version-history":[{"count":2,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/1565\/revisions"}],"predecessor-version":[{"id":1567,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/1565\/revisions\/1567"}],"wp:attachment":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1565"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1565"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1565"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}