PDFium komponentė randa savąją biblioteką per fiksuotą, surūšiuotą paieškos grandinę, o ne palieka tai operacinės sistemos įkėlikliui, nes aiškus diegimo medis yra diegimo medis, kurį galite derinti. Windows ji ieško Win32 arba Win64 pakatalogio, kurį jau tiekia įdiegimo programa. Kitose paskirtyse ji stato pakatalogio vardą iš Free Pascal paskirties makroesų, kaip <cpu>-<os>, todėl diegimo medis skaitosi lygiai kaip sukompiliuotų modulių medis. Tas paskutinis sprendimas įvedė klaidą, vertą viso straipsnio, nes priežastis buvo didžioji raidė, o simptomas — tyla
Grandinė, tvarka
Keturių vietų, bandomų seka, tada platformos įkėliklis kaip paskutinė priemonė. Pirma pageidaujama išdėstytis — DLLs katalogas greta vykdomojo failo su vienu pakatalogiu paskirčiai. Antra alternatyvi išdėstytis su paskirties pakatalogiu tiesiai greta vykdomojo failo. Trečia plokščioji senoji išdėstytis — biblioteka greta vykdomojo failo be jokio pakatalogio. Ketvirta, tik Windows, sistemos katalogas, reikalaujantis atsargos, nes 32 bitų procesas privalo žiūrėti SysWOW64, o 64 bitų procesas — System32, o 32 bitų Windows pastarasis neegzistuoja, todėl paieška turi nukristi atgal. Tik po viso to įkėliklis prašomas ieškoti pats
Už Windows ribų sąmoningai nėra sistemos katalogo žingsnio. Pačios platformos įkėliklio paieškos kelias, valdomas vykdymo laiko linkerio konfigūracijos ir bibliotekų kelių aplinkos, jau dengia tą plotą, ir jo dubliavimas Pascal reikštų taisyklių, kintančių pagal distribuciją, įgyvendinimą iš naujo. Nesėkmių Windows grandinėje diagnostika atskirai dengiama PDFium DLL diegimo ir įkėlimo nesėkmių diagnostikos straipsnyje
Iš kur atkeliauja pakatalogio vardas
Windows tai Win32 arba Win64, sprendžiama pagal besileidžiančio proceso bitumą, o ne pagal operacinės sistemos, nes būtent tai nulemia, kurį dvejetainį failą galima įkelti. Visur kitur vardas statomas iš kompiliatoriaus paskirties makroesų, kad mašina, statanti dviem architektūroms, duotų dvi aiškiai atskirtas medžio struktūras, ir kad aplankas, laikantis savosios bibliotekos, sėdėtų greta aplanko, laikančio sukompiliuotus modulius, tokiu pačiu vardu
function BuildDllSubDir(UseV8: Boolean): string;
begin
{$IFDEF MSWINDOWS}
if IsWin64 then
Result := 'Win64'
else
Result := 'Win32';
{$ELSE}
// Kompiliatoriaus makroesės rašo OS didžiąja raide („Linux“, „Darwin“),
// o paketo modulių išvesties katalogas — ne, todėl abu sutampa tik po
// suvienodinimo. Raidžių dydį skiriančioje failų sistemoje tas skirtumas
// yra visa paieška
Result := LowerCase({$I %FPCTARGETCPU%} + '-' + {$I %FPCTARGETOS%});
{$ENDIF}
end;
Kodėl viena didžioji raidė sugriovė visą grandinę
Kompiliatoriaus makroesė rašo paskirties operacinę sistemą su pradine didžiąja raide: Win64, Linux, Darwin. Lazarus paketas rašo savo modulių išvestį į katalogą, pavadintą pagal savo paskirties kintamąjį, kuris mažosiomis: win64, linux, darwin. Dvi to paties dalyko rašybos, ir nė kaip pastebėti Windows, kur failų sistema jų neskiria
Linux tai du skirtingi katalogai. Diegimas, padedantis bendro naudojimo objektą į DLLs/x86_64-linux, yra nematomas įkėlikliui, ieškančiam DLLs/x86_64-Linux, todėl visi keturi aiškūs grandinės žingsniai praleidžia, ir kodas nukrenta iki platformos įkėliklio paieškos leidimo. Kartais tai veikia, jeigu biblioteka atsitiktinai įdiegta sistemos lygiu, o kartais ne, ir bet kuriuo atveju kruopščiai sudėliotas diegimo medis neduoda nieko. Nesėkmė neturi klaidos pranešimo, nes nesugedo niekas: kiekvienas žingsnis teisingai pranešė, kad failo ten, kur jis žiūrėjo, nėra
Zondo programa, sukompiliuota ir paleista
Toks klaidos tipas negali būti rastas skaitant, ir negali būti rastas kompiliuojant. Įprasta technika patikrinti platformos šaką, kuri niekada nesukompiliuoja kūrimo mašinoje, yra nukopijuoti modulį į laikinąjį katalogą, pervadinti jį, pakeisti platformos sąlygą niekada neapibrėžtu simboliu ir sukompiliuoti kopiją; jei sukompiliuoja, uses sakinys ir iškvietimų parašai tame kelyje bent savi nuoseklūs. Tai gerai veikia savaip uždarą modulį
Čia tai neveikia. Pagrindinis susiejimo modulis labai didelis ir patraukia LCL, todėl jo negalima paprasčiausiai nukopijuoti ir sukompiliuoti išjungus Windows simbolį. Vietoje to saujelė funkcijų, kurių palietė pakeitimas, buvo perrašyta iki žodžio į mažą savaip uždarą programą, ir ta programa buvo paleista. Ji išspausdino x86_64-Win64, ir nesutapimas buvo matomas vienoje išvesties eilutėje. Tos pačios programos kompiliavimas nebūtų pasakęs nieko, nes eilutė visiškai teisėta; neteisinga tik jos reikšmė
program ProbeSubDir;
{$MODE DELPHI}
uses
SysUtils;
begin
// Spausdinkite, neteiginkite. Esmė pažiūrėti, į kokią reikšmę makroesė
// iš tikrųjų išsiskleidžia šioje įrankių grandinėje
Writeln('raw: ', {$I %FPCTARGETCPU%}, '-', {$I %FPCTARGETOS%});
Writeln('folded: ', LowerCase({$I %FPCTARGETCPU%} + '-' +
{$I %FPCTARGETOS%}));
end.
Bendra pamoka: kai tarpplatformis pakeitimas liečia kažko reikšmę, o ne jo tipą, tik kompiliavimo patikra nėra patikra. Spausdinkite ją. Platesnis tarpkompiliatorių skirtumų tarp Delphi ir Free Pascal rinkinys surinktas Delphi ir FPC tarpkompiliatorių spąstų straipsnyje
Leiskite platformai paaiškinti savas įkėlimo nesėkmes
Įkėliklio Windows šaka rankomis išvardija priežastis, kuriomis įkėlimas gali nepavykti, nes ten naudingos išskirtys — architektūros nesutapimas, dingusi percheinė priklausomybė, neišsiskleidžiantis kelias — atitinka klaidų kodus, vertus įvardinti atskirai. Už Windows ribų perkeliamasis įkėliklio modulis jau grąžina aprašomąją eilutę, dengiančią tą patį plotą, todėl nebūsianti Windows šaka ją naudoja tiesiogiai, vietoj iš naujo išvedimo kategorijų iš klaidos numerio, reiškiančio skirtingus dalykus skirtingose sistemose
Atsilaikymas prieš norą tuos du suvienodinti į vieną pranešimą yra sąmoningas. Įkėlimo nesėkmė yra diegimo problema, ir žmogui, skaitančiam pranešimą, reikia pačios platformos žodyno, kuriuo ieškoti
Vardų susidūrimas, kuris rekursuoja
Dar vieni spąstai, maži ir aštrūs. Perkeliamasis įkėliklio modulis eksportuoja procedūrą, vadinamą UnloadLibrary, o susiejimo modulis turi to paties vardo procedūrą, prieš atleidžianti rankenėlę atliekančią savą apskaitą. Tos procedūros viduje nekvalifikuotas UnloadLibrary iškvietimas išsiskleidžia į tą, esančią esamame modulyje, kuri kviečia save. Pataisa — kvalifikuoti iškvietimą modulio vardu
Tai tos pačios formos kaip identifikatorių užtemdymo problemos, dominuojančios Free Pascal perkeliamumuose apskritai: Windows modulis eksportuoja sveikojo tipo minimumo ir maksimumo funkcijas, užtemdžiančias slankiojo kablelio, ir sinchronizavimo tipą, užtemdžiantį to paties vardo klasę, ir kiekvienu atveju išsiskleidimas priklauso nuo uses sakinio tvarkos. Iškvietimo vietos kvalifikavimas yra pataisa, nepriklausanti nuo to, kad kas nors vėliau išsaugos tą tvarką
Diegimo kontrolinis sąrašas
Trys dalykai sudaro daugumą įkėlimo nesėkmių, kai kelio aritmetika teisinga. Architektūra privalo atitikti procesą, o ne mašiną, todėl 32 bitų programa 64 bitų Windows reikalauja 32 bitų dvejetainio failo. V8 įjungtas statymas turi kitokį failo vardą, todėl diegimas, juos sumaišantis, atrodys teisingai ir nieko neįkels. Ir tik vienas variantas gali gyventi sistemos kataloge vienu metu, kas yra gera priežastis teikti pirmenybę aiškiai pakatalogio išdėstyčiai vietoj ko nors sistemos lygio diegimo
Lazarus atveju konkrečiai padėkite savąją biblioteką po DLLs/<cpu>-<os> mažosiomis raidėmis, greta vykdomojo failo, ir ji bus rasta pirmuoju grandinės žingsniu kiekvienoje paskirtyje. Peržiūros programos pavyzdys, tai pratąsantis Lazarus aplinkoje, aprašytas Lazarus ir FPC peržiūros programos straipsnyje, o esamas platformų palaikymas išvardytas PDFium Delphi component produkto puslapyje