How can I make sure RTTI is available for a class without creating it?

I recently posted a question on this forum asking for any advice regarding the lack of RTTI information in the DXE2 executable.

This post was a stripped-down version of my actual case. RRUZ came to the rescue, and so the truncated version was quickly resolved. The original problem, however, is still standing, and so I publish it in its entirety. "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. 

Desired type not found. However, if I modify TRttiHelper.IsTypeFound so that it creates an instance of TMyClass (and immediately releases it), the type is found. For instance:

 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 if there is a way to get RTTI emitted for TMyClass without actually creating it?

Update:

On the side, no, I could mention that if I try to extract TRttiType using TRttiContext.GetType , the desired type will be found. So there is RTTI. Checking the TRttiType.IsPublic property obtained with TRttiContext.GetType gives a true value, i.e. The extracted type is public (and therefore can be found using TRttiContext.FindType ).

+6
source share
2 answers

Add a reference to the class and make sure that the compiler / linker cannot remove 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 like to place ForceReferenceToClass in the base unit so that it can be shared. The initialization section of the device declaring the class is the most natural place for ForceReferenceToClass calls, since the module is then self-contained.

As for your observation that GetType can find a type, the act of calling GetType(TMyClass) adds a reference to the type in the program. It is not that RTTI is present, but FindType cannot find it. Rather, the inclusion of GetType(TMyClass) adds RTTI to the resulting program.

+14
source

I used {$ STRONGLINKTYPES ON} and worked very well. Place it on the main unit.

+2
source

Source: https://habr.com/ru/post/915876/


All Articles