Tehnični članak

Nalaganje domorodne knjižnice PDFium na katerem koli cilju

Komponenta PDFium najde svojo domorodno knjižnico skozi fiksno, urejeno verigo iskanja namesto da bi jo prepustila nalagalniku operacijskega sistema, ker je drevo namestitve, ki je izrecno, drevo namestitve, ki ga lahko razhroščujete. Na Windows ta veriga išče podmapo Win32 ali Win64, ki jo namestitveni program že pošilja. Na drugih ciljih zgradi ime podmape iz makrojev cilja Free Pascal, kot <cpu>-<os>, tako da drevo namestitve bere natanko kot drevo prevedenih enot. Ta zadnja odločitev je uvedla hrošča, vrednega celega članka, ker je bil vzrok velika črka in simptom tišina

Veriga, po vrstnem redu

Štiri lokacije, poskušane v zaporedju, nato nalagalnik platforme kot zadnja rešitev. Najprej prednostna razporeditev, mapa DLLs poleg izvedljive datoteke, ki vsebuje eno podmapo na cilj. Drugo alternativna razporeditev s podmapo cilja naravnost poleg izvedljive datoteke. Tretje ravna podedovana razporeditev, knjižnica sedi poleg izvedljive datoteke brez sploh nobene podmape. Četrto, samo na Windows, sistemska mapa, ki potrebuje skrb, ker mora 32-bitni proces gledati v SysWOW64 in 64-bitni proces v System32, in na 32-bitnem Windows prvi ne obstaja, tako da mora iskanje pasti nazaj. Šele po vsem tem je nalagalnik vprašan, naj išče sam

Diagram verige iskanja domorodne knjižnice PDFium za Delphi, od podmape cilja DLLs skozi alternativne, ravne in sistemske razporeditve map Windows do nalagalnika platforme
Štiri izrecne lokacije so sondirane po vrstnem redu, preden je nalagalnik OS vprašan, naj išče sam

Namensko ni koraka sistemske mape zunaj Windows. Lastna iskalna pot nalagalnika platforme, gnana s strani konfiguracije izvajalnega povezovalnika in okolja poti knjižnic, že pokriva to področje, podvajanje nje v Pascalu bi pomenilo ponovno implementiranje pravil, ki se razlikujejo po distribuciji. Diagnosticiranje odpovedi v verigi Windows je pokrito ločeno v namestitvi DLL PDFium in diagnosticiranju odpovedi nalaganja

Od kod pride ime podmape

Na Windows je Win32 ali Win64, odločeno z bitnostjo tekočega procesa in ne operacijskega sistema, ker je to tisto, kar določa, katera binarna datoteka se lahko naloži. Povsod drugje je ime zgrajeno iz makrojev cilja prevajalnika, tako da stroj, ki gradi za dve arhitekturi, proizvede dve jasno ločeni drevesi, in tako, da mapa, ki drži domorodno knjižnico, sedi poleg mape, ki drži prevedene enote, z istim imenom

function BuildDllSubDir(UseV8: Boolean): string;
begin
{$IFDEF MSWINDOWS}
  if IsWin64 then
    Result := 'Win64'
  else
    Result := 'Win32';
{$ELSE}
  // Makroji prevajalnika velikajočajo OS (»Linux«, »Darwin«), izhodna
  // mapa enot paketa pa ne, tako da se ti dve ujemata šele po zlaganju.
  // Na sistemu datotek, občutljivem na velike in male črke, je ta
  // razlika celotno iskanje
  Result := LowerCase({$I %FPCTARGETCPU%} + '-' + {$I %FPCTARGETOS%});
{$ENDIF}
end;

Zakaj je velika črka polomila celo verigo

Makro prevajalnika črkuje ciljni operacijski sistem z začetnico veliko: Win64, Linux, Darwin. Paket Lazarus zapiše svoj izhod enot v mapo, poimenovano iz svoje lastne spremenljivke cilja, ki je mala: win64, linux, darwin. Dve črkovanji iste stvari in noben način opažanja na Windows, kjer sistem datotek ne razlikuje njiju

Na Linuxu sta dve različni mapi. Namestitev, ki da skupni objekt v DLLs/x86_64-linux, je nevidna nalagalniku, ki išče DLLs/x86_64-Linux, tako da vsi štirje izrecni koraki verige zgrešijo in koda pade skozi na pustiti nalagalniku platforme iskati. Včasih to deluje, če je knjižnica slučajno nameščena po celem sistemu, včasih pa ne, in v obeh primerih skrbno urejeno drevo namestitve ne prispeva ničesar. Odpoved nima sporočila napake, ker nič ni odpovedalo: vsak korak je pravilno poročal, da datoteka ni bila tam, kjer je gledal

Kako ena velika črka v makroju cilja FPC polomi iskanje DLL PDFium na Linuxu: nalagalnik išče DLLs/x86_64-Linux, medtem ko je nameščena mapa DLLs/x86_64-linux, kar se ujema samo na Windows, neobčutljivih na velikost črk
Isti cilj, črkovan na dva načina, se ujema na Windows in tiho zgreši na sistemu datotek, občutljivem na velikost črk

Program sonde, preveden in pognan

Ta razred hroščev ni mogoče najti z branjem in ga ni mogoče najti niti s prevajanjem. Običajna tehnika za preverjanje veje platforme, ki se nikoli ne prevede na razvojnem stroju, je kopirati enoto v začasno mapo, jo preimenovati, zamenjati pogoj platforme s simbolom, ki ni nikoli definiran, in prevesti kopijo; če se prevede, so razdelek uses in podpisi klicev na tej poti vsaj samoskladni. To deluje dobro za samozadostno enoto

Tukaj ne deluje. Glavna vezalna enota je zelo velika in vleče LCL noter, zato je ne more preprosto kopirati in prevesti z izklopljenim simbolom Windows. Namesto tega je bila peščica funkcij, ki jih je sprememba dotaknila, prepisana dobesedno v majhen samozadosten program in ta program je bil pognan. Natisnil je x86_64-Win64 in neskladje je bilo vidno v eni vrstici izhoda. Prevajanje istega programa vam ne bi reklo ničesar, ker je niz popolnoma veljaven; samo njegova vrednost je napačna

program ProbeSubDir;
{$MODE DELPHI}
uses
  SysUtils;
begin
  // Natisnite, ne trdite. Točka je pogledati vrednost, v katero se
  // makro dejansko razširi na tej orodjarni
  Writeln('raw:    ', {$I %FPCTARGETCPU%}, '-', {$I %FPCTARGETOS%});
  Writeln('folded: ', LowerCase({$I %FPCTARGETCPU%} + '-' +
    {$I %FPCTARGETOS%}));
end.

Splošna lekcija: ko zadeva sprememba čez platforme vrednost česa in ne njenega tipa, je preverjanje samo-prevajanje ni preverjanje. Natisnite jo. Širši nabor razlik čez prevajalnike med Delphi in Free Pascal je zbran v članku o pasteh čez prevajalnike Delphi in FPC

Pustite platformi razložiti svoje odpovedi nalaganja

Veja Windows nalagalnika ročno oštevilči razloge, ki jih nalaganje lahko odpove, ker se uporabne razlike tam — neskladje arhitektur, manjkajoča tranzitivna odvisnost, pot, ki se ne razreši — preslikajo v kode napak, vredne posameznega poimenovanja. Zunaj Windows prenosljiva enota nalagalnika že vrne opisni niz, ki pokriva isto področje, tako da veja ne-Windows uporabi njega neposredno namesto ponovnega izpeljevanja kategorij iz številke napake, ki pomeni različne stvari na različnih sistemih

Upiranje nagibu, da se ti dve normalizirata v eno sporočilo, je namerno. Odpoved nalaganja je težava namestitve in oseba, ki bere sporočilo, potrebuje lastni besednjak platforme za iskanje njega

Trčenje imen, ki se rekurzira

Še ena past, majhna in ostra. Prenosljiva enota nalagalnika izvozi proceduro, imenovano UnloadLibrary, vezalna enota pa ima proceduro istega imena, ki počne svoje lastno knjigovodstvo pred sprostitvijo ročaja. Znotraj te procedure se nekvalificiran klic UnloadLibrary razreši v tisto v trenutni enoti, ki kliče samo sebe. Popravek je kvalificirati klic z imenom enote

To je ista oblika kot težave sencenja identifikatorjev, ki prevladujejo na prenosih Free Pascal na splošno: enota Windows izvozi funkciji minimum in maksimum celoštevilskega tipa, ki senčita plavajoče-vejične različice, in tip sinhronizacije, ki senči razred istega imena, in v vsakem primeru je razrešitev odvisna od vrstnega reda razdelka uses. Kvalificiranje mesta klica je popravek, ki ni odvisen od tega, da nekdo ohrani ta vrstni red kasneje

Trčenje imen UnloadLibrary v komponenti PDFium: nekvalificiran klic v vezalni enoti Delphi rekurzira v samo, medtem ko enoto-kvalificiran klic doseže prenosljivo enoto nalagalnika in sprosti ročaj
Kvalificiranje mesta klica pošlje sprostitev skozi enoto nalagalnika namesto rekurziranja v vezalno enoto

Kontrolni seznam namestitve

Trije stvari pojasnijo večino odpovedi nalaganja, ko je aritmetika poti prava. Arhitektura se mora ujemati s procesom in ne s strojem, zato 32-bitna aplikacija na 64-bitnem Windows potrebuje 32-bitno binarno datoteko. Gradnja z omogočenim V8 ima drugo ime datoteke, zato namestitev, ki jih zmeša, bo izgledala pravilno in naložila ničesar. In samo ena različica lahko živi v sistemski mapi naenkrat, kar je dober razlog, da dajete prednost izrecni razporeditvi podmap pred nameščanjem česar koli po celem sistemu

Za Lazarus posebej dajte domorodno knjižnico pod DLLs/<cpu>-<os> z malimi črkami, poleg izvedljive datoteke, in bo najdena s strani prvega koraka verige na vsakem cilju. Vzorčni pregledovalnik, ki to vadi na Lazarusu, je opisan v članku o pregledovalniku Lazarus in FPC, trenutna podpora platformam pa je navedena na strani produkta PDFium Delphi component