A PDFium komponens rögzített, rendezett keresőláncon át találja meg a natív függvénytárát, nem pedig az operációs rendszer betöltőjére bízva, mert egy explicit telepítési fa olyan telepítési fa, amelyet hibakeresni lehet. Windowson az a lánc egy Win32 vagy Win64 alkönyvtárat keres, amelyet a telepítő már szállít. Más célokon az alkönyvtár nevét a Free Pascal cél-makróiból építi, <cpu>-<os> alakban, tehát a telepítési fa pontosan úgy olvasható, mint a lefordított egység fája. Az az utolsó döntés vezetett be egy hibát, amely megéri az egész cikket, mert az ok egy nagybetű volt, a tünet pedig csend
A lánc, sorrendben
Négy hely, sorrendben kipróbálva, majd a platformbetöltő mint utolsó menedék. Először a preferált elrendezés, egy DLLs könyvtár a végrehajtható mellett, célonként egy alkönyvtárral. Másodszor egy alternatív elrendezés, a célalkönyvtárral közvetlenül a végrehajtható mellett. Harmadszor a lapos örökölt elrendezés, a függvénytár a végrehajtható mellett, egyáltalán nem alkönyvtárban. Negyedszer, csak Windowson, a rendszerkönyvtár, amely gondot igényel, mert egy 32 bites folyamatnak a SysWOW64-ben, egy 64 bitesnek a System32-ben kell keresnie, és 32 bites Windowson az előbbi nem létezik, tehát a keresésnek vissza kell esnie. Csak mindez után kérik fel a betöltőt, hogy maga keressen
Szándékosan nincs rendszerkönyvtár lépés Windowson kívül. A platformbetöltő saját keresési útja, amelyet a futásidejű linker konfiguráció és a függvénytár út környezete hajt, már lefedi azt a terepet, és annak Pascalban való megkettőzése olyan szabályok újraimplementálását jelentené, amelyek disztribúciónként változnak. A Windows lánc megbukásainak diagnosztikáját külön tárgyalja a PDFium DLL telepítése és a betöltési hibák diagnosztikája
Honnan jön az alkönyvtár neve
Windowson az Win32 vagy Win64, a futó folyamat bitessége dönt, nem az operációs rendszeré, mert az dönti el, melyik bináris tölthető be. Minden más helyen a név a fordító cél-makróiból épül, hogy egy gép, amely két architektúrára épít, két tisztán elkülönített fát produkáljon, és hogy a natív függvénytárat tartó mappa a lefordított egységeket tartó mappa mellett azonos névvel üljön
function BuildDllSubDir(UseV8: Boolean): string;
begin
{$IFDEF MSWINDOWS}
if IsWin64 then
Result := 'Win64'
else
Result := 'Win32';
{$ELSE}
// A fordító makrói nagybetűvel írják az OS-t („Linux”, „Darwin”), a
// csomagegység kimeneti könyvtára pedig nem, tehát a kettő csak
// kisbetűsítés után egyezik. Kisbetű-nagybetű érzékeny fájlrendszeren
// az a különbség maga a teljes keresés
Result := LowerCase({$I %FPCTARGETCPU%} + '-' + {$I %FPCTARGETOS%});
{$ENDIF}
end;
Miért tört meg egy nagybetű a teljes láncot
A fordító makrója kezdeti nagybetűvel írja a cél operációs rendszert: Win64, Linux, Darwin. A Lazarus csomag az egységkimenetét a saját célváltozójából képzett könyvtárba írja, amely kisbetűs: win64, linux, darwin. Ugyanannak a dolognak két írása, és Windowson nincs mód észrevenni, ahol a fájlrendszer nem különbözteti meg őket
Linuxon két különböző könyvtár. Egy olyan telepítés, amely a megosztott objektumot a DLLs/x86_64-linux helyre teszi, láthatatlan egy DLLs/x86_64-Linux-ot kereső betöltő számára, tehát a lánc mind a négy explicit lépése lemarad, és a kód arra esik vissza, hogy a platformbetöltőre bízza a keresést. Néha az működik, ha a függvénytár véletlenül rendszerszinten telepített, és néha nem, és akárhogy is, a gondosan berendezett telepítési fa semmit sem ad hozzá. A megbukásnak nincs hibaüzenete, mert semmi nem bukott meg: minden lépés helyesen jelentette, hogy a fájl nem ott volt, ahol kereste
A szondaprogram, lefordítva és lefuttatva
Ez a hibaosztály olvasással nem található meg, és fordítással sem. A szokásos technika egy olyan platformág ellenőrzésére, amely a fejlesztőgépen soha nem fordul, az, hogy az egységet ideiglenes könyvtárba másolják, átnevezik, a platformfeltételt egy soha nem definiált szimbólumra cserélik, és a másolatot lefordítják; ha lefordul, az adott út uses szakasza és hívásszignatúrái legalább önkonisztensek. Önálló egységnél jól működik
Itt nem működik. A fő kötő egység nagyon nagy, és behúzza az LCL-t, tehát nem másolható és fordítható egyszerűen a Windows szimbólum kikapcsolásával. Ezért a változtatás által érintett néhány függvényt szó szerint átírták egy kis önálló programba, és azt a programot lefuttatták. Kiírta, hogy x86_64-Win64, és az eltérés egy kimeneti sorban látható volt. Ugyanazon program lefordítása semmit sem mondott volna, mert a karakterlánc tökéletesen érvényes; csak az értéke téves
program ProbeSubDir;
{$MODE DELPHI}
uses
SysUtils;
begin
// Írjon ki, ne állítson elő. A lényeg, hogy megnézze, mire terjed ki
// egy makró valójában ezen az eszközláncon
Writeln('raw: ', {$I %FPCTARGETCPU%}, '-', {$I %FPCTARGETOS%});
Writeln('folded: ', LowerCase({$I %FPCTARGETCPU%} + '-' +
{$I %FPCTARGETOS%}));
end.
Az általános tanulság: amikor egy platformok közötti változtatás valaminek az értékét érinti, nem a típusát, a csak fordításos ellenőrzés nem ellenőrzés. Írassa ki. A Delphi és a Free Pascal közötti szélesebb keresztfordító különbségeket a Delphi és FPC keresztfordító buktatók cikke gyűjti össze
Hagyja, hogy a platform a saját betöltési megbukásait magyarázza
A betöltő Windows ága kézzel sorolja fel azokat az okokat, amelyekért egy betöltés megbukhat, mert ott a hasznos megkülönböztetések — architektúra-eltérés, hiányzó tranzitív függőség, fel nem oldódó út — olyan hibakódokra mennek, amelyeket érdemes egyenként megnevezni. Windowson kívül a hordozható betöltő egység már most is leíró karakterláncot ad vissza, amely ugyanazt a terepet fedi, tehát a nem Windows ág azt használja közvetlenül, nem pedig hibaszámból származtat újra kategóriákat, amely száma rendszerről rendszerre mást jelent
Az a késztetés ellenállása, hogy a kettőt egyetlen üzenetté normalizálják, szándékos. Egy betöltési megbukás telepítési probléma, és az a személy, aki az üzenetet olvassa, a platform saját szókincsére van szüksége, hogy rákeressen
Egy névütközés, amely rekurzál
Még egy csapda, kicsi és éles. A hordozható betöltő egység egy UnloadLibrary nevű eljárást exportál, és a kötő egységnek van ugyanolyan nevű eljárása, amely a handle kiadása előtt a saját könyvelését végzi. Az az eljáráson belül a UnloadLibrary minősítetlen hívása az aktuális egységben lévőre oldódik fel, amely önmagát hívja. A javítás az, hogy a hívást az egység nevével minősítsék
Ez ugyanaz az alak, mint az azonosító-árnyékolási problémák, amelyek általában uralják a Free Pascal portolásokat: a Windows egység egész típusú minimum- és maximumfüggvényeket exportál, amelyek árnyékolják a lebegőpontosakat, és egy szinkronizálási típust, amely árnyékolja az azonos nevű osztályt, és minden esetben a feloldás a uses szakasz sorrendjétől függ. A hívási hely minősítése az a javítás, amely nem függ attól, hogy valaki később megőrzi-e azt a sorrendet
Telepítési ellenőrzőlista
Három dolog magyarázza a legtöbb betöltési megbukást, ha az útszámítás helyes. Az architektúrának a folyamathoz kell illeszkednie, nem a géphez, tehát egy 64 bites Windowson futó 32 bites alkalmazásnak a 32 bites bináris kell. A V8 engedélyezett buildnek más a fájlneve, tehát amelyik keveri őket, az helyesnek fog kinézni, és semmit sem tölt be. És egyszerre csak egy változat élhet rendszerkönyvtárban, ami jó ok arra, hogy az explicit alkönyvtár-elrendezést részesítse előnyben bármilyen rendszerszintű telepítés helyett
Lazarusra kifejezetten: tegye a natív függvénytárat a DLLs/<cpu>-<os> alá kisbetűvel, a végrehajtható mellé, és a lánc első lépése megtalálja minden célon. A Lazaruson ezt kipróbáló megjelenítő mintát a Lazarus és FPC megjelenítő cikk írja le, és az aktuális platformtámogatás a PDFium Delphi component terméklapon található