Teknik Makale

Delphi Bileşenlerini C++Builder için Çapraz Derleme: Çözümlenmemiş Dış Sembollerden Kaçınmak

Delphi ile yazılmış ama hem Delphi hem de C++Builder kullanıcıları tarafından tüketilen bir VCL bileşeninin bakımını yaparken, iki derleme sisteminin bağımlılıkları çok farklı ele aldığını çabucak fark edersiniz. Delphi'de kusursuz derlenen bir birim (unit), C++Builder'da yıkıcı bağlayıcı (linker) hatalarına yol açabilir. Bu tutarsızlık, özellikle mevcut bir kütüphaneye yeni dahili birimler eklerken bileşen yazarları için sık rastlanan bir tuzaktır

İşte bunun neden olduğuna dair, HotXLS bileşeninden gerçek dünya örnekleri kullanarak yapılmış ayrıntılı bir çözümleme ve açık dahil etmeler (include), {$HPPEMIT} ve pragma bağlama kullanarak çapraz derleme sürecinizi nasıl kurşun geçirmez hale getireceğiniz

Tuzak: Örtük Derleme ve Açık Dahil Etme

Belge meta verilerini işlemek için yeni bir Delphi birimi olan lxXlsSummary.pas oluşturduğunuzu ve ana ayrıştırma biriminiz lxRead.pas içinde onu uses ile kullandığınızı varsayalım. Delphi IDE'de derlemeye basarsınız, derleme yeşile döner ve güncellemeyi yayınlarsınız

Ertesi gün, C++Builder kullanıcılarınız bağlama aşamasında bir hata bildirir: Unresolved external 'XlsReadSummaryInformation' referenced from lxRead.obj

Delphi Yolu (dcc32)

Delphi derleyicisi bir paketi (.dpk) işlerken, contains yan tümcesinde açıkça listelenen birimlere bakar. Bu birimlerden biri, contains listesinde olmayan bir dış birimi (lxXlsSummary.pas gibi) uses ile kullanıyorsa, Delphi derleyicisi örtük statik bağlama (implicit static linking) gerçekleştirir. .pas dosyasını arama yolunda bulur, bir .dcu dosyasına derler ve elde edilen .bpl içine gömer. Derleme başarılı olur ve bu ihmali tamamen gizler

C++Builder Yolu (MSBuild / .cbproj)

C++Builder'ın derleme sistemi çok daha katıdır. Yalnızca .cbproj dosyasının <DelphiCompile> öğe grubunda açıkça listelenen Delphi birimleri için C++ nesne dosyaları (.obj) ve başlıklar (.hpp) üretir. lxXlsSummary.pas proje dosyasına hiçbir zaman açıkça kaydedilmediği için, hiçbir lxXlsSummary.obj oluşturulmaz. Bağlayıcı, lxRead.obj tarafından yapılan çağrıları çözmeye çalıştığında semboller eksiktir ve bu, çözümlenmemiş bir dış sembol (unresolved external) hatasına yol açar

Pragma Link ve HPPEMIT ile Dış Sembolleri Çözme

Kullanıcıyı .obj dosyasını projesine elle eklemeye zorlamadan bir birimin C++'ta düzgün biçimde bağlandığından emin olmak istiyorsanız, Delphi'nin {$HPPEMIT} yönergesini kullanabilirsiniz. Bu, Delphi derleyicisine, üretilen .hpp dosyasına belirli bir C++ #pragma link yönergesi enjekte etmesini söyler

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.

C++Builder lxXlsSummary.hpp dosyasını dahil ettiğinde, derleyici #pragma link ile karşılaşır ve bağlayıcıya (ILINK32/ILINK64) sembolleri lxXlsSummary.obj'den çözmesini otomatik olarak söyler

Bileşen Bakımı için Altın Kural

C++Builder derlemelerini tamamen bozmaktan kaçınmak için katı bir kayıt politikası benimsemelisiniz. Kütüphanenize yeni bir Pascal birimi eklendiğinde, üç proje dosyası türünün tümüne aynı anda açıkça kaydedilmelidir

1. C++Builder Projesini Güncelleyin (.cbproj / .bpk)

.cbproj dosyasını bir metin düzenleyicide açın ve yeni birimi derleme listesine ekleyerek benzersiz bir derleme sırası (build order) sağladığınızdan emin olun. .bpk dosyalarına sahip eski C++Builder sürümlerini kullanıyorsanız, <file containerid="PascalCompiler" designclass="" filename="lxXlsSummary.pas" formname="" localcommand="" unitname="lxXlsSummary"></file> etiketinin eklendiğinden emin olun

<DelphiCompile Include="lxXlsSummary.pas">
  <BuildOrder>101</BuildOrder>
</DelphiCompile>

2. Delphi Paketini Güncelleyin (.dpk)

Birimi açık contains yan tümcesine ekleyin. Bu, Delphi derleyicisinin, zaten genelde kötü uygulama olarak kabul edilen örtük bağlamaya güvenmek zorunda kalmamasını sağlar

package HotXLS;

{$R *.res}
{$ALIGN 8}
{$ASSERTIONS ON}
{$BOOLEVAL OFF}

requires
  rtl,
  vcl;

contains
  lxRead in 'lxRead.pas',
  lxXlsSummary in 'lxXlsSummary.pas';

end.

Sürekli Entegrasyon Doğrulaması

Bu tuzağa karşı nihai savunma CI/CD doğrulamasıdır. Çift dilli bir bileşeni yayınlamadan önce yalnızca başarılı bir Delphi derlemesine asla güvenmeyin. Derleme betikleriniz, C++Builder projeleri üzerinde MSBuild veya bcc32c komut satırı araçlarını çağırmalı (örneğin build-Win32-Lib-CB.cmd) ve C++ deneme ve tam demolarının eksiksiz bir bağlamasını çalıştırmalıdır. Yalnızca C++ bağlayıcısı başarılı olduğunda tüm Delphi birimlerinin doğru kaydedildiğinden ve sembollerini C++ çalışma zamanına açtığından emin olabilirsiniz

Not: Çapraz platform derleyici uyumluluğu, HotXLS VCL Bileşeninin Delphi ve C++Builder sürümlerinde katı biçimde korunur