Saat memelihara komponen VCL yang ditulis dalam bahasa Delphi tetapi digunakan oleh pengguna Delphi dan C++Builder, Anda akan segera menyadari bahwa kedua sistem build memperlakukan dependensi secara sangat berbeda. Sebuah unit yang berhasil dikompilasi dengan sempurna di Delphi dapat menyebabkan kesalahan penaut di C++Builder. Perbedaan ini sering menjadi jebakan bagi pembuat komponen, khususnya saat menambahkan unit internal baru ke pustaka yang sudah ada
Berikut adalah rincian mendetail mengapa hal ini terjadi, menggunakan contoh dunia nyata dari komponen HotXLS, dan bagaimana membentengi proses kompilasi silang Anda menggunakan inklusi eksplisit, {$HPPEMIT}, dan penautan pragma
Perbedaan ini muncul karena Delphi dapat menemukan unit melalui search path, sedangkan C++Builder perlu melihat unit dan objek yang benar-benar masuk ke proyek atau paketnya. Panduan ini menggunakan contoh komponen HotXLS untuk menjelaskan inklusi eksplisit, {$HPPEMIT}, dan pragma linking tanpa mengubah API Delphi
Jebakan: Kompilasi Implisit vs. Inklusi Eksplisit
Misalkan Anda membuat unit Delphi baru, lxXlsSummary.pas, untuk menangani metadata dokumen, dan Anda meng-uses unit tersebut di unit pem-parsing-an utama Anda, lxRead.pas. Anda menekan kompilasi di IDE Delphi, build menjadi hijau, dan Anda mengirimkan pembaruan
Keesokan harinya, pengguna C++Builder Anda melaporkan kesalahan selama fase penautan: Unresolved external 'XlsReadSummaryInformation' referenced from lxRead.obj
Cara Delphi (dcc32)
Saat kompiler Delphi memproses sebuah paket (.dpk), ia melihat unit-unit yang secara eksplisit terdaftar di klausa contains. Jika salah satu dari unit tersebut meng-uses unit eksternal (seperti lxXlsSummary.pas) yang tidak ada dalam daftar contains, kompiler Delphi melakukan penautan statis implisit. Kompiler tersebut secara sederhana menemukan file .pas di jalur pencarian, mengompilasinya menjadi .dcu, dan memasukkannya ke dalam .bpl yang dihasilkan. Build berhasil, sepenuhnya menutupi kelalaian tersebut
Cara C++Builder (MSBuild / .cbproj)
Sistem build C++Builder jauh lebih ketat. Sistem ini hanya menghasilkan file objek C++ (.obj) dan header (.hpp) untuk unit Delphi yang secara eksplisit terdaftar dalam grup item <DelphiCompile> di file .cbproj. Karena lxXlsSummary.pas tidak pernah didaftarkan secara eksplisit dalam file proyek, tidak ada lxXlsSummary.obj yang dibuat. Saat penaut mencoba menyelesaikan panggilan yang dibuat oleh lxRead.obj, simbol-simbol tersebut hilang, sehingga menyebabkan kesalahan eksternal yang tak terpecahkan
Memecahkan Eksternal dengan Pragma Link dan HPPEMIT
Jika Anda ingin memastikan bahwa sebuah unit ditautkan dengan benar di C++ tanpa memaksa pengguna untuk menambahkan file .obj ke proyek mereka secara manual, Anda dapat menggunakan arahan {$HPPEMIT} Delphi. Ini memberi tahu kompiler Delphi untuk menyuntikkan arahan #pragma link C++ tertentu ke dalam file .hpp yang dihasilkan
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.
Saat C++Builder menyertakan lxXlsSummary.hpp, kompiler tersebut menemui #pragma link dan secara otomatis memberi tahu penaut (ILINK32/ILINK64) untuk menyelesaikan simbol dari lxXlsSummary.obj
Aturan Emas untuk Pemeliharaan Komponen
Untuk menghindari kerusakan build C++Builder sepenuhnya, Anda harus menerapkan kebijakan pendaftaran yang ketat. Kapan pun unit Pascal baru ditambahkan ke pustaka Anda, unit tersebut harus didaftarkan secara eksplisit di ketiga jenis file proyek secara bersamaan
1. Perbarui Proyek C++Builder (.cbproj / .bpk)
Buka file .cbproj di editor teks dan tambahkan unit baru ke daftar kompilasi, pastikan Anda memberikan urutan build yang unik. Jika menggunakan versi C++Builder lama dengan file .bpk, pastikan tag <file containerid="PascalCompiler" designclass="" filename="lxXlsSummary.pas" formname="" localcommand="" unitname="lxXlsSummary"></file> ditambahkan
<DelphiCompile Include="lxXlsSummary.pas">
<BuildOrder>101</BuildOrder>
</DelphiCompile>
2. Perbarui Paket Delphi (.dpk)
Tambahkan unit ke klausa eksplisit contains. Ini memastikan kompiler Delphi tidak perlu bergantung pada penautan implisit, yang umumnya dianggap sebagai praktik yang buruk
package HotXLS;
{$R *.res}
{$ALIGN 8}
{$ASSERTIONS ON}
{$BOOLEVAL OFF}
requires
rtl,
vcl;
contains
lxRead in 'lxRead.pas',
lxXlsSummary in 'lxXlsSummary.pas';
end.
Validasi Integrasi Berkelanjutan
Pertahanan utama terhadap jebakan ini adalah validasi CI/CD. Jangan pernah mengandalkan build Delphi yang berhasil semata sebelum mengirimkan komponen bahasa ganda. Skrip build Anda harus memanggil MSBuild atau alat bantu baris perintah bcc32c pada proyek C++Builder (misalnya, build-Win32-Lib-CB.cmd) dan menjalankan penautan lengkap dari demo C++ uji coba dan penuh. Hanya ketika penaut C++ berhasil Anda dapat memastikan bahwa semua unit Delphi terdaftar dengan benar dan memaparkan simbolnya ke runtime C++
Catatan: Kompatibilitas kompiler lintas platform dipertahankan secara ketat di semua edisi Delphi dan C++Builder dari Komponen VCL HotXLS