PDFium komponenta pronalazi svoju izvornu knjižnicu kroz fiksni, uređeni lanac pretraživanja umjesto da to prepusti učitavaču operativnog sustava, jer je stablo raspoređivanja koje je izričito stablo raspoređivanja koje možete otklanjati. Na Windowsu taj lanac traži poddirektorij Win32 ili Win64 koji instalacijski program već isporučuje. Na drugim ciljevima gradi ime poddirektorija iz makronaredbi Free Pascal cilja, kao <cpu>-<os>, pa stablo raspoređivanja čita točno kao stablo kompajliranih jedinica. Ta posljednja odluka uvela je grešku vrijednu cijelog članka, jer je uzrok bilo veliko slovo, a simptom tišina
Lanac, po redu
Četiri lokacije, isprobane u nizu, zatim platformski učitavač kao posljednje utočište. Prvo preferirani raspored, direktorij DLLs uz izvršnu datoteku koji sadrži jedan poddirektorij po cilju. Drugo zamjenski raspored s poddirektorijem cilja izravno uz izvršnu datoteku. Treće ravni naslijeđeni raspored, knjižnica uz izvršnu datoteku bez ikakvog poddirektorija. Četvrto, samo na Windowsu, sistemski direktorij, koji treba pažnje jer 32-bitni proces mora gledati u SysWOW64, a 64-bitni u System32, i na 32-bitnom Windowsu prvi ne postoji pa se traženje mora vratiti. Tek nakon svega toga učitavaču se daje da traži sam
Izvan Windowsa namjerno ne postoji korak sistemskog direktorija. Vlastita putanja pretraživanja platformskog učitavača, vođena konfiguracijom povezivača vremena izvođenja i okruženjem knjižničnih putanja, već pokriva to područje, i dupliciranje u Pascalu značilo bi ponovno implementiranje pravila koja se razlikuju po distribuciji. Dijagnosticiranje neuspjeha u Windows lancu pokriveno je odvojeno u raspoređivanju PDFium DLL-a i dijagnosticiranju neuspjeha učitavanja
Otkud ime poddirektorija
Na Windowsu to je Win32 ili Win64, odlučeno bitnošću procesa koji radi, a ne operativnog sustava, jer to odlučuje koja se binarna datoteka može učitati. Svugdje drugo ime se gradi iz makronaredbi cilja kompajlera tako da stroj koji gradi za dvije arhitekture proizvodi dva jasno odvojena stabla, i tako da mapa koja drži izvornu knjižnicu sjedi uz mapu koja drži kompajlirane jedinice s istim imenom
function BuildDllSubDir(UseV8: Boolean): string;
begin
{$IFDEF MSWINDOWS}
if IsWin64 then
Result := 'Win64'
else
Result := 'Win32';
{$ELSE}
// Kompajlerske makronaredbe pišu OS s velikim početnim slovom ("Linux",
// "Darwin"), a izlazni direktorij jedinice paketa ne, pa se njih dvoje
// slažu tek nakon savijanja malih slova. Na sustavu datoteka koji
// razlikuje velika i mala slova ta je razlika cijelo traženje
Result := LowerCase({$I %FPCTARGETCPU%} + '-' + {$I %FPCTARGETOS%});
{$ENDIF}
end;
Zašto je veliko slovo slomilo cijeli lanac
Kompajlerska makronaredba piše ciljni operativni sustav s početnim velikim slovom: Win64, Linux, Darwin. Lazarusov paket piše svoj izlaz jedinica u direktorij imenovan iz vlastite ciljne varijable, koja je malim slovima: win64, linux, darwin. Dva pravopisa iste stvari, i bez načina da se primijeti na Windowsu, gdje sustav datoteka ne razlikuje ih
Na Linuxu oni su dva različita direktorija. Raspoređivanje koje stavi dijeljeni objekt u DLLs/x86_64-linux nevidljivo je učitavaču koji traži DLLs/x86_64-Linux, pa sva četiri izričita koraka lanca promaše i kôd padne na to da platformski učitavač traži sam. Ponekad to radi, ako se knjižnica slučajno nalazi instalirana cijelim sustavom, i ponekad ne, i u oba slučaja pažljivo uređeno stablo raspoređivanja ne pridonosi ničemu. Neuspjeh nema poruku pogreške jer ništa nije palo: svaki je korak ispravno javio da datoteka nije bila gdje je gledao
Probni program, kompajliran i pokrenut
Ovu klasu grešaka ne može se naći čitanjem, i ne može se naći ni kompajliranjem. Uobičajena tehnika za provjeru platformske grane koja se na razvojnom stroju nikad ne kompajlira jest kopirati jedinicu u privremeni direktorij, preimenovati je, zamijeniti platformski uvjetni izraz simbolom koji nikad nije definiran i kompajlirati kopiju; ako se kompajlira, red uses i potpisi poziva na tom putu barem su samousklađeni. To dobro radi za samodostatnu jedinicu
Ovdje ne radi. Glavna vezivna jedinica vrlo je velika i povlači LCL, pa se ne može jednostavno kopirati i kompajlirati s isključenim Windows simbolom. Umjesto toga šaka funkcija koje je promjena dirala prepisana je doslovno u mali samodostatni program, i taj program je pokrenut. Ispisao je x86_64-Win64, i nepodudarnost bila je vidljiva u jednom retku izlaza. Kompajliranje istog programa ne bi vam reklo ništa, jer je niz savršeno valjan; samo je njegova vrijednost pogrešna
program ProbeSubDir;
{$MODE DELPHI}
uses
SysUtils;
begin
// Ispisujte, ne tvrdite. Poanta je pogledati u što se makronaredba
// stvarno širi na ovom alatnom lancu
Writeln('raw: ', {$I %FPCTARGETCPU%}, '-', {$I %FPCTARGETOS%});
Writeln('folded: ', LowerCase({$I %FPCTARGETCPU%} + '-' +
{$I %FPCTARGETOS%}));
end.
Opća lekcija: kada se višeplatformska promjena tiče vrijednosti nečega umjesto njegova tipa, provjera samo kompajliranjem nije provjera. Ispišite je. Širi skup razlika između kompajlera Delphi i Free Pascal sabran je u članku o zamkama unakrsnog kompajliranja Delphi i FPC
Pustite platformu da objasni vlastite neuspjehe učitavanja
Windows grana učitavača ručno nabraja razloge zbog kojih učitavanje može pasti, jer se korisne razlike tamo, nepodudarnost arhitekture, nedostajuća tranzitivna ovisnost, putanja koja se ne razriješi, preslikavaju u kodove pogrešaka vrijedne pojedinačnog imenovanja. Izvan Windowsa prijenosna jedinica učitavača već vraća opisni niz koji pokriva isto područje, pa ne-Windows grana koristi nju izravno umjesto ponovnog izvođenja kategorija iz broja pogreške koji znači različite stvari na različitim sustavima
Otpor nagonu da se ta dva normaliziraju u jednu poruku namjerni je. Neuspjeh učitavanja problem je raspoređivanja, i osoba koja čita poruku treba vlastiti rječnik platforme da ga potraži
Sudar imena koji se rekurzira
Još jedna zamka, mala i oštra. Prijenosna jedinica učitavača izvozi proceduru nazvanu UnloadLibrary, a vezivna jedinica ima proceduru istog imena koja obavlja vlastito knjigovodstvo prije puštanja handlea. Unutar te procedure nekvalificirani poziv UnloadLibrary razrješuje se na onu u trenutnoj jedinici, koja poziva samu sebe. Ispravak je kvalificirati poziv imenom jedinice
To je isti oblik kao problemi zasjenjivanja identifikatora koji dominiraju prijenosima na Free Pascal općenito: jedinica Windows izvozi cjelobrojno tipizirane funkcije najmanjeg i najvećeg koje zasjenjuju one s pomičnim zarezom, i tip sinkronizacije koji zasjenjuje klasu istog imena, i u svakom slučaju razrješenje ovisi o redoslijedu reda uses. Kvalificiranje mjesta poziva ispravak je koji ne ovisi o tome hoće li netko kasnije očuvati taj redoslijed
Popis provjera raspoređivanja
Tri stvari objašnjavaju većinu neuspjeha učitavanja jednom kad je aritmetika putanja ispravna. Arhitektura mora odgovarati procesu, ne stroju, pa 32-bitna aplikacija na 64-bitnom Windowsu treba 32-bitnu binarnu datoteku. Izgradnja s omogućenim V8-om ima drugo ime datoteke, pa raspoređivanje koje ih pomiješa izgledat će ispravno i neće ništa učitati. I samo jedna varijanta može u isto vrijeme živjeti u sistemskom direktoriju, što je dobar razlog preferirati izričiti raspored poddirektorija nad instaliranjem bilo čega cijelim sustavom
Za Lazarus posebno, smjestite izvornu knjižnicu pod DLLs/<cpu>-<os> malim slovima, uz izvršnu datoteku, i naći će je prvi korak lanca na svakom cilju. Uzorak preglednika koji ovo vježba na Lazarusu opisan je u članku o pregledniku Lazarus i FPC, a trenutna podrška platformi navedena je na stranici proizvoda PDFium Delphi component