Kada održavate VCL komponentu napisanu u Delphiju koju koriste i korisnici Delphija i korisnici C++Buildera, brzo ćete shvatiti da ova dva sistema za izgradnju tretiraju zavisnosti veoma različito. Jedinica koja se savršeno kompajlira u Delphiju može izazvati katastrofalne greške linkera u C++Builderu. Ovo nepodudaranje je česta zamka za autore komponenti, posebno kada se dodaju nove interne jedinice u postojeću biblioteku.
Evo detaljne analize zašto se to dešava, koristeći primere iz stvarnog sveta sa HotXLS komponentom, i kako da obezbedite otpornost vašeg procesa unakrsnog kompajliranja korišćenjem eksplicitnih uključivanja, {$HPPEMIT} i pragma povezivanja.
Zamka: Implicitno kompajliranje naspram eksplicitnog uključivanja
Pretpostavimo da kreirate novu Delphi jedinicu, lxXlsSummary.pas, za obradu metapodataka dokumenta, i uključite je pomoću uses u vašu glavnu jedinicu za parsiranje, lxRead.pas. Pritisnete dugme za kompajliranje u Delphi IDE-u, proces se uspešno završi, i vi objavite ažuriranje.
Sledećeg dana, vaši C++Builder korisnici prijavljuju grešku tokom faze povezivanja: Unresolved external 'XlsReadSummaryInformation' referenced from lxRead.obj.
Delphi način (dcc32)
Kada Delphi kompajler obrađuje paket (.dpk), on posmatra jedinice eksplicitno navedene u contains klauzuli. Ako jedna od tih jedinica koristi (uses) eksternu jedinicu (kao što je lxXlsSummary.pas) koja nije na contains listi, Delphi kompajler vrši implicitno statičko povezivanje. On jednostavno pronalazi .pas datoteku u putanji za pretragu, kompajlira je u .dcu, i ugrađuje je u rezultujući .bpl. Izrada uspeva, potpuno maskirajući propust.
C++Builder način (MSBuild / .cbproj)
Sistem za izgradnju u C++Builderu je mnogo stroži. On generiše C++ objektne datoteke (.obj) i zaglavlja (.hpp) samo za one Delphi jedinice koje su eksplicitno navedene u <DelphiCompile> grupi stavki u .cbproj datoteci. Pošto lxXlsSummary.pas nikada nije eksplicitno registrovan u projektnoj datoteci, nijedan lxXlsSummary.obj se ne kreira. Kada linker pokuša da razreši pozive koje pravi lxRead.obj, simboli nedostaju, što dovodi do greške nerešene eksterne reference.
Rešavanje eksternih referenci sa Pragma Link i HPPEMIT
Ako želite da osigurate da je jedinica pravilno povezana u C++ bez prisiljavanja korisnika da ručno dodaje .obj datoteku u svoj projekat, možete koristiti Delphi direktivu {$HPPEMIT}. Ovo govori Delphi kompajleru da ubaci specifičnu C++ #pragma link direktivu u generisanu .hpp datoteku.
unit lxXlsSummary;
interface
{$IFDEF WINDOWS}
// Inject a pragma link into the generated C++ header file
// This forces the C++ linker to include the corresponding .obj file
{$HPPEMIT '#pragma link "lxXlsSummary.obj"'}
{$ENDIF}
uses
SysUtils, Classes;
type
TXlsSummaryInfo = class(TObject)
public
Title: string;
Author: string;
CreateTime: TDateTime;
end;
function XlsReadSummaryInformation(const FileName: string): TXlsSummaryInfo;
implementation
function XlsReadSummaryInformation(const FileName: string): TXlsSummaryInfo;
begin
Result := TXlsSummaryInfo.Create;
// Metadata extraction logic here
end;
end.
Kada C++Builder uključi lxXlsSummary.hpp, kompajler nailazi na #pragma link i automatski nalaže linkeru (ILINK32/ILINK64) da razreši simbole iz lxXlsSummary.obj.
Zlatno pravilo za održavanje komponenti
Da biste izbegli potpuno kvarenje C++Builder build-ova, morate usvojiti strogu politiku registracije. Kad god se nova Pascal jedinica doda u vašu biblioteku, ona mora biti eksplicitno registrovana u svim tipovima projektnih datoteka istovremeno.
1. Ažurirajte C++Builder projekat (.cbproj / .bpk)
Otvorite .cbproj datoteku u uređivaču teksta i dodajte novu jedinicu na listu za kompajliranje, pazeći da obezbedite jedinstveni redosled izgradnje. Ako koristite starije verzije C++Buildera sa .bpk datotekama, osigurajte da je dodata oznaka <file containerid="PascalCompiler" designclass="" filename="lxXlsSummary.pas" formname="" localcommand="" unitname="lxXlsSummary"></file>.
<DelphiCompile Include="lxXlsSummary.pas">
<BuildOrder>101</BuildOrder>
</DelphiCompile>
2. Ažurirajte Delphi paket (.dpk)
Dodajte jedinicu u eksplicitnu contains klauzulu. Ovo osigurava da Delphi kompajler ne mora da se oslanja na implicitno povezivanje, što se ionako generalno smatra lošom praksom.
package HotXLS;
{$R *.res}
{$ALIGN 8}
{$ASSERTIONS ON}
{$BOOLEVAL OFF}
requires
rtl,
vcl;
contains
lxRead in 'lxRead.pas',
lxXlsSummary in 'lxXlsSummary.pas';
end.
Validacija kontinuirane integracije
Krajnja odbrana od ove zamke je CI/CD validacija. Nikada se nemojte oslanjati isključivo na uspešan Delphi build pre objavljivanja komponente za dva jezika. Vaše skripte za izgradnju moraju pozvati MSBuild ili alatke komandne linije bcc32c na C++Builder projektima (npr. build-Win32-Lib-CB.cmd) i pokrenuti kompletno povezivanje C++ probne verzije i punih demo primera. Tek kada C++ linker uspe, možete biti sigurni da su sve Delphi jedinice pravilno registrovane i da izlažu svoje simbole C++ okruženju.
Napomena: Kompatibilnost unakrsnog kompajliranja je strogo održavana u Delphi i C++Builder izdanjima HotXLS VCL komponente.