I've recently posted a question in this forum asking for any advice regarding missing RTTI information in a DXE2 executable.
That post was a stripped down version of my actual case. RRUZ came to the rescue, and so the stripped down version was quickly resolved. The original problem, though, is still standing, and so I'm posting it in full now. "Main":
program MissingRTTI;
{$APPTYPE CONSOLE}
uses
System.SysUtils, RTTI, MyUnit in 'MyUnit.pas', RTTIUtil in 'RTTIUtil.pas';
var
RHelp: TRttiHelper;
begin
RHelp := TRttiHelper.Create();
if (RHelp.IsTypeFound('MyUnit.TMyClass')) then WriteLn('TMyClass was found.')
else WriteLn('TMyClass was not found.');
ReadLn;
RHelp.Free();
end.
RTTIUtil.pas
:
unit RTTIUtil;
interface
uses
MyUnit;
type
TRttiHelper = class(TObject)
public
function IsTypeFound(TypeName: string) : boolean;
end;
implementation
uses
RTTI;
function TRttiHelper.IsTypeFound(TypeName: string): boolean;
var
rCtx: TRttiContext;
rType: TRttiType;
begin
Result := false;
rCtx := TRttiContext.Create();
rType := rCtx.FindType(TypeName);
if (rType <> nil) then
Result := true;
rCtx.Free();
end;
end.
and finally MyUnit.pas
:
unit MyUnit;
interface
type
TMyClass = class(TObject)
end;
implementation
end.
The desired type is not found. However, if I change TRttiHelper.IsTypeFound
so that it instantiates (and immediately frees) an instance of TMyClass
, the type is found. Like so:
function TRttiHelper.IsTypeFound(TypeName: string): boolean;
var
rCtx: TRttiContext;
rType: TRttiType;
MyObj: TMyClass;
begin
Result := false;
MyObj:= TMyClass.Create();
MyObj.Free();
rCtx := TRttiContext.Create();
...
So I'm wondering, is there any way I can force RTTI to be emitted for TMyClass
without actually instantiating it?
Update:
On a side not, I might mention that if I try to fetch the TRttiType using TRttiContext.GetType
, the desired type is found. So there is some RTTI emitted. Checking the TRttiType.IsPublic
property as retrieved by TRttiContext.GetType
yields a true value, i.e. the retrieved type is public (and hence should be possible to locate using TRttiContext.FindType
).
Add a reference to the class and make sure that the compiler/linker cannot strip it from the executable.
unit MyUnit;
interface
type
TMyClass = class(TObject)
end;
implementation
procedure ForceReferenceToClass(C: TClass);
begin
end;
initialization
ForceReferenceToClass(TMyClass);
end.
In production code you would want to place ForceReferenceToClass
in a base unit so that it could be shared. The initialization section of the unit that declares the class is the most natural place for the calls to ForceReferenceToClass
since the unit is then self-contained.
Regarding your observation that GetType
can locate the type, the very act of calling GetType(TMyClass)
adds a reference to the type to the program. It's not that the RTTI is present and FindType
cannot find it. Rather, the inclusion of GetType(TMyClass)
adds the RTTI to the resulting program.
I used {$STRONGLINKTYPES ON} and worked very well. Put it on main unit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With