feat(parser): external 'lib' name directive + link-library propagation
`external 'c' name 'strlen'` now records the bare library name on the declaration (TMethodDecl.ExternalLib) and hoists it into the owning unit/program's LinkLibs set, so the link layer can expand it to a -l<name> dependency. The library clause is optional and parsed before the existing `name '...'` clause, so `external name 'x'` and bare `external 'c'` both still parse. TUnitInterface.LinkLibs is serialised in the .bif META block (one EncodeStringList after ImplUsedUnits, before HasInitialization) so a unit's external-library dependencies round-trip across separate compilation. IFACE_VERSION is bumped 6 -> 7: the META layout grew, so a v6 reader must reject these .bif and recompile (without the bump a v6 binary would misparse the extra field and read past the END marker). Tests: a parser test asserting `external 'c' name 'strlen'` populates ExternalLib + the program's LinkLibs; a .bif round-trip test for TUnitInterface.LinkLibs; the magic/version assertion updated to v7; and the existing e2e strlen case. bif-coverage.status records TUnitInterface.LinkLibs as serialised.
This commit is contained in:
parent
e2ee936663
commit
c1f14b5c78
|
|
@ -863,6 +863,7 @@ type
|
||||||
consumed by codegen for cross-unit references. }
|
consumed by codegen for cross-unit references. }
|
||||||
IsExternal: Boolean; { declared with 'external' directive — no body }
|
IsExternal: Boolean; { declared with 'external' directive — no body }
|
||||||
ExternalName: string; { C symbol name from 'external name ''c_foo'''; empty = use Pascal name }
|
ExternalName: string; { C symbol name from 'external name ''c_foo'''; empty = use Pascal name }
|
||||||
|
ExternalLib: string; { library from 'external ''c'' name ''malloc'''; bare name, link layer expands per platform. Also recorded unit-level in LinkLibs. }
|
||||||
NoStackFrame: Boolean; { declared 'nostackframe' — body is an asm
|
NoStackFrame: Boolean; { declared 'nostackframe' — body is an asm
|
||||||
block that owns the whole frame; codegen
|
block that owns the whole frame; codegen
|
||||||
emits no compiler prologue/epilogue }
|
emits no compiler prologue/epilogue }
|
||||||
|
|
@ -1067,6 +1068,19 @@ type
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ A library this compilation unit must be linked against — collected by the
|
||||||
|
parser from every 'external ''lib''' declaration (interface OR
|
||||||
|
implementation). Hoisted to the unit level so an implementation-private
|
||||||
|
import still records its link dependency: the private routine stays out of
|
||||||
|
the .bif, but the library it needs is serialised via
|
||||||
|
TUnitInterface.LinkLibs and propagates to any program that uses the unit.
|
||||||
|
LibName is the bare name ('c', 'kernel32') — the link layer expands it per
|
||||||
|
platform (-l<name> on ELF, <name>.dll on PE). }
|
||||||
|
TLinkLibDecl = class(TASTNode)
|
||||||
|
public
|
||||||
|
LibName: string;
|
||||||
|
end;
|
||||||
|
|
||||||
{ ------------------------------------------------------------------ }
|
{ ------------------------------------------------------------------ }
|
||||||
{ Block and Program }
|
{ Block and Program }
|
||||||
{ ------------------------------------------------------------------ }
|
{ ------------------------------------------------------------------ }
|
||||||
|
|
@ -1082,6 +1096,7 @@ type
|
||||||
GenericMethodInstances: TObjectList; { owned TGenericMethodInstance — populated by uSemantic }
|
GenericMethodInstances: TObjectList; { owned TGenericMethodInstance — populated by uSemantic }
|
||||||
GenericIntfInstances: TObjectList; { owned TGenericInterfaceInstance — populated by uSemantic }
|
GenericIntfInstances: TObjectList; { owned TGenericInterfaceInstance — populated by uSemantic }
|
||||||
GenericRecordInstances: TObjectList; { owned TGenericRecordInstance — populated by uSemantic }
|
GenericRecordInstances: TObjectList; { owned TGenericRecordInstance — populated by uSemantic }
|
||||||
|
LinkLibs: TObjectList; { owned TLinkLibDecl — libraries to link, collected by the parser }
|
||||||
constructor Create;
|
constructor Create;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
end;
|
end;
|
||||||
|
|
@ -1105,6 +1120,7 @@ type
|
||||||
GenericMethodInstances: TObjectList;
|
GenericMethodInstances: TObjectList;
|
||||||
GenericIntfInstances: TObjectList;
|
GenericIntfInstances: TObjectList;
|
||||||
GenericRecordInstances: TObjectList;
|
GenericRecordInstances: TObjectList;
|
||||||
|
LinkLibs: TObjectList; { owned TLinkLibDecl — libraries to link, collected by the parser }
|
||||||
constructor Create;
|
constructor Create;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
end;
|
end;
|
||||||
|
|
@ -1811,6 +1827,7 @@ begin
|
||||||
GenericMethodInstances := TObjectList.Create(True);
|
GenericMethodInstances := TObjectList.Create(True);
|
||||||
GenericIntfInstances := TObjectList.Create(True);
|
GenericIntfInstances := TObjectList.Create(True);
|
||||||
GenericRecordInstances := TObjectList.Create(True);
|
GenericRecordInstances := TObjectList.Create(True);
|
||||||
|
LinkLibs := TObjectList.Create(True);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TConstDecl.Destroy;
|
destructor TConstDecl.Destroy;
|
||||||
|
|
@ -1841,6 +1858,7 @@ begin
|
||||||
GenericMethodInstances := TObjectList.Create(True);
|
GenericMethodInstances := TObjectList.Create(True);
|
||||||
GenericIntfInstances := TObjectList.Create(True);
|
GenericIntfInstances := TObjectList.Create(True);
|
||||||
GenericRecordInstances := TObjectList.Create(True);
|
GenericRecordInstances := TObjectList.Create(True);
|
||||||
|
LinkLibs := TObjectList.Create(True);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TUnit.Destroy;
|
destructor TUnit.Destroy;
|
||||||
|
|
@ -2437,6 +2455,7 @@ begin
|
||||||
Result.IsPublished := ASrc.IsPublished;
|
Result.IsPublished := ASrc.IsPublished;
|
||||||
Result.IsExternal := ASrc.IsExternal;
|
Result.IsExternal := ASrc.IsExternal;
|
||||||
Result.ExternalName := ASrc.ExternalName;
|
Result.ExternalName := ASrc.ExternalName;
|
||||||
|
Result.ExternalLib := ASrc.ExternalLib;
|
||||||
Result.CallingConv := ASrc.CallingConv;
|
Result.CallingConv := ASrc.CallingConv;
|
||||||
Result.IsRecordMethod := ASrc.IsRecordMethod;
|
Result.IsRecordMethod := ASrc.IsRecordMethod;
|
||||||
{ Static (class-level) methods take no implicit Self. Dropping this in the
|
{ Static (class-level) methods take no implicit Self. Dropping this in the
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,12 @@ type
|
||||||
FUsedUnits: TStringList; { unit names from every 'uses' clause, plus implicit
|
FUsedUnits: TStringList; { unit names from every 'uses' clause, plus implicit
|
||||||
'System'. Consulted purely as a syntactic name list
|
'System'. Consulted purely as a syntactic name list
|
||||||
to recognise 'UnitName.Symbol' — no symbol lookup. }
|
to recognise 'UnitName.Symbol' — no symbol lookup. }
|
||||||
|
FLinkLibs: TObjectList; { non-owning ref to the current TUnit/TProgram.LinkLibs;
|
||||||
|
external 'lib' decls append a TLinkLibDecl here as they
|
||||||
|
are parsed (any section). nil outside a unit/program. }
|
||||||
|
|
||||||
|
{ Record a 'link library X' dependency on the unit/program being parsed. }
|
||||||
|
procedure AddLinkLib(const ALibName: string; ALine, ACol: Integer);
|
||||||
function IsUsedUnit(const AName: string): Boolean;
|
function IsUsedUnit(const AName: string): Boolean;
|
||||||
function IsUnitPrefix(const AName: string): Boolean;
|
function IsUnitPrefix(const AName: string): Boolean;
|
||||||
{ Unbounded lookahead, exposed as scalar accessors (0 = FCurrent). A
|
{ Unbounded lookahead, exposed as scalar accessors (0 = FCurrent). A
|
||||||
|
|
@ -261,6 +266,20 @@ begin
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Case-insensitive membership test against the parsed 'uses' names. }
|
{ Case-insensitive membership test against the parsed 'uses' names. }
|
||||||
|
{ Append a 'link library ALibName' dependency to the unit/program being parsed.
|
||||||
|
Duplicates are tolerated — the exporter dedupes when building the .bif set. }
|
||||||
|
procedure TParser.AddLinkLib(const ALibName: string; ALine, ACol: Integer);
|
||||||
|
var
|
||||||
|
LL: TLinkLibDecl;
|
||||||
|
begin
|
||||||
|
if (FLinkLibs = nil) or (ALibName = '') then Exit;
|
||||||
|
LL := TLinkLibDecl.Create();
|
||||||
|
LL.LibName := ALibName;
|
||||||
|
LL.Line := ALine;
|
||||||
|
LL.Col := ACol;
|
||||||
|
FLinkLibs.Add(LL);
|
||||||
|
end;
|
||||||
|
|
||||||
function TParser.IsUsedUnit(const AName: string): Boolean;
|
function TParser.IsUsedUnit(const AName: string): Boolean;
|
||||||
var
|
var
|
||||||
I: Integer;
|
I: Integer;
|
||||||
|
|
@ -754,6 +773,7 @@ end;
|
||||||
function TParser.ParseProgram: TProgram;
|
function TParser.ParseProgram: TProgram;
|
||||||
begin
|
begin
|
||||||
Result := TProgram.Create();
|
Result := TProgram.Create();
|
||||||
|
FLinkLibs := Result.LinkLibs; { collect external 'lib' deps into the program }
|
||||||
try
|
try
|
||||||
Result.Line := FCurrent.Line;
|
Result.Line := FCurrent.Line;
|
||||||
Result.Col := FCurrent.Col;
|
Result.Col := FCurrent.Col;
|
||||||
|
|
@ -2505,6 +2525,15 @@ begin
|
||||||
begin
|
begin
|
||||||
Result.IsExternal := True;
|
Result.IsExternal := True;
|
||||||
Advance();
|
Advance();
|
||||||
|
{ optional: a library name string — external 'c' name 'malloc'.
|
||||||
|
Records a unit-level link dependency (works for implementation
|
||||||
|
imports too, so the private routine's library still propagates). }
|
||||||
|
if Check(tkStringLit) then
|
||||||
|
begin
|
||||||
|
Result.ExternalLib := FCurrent.Value;
|
||||||
|
AddLinkLib(FCurrent.Value, FCurrent.Line, FCurrent.Col);
|
||||||
|
Advance();
|
||||||
|
end;
|
||||||
{ optional: name 'c_symbol' }
|
{ optional: name 'c_symbol' }
|
||||||
if Check(tkIdent) and SameText(FCurrent.Value, 'name') then
|
if Check(tkIdent) and SameText(FCurrent.Value, 'name') then
|
||||||
begin
|
begin
|
||||||
|
|
@ -4471,6 +4500,14 @@ begin
|
||||||
begin
|
begin
|
||||||
Result.IsExternal := True;
|
Result.IsExternal := True;
|
||||||
Advance();
|
Advance();
|
||||||
|
{ optional library name — external 'c' name 'malloc' (records a
|
||||||
|
unit-level link dependency). }
|
||||||
|
if Check(tkStringLit) then
|
||||||
|
begin
|
||||||
|
Result.ExternalLib := FCurrent.Value;
|
||||||
|
AddLinkLib(FCurrent.Value, FCurrent.Line, FCurrent.Col);
|
||||||
|
Advance();
|
||||||
|
end;
|
||||||
if Check(tkIdent) and SameText(FCurrent.Value, 'name') then
|
if Check(tkIdent) and SameText(FCurrent.Value, 'name') then
|
||||||
begin
|
begin
|
||||||
Advance();
|
Advance();
|
||||||
|
|
@ -4523,6 +4560,7 @@ var
|
||||||
InitStmt: TASTStmt;
|
InitStmt: TASTStmt;
|
||||||
begin
|
begin
|
||||||
Result := TUnit.Create();
|
Result := TUnit.Create();
|
||||||
|
FLinkLibs := Result.LinkLibs; { collect external 'lib' deps into the unit }
|
||||||
try
|
try
|
||||||
Result.Line := FCurrent.Line;
|
Result.Line := FCurrent.Line;
|
||||||
Result.Col := FCurrent.Col;
|
Result.Col := FCurrent.Col;
|
||||||
|
|
|
||||||
|
|
@ -481,6 +481,13 @@ begin
|
||||||
if AUnit.ImplUsedUnits <> nil then
|
if AUnit.ImplUsedUnits <> nil then
|
||||||
for I := 0 to AUnit.ImplUsedUnits.Count - 1 do
|
for I := 0 to AUnit.ImplUsedUnits.Count - 1 do
|
||||||
AIface.ImplUsedUnits.Add(AUnit.ImplUsedUnits.Strings[I]);
|
AIface.ImplUsedUnits.Add(AUnit.ImplUsedUnits.Strings[I]);
|
||||||
|
{ Link libraries — hoisted from every 'external ''lib''' decl (interface or
|
||||||
|
implementation), deduped. Carries the unit's link dependencies into the
|
||||||
|
.bif even when the importing routine is implementation-private. }
|
||||||
|
if AUnit.LinkLibs <> nil then
|
||||||
|
for I := 0 to AUnit.LinkLibs.Count - 1 do
|
||||||
|
if AIface.LinkLibs.IndexOf(TLinkLibDecl(AUnit.LinkLibs.Items[I]).LibName) < 0 then
|
||||||
|
AIface.LinkLibs.Add(TLinkLibDecl(AUnit.LinkLibs.Items[I]).LibName);
|
||||||
AIface.HasInitialization :=
|
AIface.HasInitialization :=
|
||||||
(AUnit.InitStmts <> nil) and (AUnit.InitStmts.Count > 0);
|
(AUnit.InitStmts <> nil) and (AUnit.InitStmts.Count > 0);
|
||||||
end;
|
end;
|
||||||
|
|
|
||||||
|
|
@ -204,6 +204,14 @@ type
|
||||||
that loads this unit from its cached .bif
|
that loads this unit from its cached .bif
|
||||||
still pulls in (and links) impl-only
|
still pulls in (and links) impl-only
|
||||||
dependencies. }
|
dependencies. }
|
||||||
|
LinkLibs: TStringList; { owned — bare library names this unit must be
|
||||||
|
linked against (deduped), hoisted from every
|
||||||
|
'external ''lib''' decl, interface OR
|
||||||
|
implementation. An implementation-private
|
||||||
|
import keeps its symbol out of the .bif but
|
||||||
|
its library still propagates here, so a
|
||||||
|
downstream program links it (-l<name> /
|
||||||
|
<name>.dll). }
|
||||||
HasInitialization: Boolean; { unit has a non-empty initialization
|
HasInitialization: Boolean; { unit has a non-empty initialization
|
||||||
section. An incremental rebuild loads this
|
section. An incremental rebuild loads this
|
||||||
unit from its cached .bif and must still
|
unit from its cached .bif and must still
|
||||||
|
|
@ -402,6 +410,7 @@ begin
|
||||||
Name := AName;
|
Name := AName;
|
||||||
UsedUnits := TStringList.Create();
|
UsedUnits := TStringList.Create();
|
||||||
ImplUsedUnits := TStringList.Create();
|
ImplUsedUnits := TStringList.Create();
|
||||||
|
LinkLibs := TStringList.Create();
|
||||||
|
|
||||||
Types := TObjectList.Create(True);
|
Types := TObjectList.Create(True);
|
||||||
Consts := TObjectList.Create(True);
|
Consts := TObjectList.Create(True);
|
||||||
|
|
@ -432,6 +441,7 @@ begin
|
||||||
Consts.Free();
|
Consts.Free();
|
||||||
Types.Free();
|
Types.Free();
|
||||||
|
|
||||||
|
LinkLibs.Free();
|
||||||
ImplUsedUnits.Free();
|
ImplUsedUnits.Free();
|
||||||
UsedUnits.Free();
|
UsedUnits.Free();
|
||||||
inherited Destroy();
|
inherited Destroy();
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,14 @@ uses
|
||||||
|
|
||||||
const
|
const
|
||||||
IFACE_MAGIC = 'BLAISE-IFACE';
|
IFACE_MAGIC = 'BLAISE-IFACE';
|
||||||
IFACE_VERSION = 6; { v6 (this cycle): the `overload` directive now round-trips.
|
IFACE_VERSION = 7; { v7 (this cycle): external-library link dependencies now
|
||||||
|
round-trip. TUnitInterface.LinkLibs is serialised in
|
||||||
|
the META block (one EncodeStringList after
|
||||||
|
ImplUsedUnits, before HasInitialization) so a unit's
|
||||||
|
`external 'lib' name '...'` declarations propagate the
|
||||||
|
libraries to link. The META layout grew, so v6 readers
|
||||||
|
must reject these .bif and recompile.
|
||||||
|
v6: the `overload` directive now round-trips.
|
||||||
TRoutineSig.IsOverload added to EncodeMethodSig/
|
TRoutineSig.IsOverload added to EncodeMethodSig/
|
||||||
ReadMethodSig (one extra byte after IsStatic) and
|
ReadMethodSig (one extra byte after IsStatic) and
|
||||||
TMethodDecl.IsOverload added to EncodeMethodDecl/
|
TMethodDecl.IsOverload added to EncodeMethodDecl/
|
||||||
|
|
@ -735,6 +742,7 @@ begin
|
||||||
EncodeInt64(AIface.SourceModTime) +
|
EncodeInt64(AIface.SourceModTime) +
|
||||||
EncodeStringList(AIface.UsedUnits) +
|
EncodeStringList(AIface.UsedUnits) +
|
||||||
EncodeStringList(AIface.ImplUsedUnits) +
|
EncodeStringList(AIface.ImplUsedUnits) +
|
||||||
|
EncodeStringList(AIface.LinkLibs) +
|
||||||
EncodeBool(AIface.HasInitialization));
|
EncodeBool(AIface.HasInitialization));
|
||||||
SB.AppendLine('END');
|
SB.AppendLine('END');
|
||||||
Result := SB.ToString();
|
Result := SB.ToString();
|
||||||
|
|
@ -2120,6 +2128,9 @@ begin
|
||||||
C := DecodeCount(AText, APos);
|
C := DecodeCount(AText, APos);
|
||||||
for I := 1 to C do
|
for I := 1 to C do
|
||||||
AIface.ImplUsedUnits.Add(ReadLpstrAt(AText, APos));
|
AIface.ImplUsedUnits.Add(ReadLpstrAt(AText, APos));
|
||||||
|
C := DecodeCount(AText, APos);
|
||||||
|
for I := 1 to C do
|
||||||
|
AIface.LinkLibs.Add(ReadLpstrAt(AText, APos));
|
||||||
AIface.HasInitialization := ReadLpstrAt(AText, APos) = '1';
|
AIface.HasInitialization := ReadLpstrAt(AText, APos) = '1';
|
||||||
if ReadTag(AText, APos) <> 'END' then
|
if ReadTag(AText, APos) <> 'END' then
|
||||||
raise EIfaceFormatError.Create('META block: missing END marker');
|
raise EIfaceFormatError.Create('META block: missing END marker');
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,11 @@ type
|
||||||
{ Basic external call — strlen via external name }
|
{ Basic external call — strlen via external name }
|
||||||
procedure TestRun_ExternalName_Strlen;
|
procedure TestRun_ExternalName_Strlen;
|
||||||
|
|
||||||
|
{ Library-qualified external — external 'c' name 'strlen': the bare library
|
||||||
|
name is parsed and recorded (propagated via the unit's LinkLibs) while the
|
||||||
|
symbol resolves as usual. }
|
||||||
|
procedure TestRun_ExternalLibName_Strlen;
|
||||||
|
|
||||||
{ Narrow-int return masking: strlen returns size_t (64-bit) but declared
|
{ Narrow-int return masking: strlen returns size_t (64-bit) but declared
|
||||||
as Byte/Word/SmallInt — upper bits must be masked/sign-extended. }
|
as Byte/Word/SmallInt — upper bits must be masked/sign-extended. }
|
||||||
procedure TestRun_ExternalByteReturn_MaskedCorrectly;
|
procedure TestRun_ExternalByteReturn_MaskedCorrectly;
|
||||||
|
|
@ -70,6 +75,18 @@ begin
|
||||||
AssertRunsOnAll(Src, '5' + Chr(10), 0);
|
AssertRunsOnAll(Src, '5' + Chr(10), 0);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TE2EExternalTests.TestRun_ExternalLibName_Strlen;
|
||||||
|
const Src = '''
|
||||||
|
program T;
|
||||||
|
function c_strlen(S: PChar): Integer; external 'c' name 'strlen';
|
||||||
|
begin
|
||||||
|
WriteLn(c_strlen(PChar('hello')))
|
||||||
|
end.
|
||||||
|
''';
|
||||||
|
begin
|
||||||
|
AssertRunsOnAll(Src, '5' + Chr(10), 0);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TE2EExternalTests.TestRun_ExternalByteReturn_MaskedCorrectly;
|
procedure TE2EExternalTests.TestRun_ExternalByteReturn_MaskedCorrectly;
|
||||||
const Src = '''
|
const Src = '''
|
||||||
program T;
|
program T;
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@ type
|
||||||
procedure TestParse_ExternalProc_IsExternal;
|
procedure TestParse_ExternalProc_IsExternal;
|
||||||
procedure TestParse_ExternalProc_ExternalNameEmpty;
|
procedure TestParse_ExternalProc_ExternalNameEmpty;
|
||||||
procedure TestParse_ExternalProcNamed_ExternalName;
|
procedure TestParse_ExternalProcNamed_ExternalName;
|
||||||
|
{ Parser — library-qualified external records ExternalLib and hoists
|
||||||
|
the bare library name into the program's LinkLibs set. }
|
||||||
|
procedure TestParse_ExternalLibName_RecordsLibAndLinkLib;
|
||||||
{ Parser — standalone function }
|
{ Parser — standalone function }
|
||||||
procedure TestParse_ExternalFunc_IsExternal;
|
procedure TestParse_ExternalFunc_IsExternal;
|
||||||
procedure TestParse_ExternalFuncNamed_ExternalName;
|
procedure TestParse_ExternalFuncNamed_ExternalName;
|
||||||
|
|
@ -199,6 +202,36 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TExternalTests.TestParse_ExternalLibName_RecordsLibAndLinkLib;
|
||||||
|
var
|
||||||
|
Prog: TProgram;
|
||||||
|
Decl: TMethodDecl;
|
||||||
|
Lib: TLinkLibDecl;
|
||||||
|
begin
|
||||||
|
Prog := ParseSrc(
|
||||||
|
'''
|
||||||
|
program Test;
|
||||||
|
function c_strlen(S: PChar): Integer; external 'c' name 'strlen';
|
||||||
|
begin
|
||||||
|
end.
|
||||||
|
'''
|
||||||
|
);
|
||||||
|
try
|
||||||
|
Decl := TMethodDecl(Prog.Block.ProcDecls.Items[0]);
|
||||||
|
AssertTrue('IsExternal should be True', Decl.IsExternal);
|
||||||
|
AssertEquals('ExternalName should be strlen', 'strlen', Decl.ExternalName);
|
||||||
|
AssertEquals('ExternalLib should be c', 'c', Decl.ExternalLib);
|
||||||
|
|
||||||
|
{ The bare library name is hoisted into the program's LinkLibs set so
|
||||||
|
the link layer can expand it to -l<name>. }
|
||||||
|
AssertEquals('one link lib collected', 1, Prog.LinkLibs.Count);
|
||||||
|
Lib := TLinkLibDecl(Prog.LinkLibs.Items[0]);
|
||||||
|
AssertEquals('link lib name', 'c', Lib.LibName);
|
||||||
|
finally
|
||||||
|
Prog.Free();
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TExternalTests.TestParse_ExternalFunc_IsExternal;
|
procedure TExternalTests.TestParse_ExternalFunc_IsExternal;
|
||||||
var
|
var
|
||||||
Prog: TProgram;
|
Prog: TProgram;
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,8 @@ type
|
||||||
procedure TestWrite_StartsWithMagicAndVersion;
|
procedure TestWrite_StartsWithMagicAndVersion;
|
||||||
{ Unit name round-trips. }
|
{ Unit name round-trips. }
|
||||||
procedure TestRoundTrip_UnitNamePreserved;
|
procedure TestRoundTrip_UnitNamePreserved;
|
||||||
|
{ External-library link deps (LinkLibs) round-trip via the META block. }
|
||||||
|
procedure TestRoundTrip_LinkLibsPreserved;
|
||||||
{ Int const round-trips. }
|
{ Int const round-trips. }
|
||||||
procedure TestRoundTrip_IntConstPreserved;
|
procedure TestRoundTrip_IntConstPreserved;
|
||||||
{ String const round-trips, even with newlines + colons in the value. }
|
{ String const round-trips, even with newlines + colons in the value. }
|
||||||
|
|
@ -2693,12 +2695,12 @@ begin
|
||||||
Iface := TUnitInterface.Create('U');
|
Iface := TUnitInterface.Create('U');
|
||||||
try
|
try
|
||||||
Buf := WriteUnitInterface(Iface);
|
Buf := WriteUnitInterface(Iface);
|
||||||
{ Blaise Pos is 0-based; match-at-start returns 0. Version is 6 since the
|
{ Blaise Pos is 0-based; match-at-start returns 0. Version is 7 since
|
||||||
`overload` directive (TRoutineSig.IsOverload + TMethodDecl.IsOverload) was
|
TUnitInterface.LinkLibs (external-library link deps) was added to the
|
||||||
added to the method encoded layouts (on top of v5's member Visibility,
|
META block (on top of v6's `overload` directive, v5's member Visibility,
|
||||||
v4's TRoutineSig.IsStatic, and v3's static-member facts). }
|
v4's TRoutineSig.IsStatic, and v3's static-member facts). }
|
||||||
AssertTrue('starts with magic',
|
AssertTrue('starts with magic',
|
||||||
Pos('BLAISE-IFACE 6', Buf) = 0);
|
Pos('BLAISE-IFACE 7', Buf) = 0);
|
||||||
finally
|
finally
|
||||||
Iface.Free();
|
Iface.Free();
|
||||||
end;
|
end;
|
||||||
|
|
@ -2723,6 +2725,29 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TIfaceIOTests.TestRoundTrip_LinkLibsPreserved;
|
||||||
|
var
|
||||||
|
Src, Dst: TUnitInterface;
|
||||||
|
Buf: string;
|
||||||
|
begin
|
||||||
|
Src := TUnitInterface.Create('MyUnit');
|
||||||
|
try
|
||||||
|
Src.LinkLibs.Add('c');
|
||||||
|
Src.LinkLibs.Add('m');
|
||||||
|
Buf := WriteUnitInterface(Src);
|
||||||
|
Dst := ReadUnitInterface(Buf);
|
||||||
|
try
|
||||||
|
AssertEquals('link-lib count', 2, Dst.LinkLibs.Count);
|
||||||
|
AssertEquals('first lib', 'c', Dst.LinkLibs.Strings[0]);
|
||||||
|
AssertEquals('second lib', 'm', Dst.LinkLibs.Strings[1]);
|
||||||
|
finally
|
||||||
|
Dst.Free();
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
Src.Free();
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TIfaceIOTests.TestRoundTrip_IntConstPreserved;
|
procedure TIfaceIOTests.TestRoundTrip_IntConstPreserved;
|
||||||
var
|
var
|
||||||
Src, Dst: TUnitInterface;
|
Src, Dst: TUnitInterface;
|
||||||
|
|
|
||||||
|
|
@ -314,6 +314,7 @@ TUnitInterface.SourceModTime serialise
|
||||||
TUnitInterface.CompilerId serialise
|
TUnitInterface.CompilerId serialise
|
||||||
TUnitInterface.UsedUnits serialise
|
TUnitInterface.UsedUnits serialise
|
||||||
TUnitInterface.ImplUsedUnits serialise
|
TUnitInterface.ImplUsedUnits serialise
|
||||||
|
TUnitInterface.LinkLibs serialise
|
||||||
TUnitInterface.HasInitialization serialise
|
TUnitInterface.HasInitialization serialise
|
||||||
|
|
||||||
# TMethodParam (uAST.pas:798)
|
# TMethodParam (uAST.pas:798)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue