feat(codegen): target toolkit + registry; register freebsd-x86_64
Introduce TTargetToolkit (Abstract Factory) and TTargetRegistry so per-target compiler-side objects (native backend + ELF link target) are resolved by name rather than hard-coded case statements. CreateNativeBackend now delegates to the registry; adding a target is a new toolkit + one registration with no edits to existing dispatch. Registers linux-x86_64 (unchanged behaviour) and freebsd-x86_64 (link target with EI_OSABI=9; reuses TX86_64Backend since FreeBSD shares the System V AMD64 ABI). FreeBSD codegen/runtime lands in later steps. The registry uses TOrderedDictionary<string, TTargetToolkit> (name -> toolkit) per the Generics.Collections policy. It is built publish-after-populate: the --incremental compile worker pool is threads, so a half-built global would let a worker wrongly conclude a target has no backend. Step 0a of docs/native-target-architecture.adoc. Behaviour-preserving: FIXPOINT_OK, NATIVE_FIXPOINT_OK, NATIVE_INTERNAL_OK, WARMCACHE_FIXPOINT_OK; full suite 3761 tests green (QBE- and native-built runners).
This commit is contained in:
parent
4384b272c3
commit
e723e80063
|
|
@ -76,19 +76,24 @@ function CreateNativeBackend(const ATarget: TTargetDesc): TNativeBackend;
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
blaise.codegen.native.x86_64;
|
blaise.codegen.toolkit;
|
||||||
|
|
||||||
{ ------------------------------------------------------------------ }
|
{ ------------------------------------------------------------------ }
|
||||||
{ Backend factory }
|
{ Backend factory }
|
||||||
{ ------------------------------------------------------------------ }
|
{ ------------------------------------------------------------------ }
|
||||||
|
|
||||||
function CreateNativeBackend(const ATarget: TTargetDesc): TNativeBackend;
|
function CreateNativeBackend(const ATarget: TTargetDesc): TNativeBackend;
|
||||||
|
var
|
||||||
|
Toolkit: TTargetToolkit;
|
||||||
begin
|
begin
|
||||||
if (ATarget.OS = osLinux) and (ATarget.CPU = cpuX86_64) then
|
{ Resolve the per-target adapter family from the registry (Abstract
|
||||||
Result := TX86_64Backend.Create(ATarget)
|
Factory). Adding a target is a new toolkit + one registration — this
|
||||||
else
|
dispatch never changes. See docs/native-target-architecture.adoc. }
|
||||||
|
Toolkit := ResolveToolkit(ATarget);
|
||||||
|
if Toolkit = nil then
|
||||||
raise ENativeCodeGenError.Create(
|
raise ENativeCodeGenError.Create(
|
||||||
'native backend not yet implemented for target ' + TargetName(ATarget));
|
'native backend not yet implemented for target ' + TargetName(ATarget));
|
||||||
|
Result := Toolkit.MakeBackend();
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ ------------------------------------------------------------------ }
|
{ ------------------------------------------------------------------ }
|
||||||
|
|
|
||||||
234
compiler/src/main/pascal/blaise.codegen.toolkit.pas
Normal file
234
compiler/src/main/pascal/blaise.codegen.toolkit.pas
Normal file
|
|
@ -0,0 +1,234 @@
|
||||||
|
{
|
||||||
|
Blaise - An Object Pascal Compiler
|
||||||
|
Copyright (c) 2026 Graeme Geldenhuys
|
||||||
|
SPDX-License-Identifier: Apache-2.0 WITH Swift-exception
|
||||||
|
Licensed under the Apache License v2.0 with Runtime Library Exception.
|
||||||
|
See LICENSE file in the project root for full license terms.
|
||||||
|
}
|
||||||
|
|
||||||
|
unit blaise.codegen.toolkit;
|
||||||
|
|
||||||
|
{ Multi-target toolkit + registry (docs/native-target-architecture.adoc).
|
||||||
|
|
||||||
|
A TTargetToolkit is the Abstract Factory that produces the consistent
|
||||||
|
*family* of per-target compiler-side objects: the native backend and the
|
||||||
|
link target. Keeping them behind one factory guarantees the family is
|
||||||
|
coherent — a FreeBSD backend paired with a Linux link target is a bug a
|
||||||
|
registry-resolved toolkit cannot produce.
|
||||||
|
|
||||||
|
TTargetRegistry maps a TTargetDesc to its toolkit. Adding a target is a new
|
||||||
|
TTargetToolkit subclass plus one registration call — no existing dispatch is
|
||||||
|
edited (Open/Closed). --target resolution and "does this target have a
|
||||||
|
native backend?" both go through the registry, replacing the previous
|
||||||
|
hard-coded case statements in blaise.codegen.native and
|
||||||
|
blaise.codegen.target.
|
||||||
|
|
||||||
|
This is the compiler-side half of the architecture. The runtime-side ports
|
||||||
|
(TKernelABI / TPlatformLayout) live in the RTL and are introduced in later
|
||||||
|
steps; they are not part of this unit. }
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
SysUtils, Generics.Collections,
|
||||||
|
blaise.codegen.target, blaise.codegen.native.backend, blaise.linker.elf;
|
||||||
|
|
||||||
|
type
|
||||||
|
{ Abstract Factory for one target's compiler-side object family. }
|
||||||
|
TTargetToolkit = class
|
||||||
|
public
|
||||||
|
{ Canonical "<os>-<cpu>" name (matches blaise.codegen.target.TargetName). }
|
||||||
|
function Name: string; virtual; abstract;
|
||||||
|
{ Construct the native backend for this target. Caller owns the result. }
|
||||||
|
function MakeBackend: TNativeBackend; virtual; abstract;
|
||||||
|
{ Construct the link target (ELF header facts) for this target. Caller
|
||||||
|
owns the result. }
|
||||||
|
function MakeLinkTarget: TLinkTarget; virtual; abstract;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Linux x86_64 — the original (and, before FreeBSD, only) target. }
|
||||||
|
TLinuxX86_64Toolkit = class(TTargetToolkit)
|
||||||
|
public
|
||||||
|
function Name: string; override;
|
||||||
|
function MakeBackend: TNativeBackend; override;
|
||||||
|
function MakeLinkTarget: TLinkTarget; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ FreeBSD x86_64 — shares the System V AMD64 ABI and the x86_64 instruction
|
||||||
|
selector with Linux, so MakeBackend reuses TX86_64Backend; only the link
|
||||||
|
target's OS/ABI byte differs. The runtime/syscall divergence is handled
|
||||||
|
in the RTL (TKernelABI / TPlatformLayout), not here. }
|
||||||
|
TFreeBSDX86_64Toolkit = class(TTargetToolkit)
|
||||||
|
public
|
||||||
|
function Name: string; override;
|
||||||
|
function MakeBackend: TNativeBackend; override;
|
||||||
|
function MakeLinkTarget: TLinkTarget; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Toolkit registry. Owns the registered toolkit instances. A linear list
|
||||||
|
is correct here: the target count is tiny (one per supported OS/CPU), so a
|
||||||
|
name scan is cheaper than a hash map and avoids instantiating a generic
|
||||||
|
map over a class type. }
|
||||||
|
TTargetRegistry = class
|
||||||
|
private
|
||||||
|
FByName: TOrderedDictionary<string, TTargetToolkit>;
|
||||||
|
public
|
||||||
|
constructor Create;
|
||||||
|
destructor Destroy; override;
|
||||||
|
{ Register a toolkit. Registry takes ownership. }
|
||||||
|
procedure Register(AToolkit: TTargetToolkit);
|
||||||
|
{ Resolve the toolkit for ATarget, or nil if none is registered. }
|
||||||
|
function Resolve(const ATarget: TTargetDesc): TTargetToolkit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ The process-wide registry, populated in this unit's initialization. }
|
||||||
|
function GTargetRegistry: TTargetRegistry;
|
||||||
|
|
||||||
|
{ Resolve the toolkit for ATarget via the global registry (nil if unknown). }
|
||||||
|
function ResolveToolkit(const ATarget: TTargetDesc): TTargetToolkit;
|
||||||
|
|
||||||
|
{ True when ATarget has a registered native backend toolkit. Replacement for
|
||||||
|
blaise.codegen.target.TargetHasNativeBackend, driven by the registry. }
|
||||||
|
function RegisteredHasNativeBackend(const ATarget: TTargetDesc): Boolean;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
blaise.codegen.native.x86_64;
|
||||||
|
|
||||||
|
{ ---- TLinuxX86_64Toolkit --------------------------------------------- }
|
||||||
|
|
||||||
|
function TLinuxX86_64Toolkit.Name: string;
|
||||||
|
begin
|
||||||
|
Result := 'linux-x86_64';
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TLinuxX86_64Toolkit.MakeBackend: TNativeBackend;
|
||||||
|
var
|
||||||
|
T: TTargetDesc;
|
||||||
|
begin
|
||||||
|
MakeTarget(osLinux, cpuX86_64, T);
|
||||||
|
Result := TX86_64Backend.Create(T);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TLinuxX86_64Toolkit.MakeLinkTarget: TLinkTarget;
|
||||||
|
begin
|
||||||
|
Result := LinuxX86_64Target();
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ ---- TFreeBSDX86_64Toolkit ------------------------------------------- }
|
||||||
|
|
||||||
|
function TFreeBSDX86_64Toolkit.Name: string;
|
||||||
|
begin
|
||||||
|
Result := 'freebsd-x86_64';
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TFreeBSDX86_64Toolkit.MakeBackend: TNativeBackend;
|
||||||
|
var
|
||||||
|
T: TTargetDesc;
|
||||||
|
begin
|
||||||
|
MakeTarget(osFreeBSD, cpuX86_64, T);
|
||||||
|
Result := TX86_64Backend.Create(T);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TFreeBSDX86_64Toolkit.MakeLinkTarget: TLinkTarget;
|
||||||
|
begin
|
||||||
|
Result := FreeBSDX86_64Target();
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ ---- TTargetRegistry ------------------------------------------------- }
|
||||||
|
|
||||||
|
constructor TTargetRegistry.Create;
|
||||||
|
begin
|
||||||
|
inherited Create();
|
||||||
|
FByName := TOrderedDictionary<string, TTargetToolkit>.Create();
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TTargetRegistry.Destroy;
|
||||||
|
var
|
||||||
|
I: Integer;
|
||||||
|
Tk: TTargetToolkit;
|
||||||
|
begin
|
||||||
|
if FByName <> nil then
|
||||||
|
begin
|
||||||
|
for I := 0 to FByName.Count - 1 do
|
||||||
|
begin
|
||||||
|
Tk := FByName.Values[I];
|
||||||
|
Tk.Free();
|
||||||
|
end;
|
||||||
|
FByName.Free();
|
||||||
|
end;
|
||||||
|
inherited Destroy();
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTargetRegistry.Register(AToolkit: TTargetToolkit);
|
||||||
|
begin
|
||||||
|
FByName.Items[AToolkit.Name()] := AToolkit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TTargetRegistry.Resolve(const ATarget: TTargetDesc): TTargetToolkit;
|
||||||
|
var
|
||||||
|
Key: string;
|
||||||
|
Tk: TTargetToolkit;
|
||||||
|
begin
|
||||||
|
Key := TargetName(ATarget);
|
||||||
|
if FByName.TryGetValue(Key, Tk) then
|
||||||
|
Result := Tk
|
||||||
|
else
|
||||||
|
Result := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ ---- Global registry -------------------------------------------------- }
|
||||||
|
|
||||||
|
var
|
||||||
|
GRegistry: TTargetRegistry;
|
||||||
|
|
||||||
|
{ Build the registry on first use. This unit's initialization section calls
|
||||||
|
EnsureRegistry once at startup (single-threaded, before any worker thread is
|
||||||
|
spawned), so the common path is a no-op nil check. The lazy guard also
|
||||||
|
covers the case where a codegen unit's own initialization constructs a
|
||||||
|
backend before this unit's initialization runs (link-order independence).
|
||||||
|
|
||||||
|
Thread-safety note: the incremental compile worker pool is THREADS, not
|
||||||
|
processes. The registry must be FULLY built before it is published to the
|
||||||
|
global, or a second thread could observe a non-nil GRegistry whose toolkit
|
||||||
|
list is still empty and wrongly conclude a target has no backend. Build
|
||||||
|
into a local and assign the global last (publish-after-populate). }
|
||||||
|
procedure EnsureRegistry;
|
||||||
|
var
|
||||||
|
R: TTargetRegistry;
|
||||||
|
begin
|
||||||
|
if GRegistry = nil then
|
||||||
|
begin
|
||||||
|
R := TTargetRegistry.Create();
|
||||||
|
R.Register(TLinuxX86_64Toolkit.Create());
|
||||||
|
R.Register(TFreeBSDX86_64Toolkit.Create());
|
||||||
|
GRegistry := R;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GTargetRegistry: TTargetRegistry;
|
||||||
|
begin
|
||||||
|
EnsureRegistry();
|
||||||
|
Result := GRegistry;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ResolveToolkit(const ATarget: TTargetDesc): TTargetToolkit;
|
||||||
|
begin
|
||||||
|
EnsureRegistry();
|
||||||
|
Result := GRegistry.Resolve(ATarget);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function RegisteredHasNativeBackend(const ATarget: TTargetDesc): Boolean;
|
||||||
|
begin
|
||||||
|
EnsureRegistry();
|
||||||
|
Result := GRegistry.Resolve(ATarget) <> nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
initialization
|
||||||
|
EnsureRegistry();
|
||||||
|
|
||||||
|
finalization
|
||||||
|
GRegistry.Free();
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
@ -84,6 +84,10 @@ type
|
||||||
{ Linux x86-64 ELF, non-PIE ET_EXEC. Caller frees. }
|
{ Linux x86-64 ELF, non-PIE ET_EXEC. Caller frees. }
|
||||||
function LinuxX86_64Target: TLinkTarget;
|
function LinuxX86_64Target: TLinkTarget;
|
||||||
|
|
||||||
|
{ FreeBSD x86-64 ELF. Same System V AMD64 machine/arch as Linux; differs
|
||||||
|
only in EI_OSABI (9 = FreeBSD). Caller frees. }
|
||||||
|
function FreeBSDX86_64Target: TLinkTarget;
|
||||||
|
|
||||||
type
|
type
|
||||||
{ One output section accumulating contributions from input objects. }
|
{ One output section accumulating contributions from input objects. }
|
||||||
TMergedSection = class
|
TMergedSection = class
|
||||||
|
|
@ -611,6 +615,13 @@ begin
|
||||||
{ defaults already describe Linux x86-64 }
|
{ defaults already describe Linux x86-64 }
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function FreeBSDX86_64Target: TLinkTarget;
|
||||||
|
begin
|
||||||
|
Result := TLinkTarget.Create();
|
||||||
|
{ Identical to Linux x86-64 except the OS/ABI byte in the ELF header. }
|
||||||
|
Result.OSABI := ELFOSABI_FREEBSD;
|
||||||
|
end;
|
||||||
|
|
||||||
{ ---- TLinker ----------------------------------------------------------- }
|
{ ---- TLinker ----------------------------------------------------------- }
|
||||||
|
|
||||||
constructor TLinker.Create;
|
constructor TLinker.Create;
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,7 @@ uses
|
||||||
cp.test.strutils,
|
cp.test.strutils,
|
||||||
cp.test.e2e.strutils,
|
cp.test.e2e.strutils,
|
||||||
cp.test.toolchain,
|
cp.test.toolchain,
|
||||||
|
cp.test.targettoolkit,
|
||||||
cp.test.dynarray,
|
cp.test.dynarray,
|
||||||
cp.test.math,
|
cp.test.math,
|
||||||
cp.test.e2e.math,
|
cp.test.e2e.math,
|
||||||
|
|
|
||||||
141
compiler/src/test/pascal/cp.test.targettoolkit.pas
Normal file
141
compiler/src/test/pascal/cp.test.targettoolkit.pas
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
{
|
||||||
|
Blaise - An Object Pascal Compiler
|
||||||
|
Copyright (c) 2026 Graeme Geldenhuys
|
||||||
|
SPDX-License-Identifier: Apache-2.0 WITH Swift-exception
|
||||||
|
Licensed under the Apache License v2.0 with Runtime Library Exception.
|
||||||
|
See LICENSE file in the project root for full license terms.
|
||||||
|
}
|
||||||
|
|
||||||
|
unit cp.test.targettoolkit;
|
||||||
|
|
||||||
|
{ Tests for the multi-target toolkit + registry (docs/native-target-
|
||||||
|
architecture.adoc). A TTargetToolkit is the Abstract Factory that produces
|
||||||
|
the consistent family of per-target objects (backend, link target); the
|
||||||
|
registry resolves a toolkit by target.
|
||||||
|
|
||||||
|
These tests pin the behaviour-preserving Step 0a refactor: the existing
|
||||||
|
Linux x86_64 target must resolve through the registry, and the FreeBSD
|
||||||
|
x86_64 target must be registered (its codegen lands in later steps, so we
|
||||||
|
only assert it is known to the registry here, not that it emits code). }
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
blaise.testing,
|
||||||
|
blaise.codegen.target, blaise.codegen.toolkit,
|
||||||
|
blaise.codegen.native.backend, blaise.linker.elf;
|
||||||
|
|
||||||
|
type
|
||||||
|
TTargetToolkitTests = class(TTestCase)
|
||||||
|
private
|
||||||
|
function LinuxTarget: TTargetDesc;
|
||||||
|
function FreeBSDTarget: TTargetDesc;
|
||||||
|
published
|
||||||
|
{ Linux x86_64 resolves to a toolkit, and that toolkit reports its name. }
|
||||||
|
procedure TestResolve_LinuxX86_64_ReturnsToolkit;
|
||||||
|
procedure TestResolve_LinuxX86_64_ToolkitName;
|
||||||
|
{ The Linux toolkit makes a real backend (the existing TX86_64Backend). }
|
||||||
|
procedure TestLinuxToolkit_MakeBackend_NotNil;
|
||||||
|
{ The Linux toolkit makes a SysV/Linux link target (OSABI 0). }
|
||||||
|
procedure TestLinuxToolkit_MakeLinkTarget_IsLinuxOSABI;
|
||||||
|
{ RegisteredHasNativeBackend mirrors the old TargetHasNativeBackend for
|
||||||
|
Linux x86_64. }
|
||||||
|
procedure TestRegistered_LinuxX86_64_HasBackend;
|
||||||
|
{ FreeBSD x86_64 is registered (resolves to a toolkit). }
|
||||||
|
procedure TestResolve_FreeBSDX86_64_ReturnsToolkit;
|
||||||
|
{ FreeBSD toolkit produces a FreeBSD-OSABI link target (OSABI 9). }
|
||||||
|
procedure TestFreeBSDToolkit_MakeLinkTarget_IsFreeBSDOSABI;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
const
|
||||||
|
ELFOSABI_SYSV = 0;
|
||||||
|
ELFOSABI_FREEBSD = 9;
|
||||||
|
|
||||||
|
function TTargetToolkitTests.LinuxTarget: TTargetDesc;
|
||||||
|
begin
|
||||||
|
MakeTarget(osLinux, cpuX86_64, Result);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TTargetToolkitTests.FreeBSDTarget: TTargetDesc;
|
||||||
|
begin
|
||||||
|
MakeTarget(osFreeBSD, cpuX86_64, Result);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTargetToolkitTests.TestResolve_LinuxX86_64_ReturnsToolkit;
|
||||||
|
var
|
||||||
|
Tk: TTargetToolkit;
|
||||||
|
begin
|
||||||
|
Tk := ResolveToolkit(Self.LinuxTarget());
|
||||||
|
AssertTrue('linux-x86_64 must resolve to a toolkit', Tk <> nil);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTargetToolkitTests.TestResolve_LinuxX86_64_ToolkitName;
|
||||||
|
var
|
||||||
|
Tk: TTargetToolkit;
|
||||||
|
begin
|
||||||
|
Tk := ResolveToolkit(Self.LinuxTarget());
|
||||||
|
AssertEquals('linux-x86_64', Tk.Name());
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTargetToolkitTests.TestLinuxToolkit_MakeBackend_NotNil;
|
||||||
|
var
|
||||||
|
Tk: TTargetToolkit;
|
||||||
|
B: TNativeBackend;
|
||||||
|
begin
|
||||||
|
Tk := ResolveToolkit(Self.LinuxTarget());
|
||||||
|
B := Tk.MakeBackend();
|
||||||
|
try
|
||||||
|
AssertTrue('Linux toolkit must produce a backend', B <> nil);
|
||||||
|
finally
|
||||||
|
B.Free();
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTargetToolkitTests.TestLinuxToolkit_MakeLinkTarget_IsLinuxOSABI;
|
||||||
|
var
|
||||||
|
Tk: TTargetToolkit;
|
||||||
|
Lt: TLinkTarget;
|
||||||
|
begin
|
||||||
|
Tk := ResolveToolkit(Self.LinuxTarget());
|
||||||
|
Lt := Tk.MakeLinkTarget();
|
||||||
|
try
|
||||||
|
AssertEquals(ELFOSABI_SYSV, Lt.OSABI);
|
||||||
|
finally
|
||||||
|
Lt.Free();
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTargetToolkitTests.TestRegistered_LinuxX86_64_HasBackend;
|
||||||
|
begin
|
||||||
|
AssertTrue('linux-x86_64 must have a native backend',
|
||||||
|
RegisteredHasNativeBackend(Self.LinuxTarget()));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTargetToolkitTests.TestResolve_FreeBSDX86_64_ReturnsToolkit;
|
||||||
|
var
|
||||||
|
Tk: TTargetToolkit;
|
||||||
|
begin
|
||||||
|
Tk := ResolveToolkit(Self.FreeBSDTarget());
|
||||||
|
AssertTrue('freebsd-x86_64 must resolve to a toolkit', Tk <> nil);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTargetToolkitTests.TestFreeBSDToolkit_MakeLinkTarget_IsFreeBSDOSABI;
|
||||||
|
var
|
||||||
|
Tk: TTargetToolkit;
|
||||||
|
Lt: TLinkTarget;
|
||||||
|
begin
|
||||||
|
Tk := ResolveToolkit(Self.FreeBSDTarget());
|
||||||
|
Lt := Tk.MakeLinkTarget();
|
||||||
|
try
|
||||||
|
AssertEquals(ELFOSABI_FREEBSD, Lt.OSABI);
|
||||||
|
finally
|
||||||
|
Lt.Free();
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
initialization
|
||||||
|
RegisterTest(TTargetToolkitTests);
|
||||||
|
|
||||||
|
end.
|
||||||
Loading…
Reference in a new issue