Browse Source

pastojs: added option -JoCheckVersion

git-svn-id: trunk@39851 -
Mattias Gaertner 6 years ago
parent
commit
cec7188704

+ 2 - 0
packages/fcl-passrc/tests/tcresolver.pas

@@ -916,7 +916,9 @@ procedure TCustomTestResolver.TearDown;
 {$IFDEF CheckPasTreeRefCount}
 {$IFDEF CheckPasTreeRefCount}
 var El: TPasElement;
 var El: TPasElement;
 {$ENDIF}
 {$ENDIF}
+{$IF defined(VerbosePasResolver) or defined(VerbosePasResolverMem)}
 var i: Integer;
 var i: Integer;
+{$ENDIF}
 begin
 begin
   FResolverMsgs.Clear;
   FResolverMsgs.Clear;
   FResolverGoodMsgs.Clear;
   FResolverGoodMsgs.Clear;

+ 74 - 6
packages/pastojs/src/fppas2js.pp

@@ -361,6 +361,7 @@ ToDos:
   v:=a[0]  gives Local variable "a" is assigned but never used
   v:=a[0]  gives Local variable "a" is assigned but never used
 - bug:
 - bug:
   exit(something) gives function result not set
   exit(something) gives function result not set
+- double utf8bom at start must give error  pscanner 4259
 - setlength(dynarray)  modeswitch to not create a copy
 - setlength(dynarray)  modeswitch to not create a copy
 - check rtl.js version
 - check rtl.js version
 - 'new', 'Function' -> class var use .prototype
 - 'new', 'Function' -> class var use .prototype
@@ -521,6 +522,7 @@ type
     pbifnAs,
     pbifnAs,
     pbifnAsExt,
     pbifnAsExt,
     pbifnCheckMethodCall,
     pbifnCheckMethodCall,
+    pbifnCheckVersion,
     pbifnClassInstanceFree,
     pbifnClassInstanceFree,
     pbifnClassInstanceNew,
     pbifnClassInstanceNew,
     pbifnCreateClass,
     pbifnCreateClass,
@@ -666,6 +668,7 @@ const
     'as', // rtl.as
     'as', // rtl.as
     'asExt', // rtl.asExt
     'asExt', // rtl.asExt
     'checkMethodCall',
     'checkMethodCall',
+    'checkVersion',
     '$destroy',
     '$destroy',
     '$create',
     '$create',
     'createClass', // rtl.createClass
     'createClass', // rtl.createClass
@@ -1404,7 +1407,10 @@ type
     coUseStrict,   // insert 'use strict'
     coUseStrict,   // insert 'use strict'
     coNoTypeInfo,  // do not generate RTTI
     coNoTypeInfo,  // do not generate RTTI
     coEliminateDeadCode,  // skip code that is never executed
     coEliminateDeadCode,  // skip code that is never executed
-    coStoreImplJS  // store references to JS code in procscopes
+    coStoreImplJS,  // store references to JS code in procscopes
+    coRTLVersionCheckMain, // insert rtl version check into main
+    coRTLVersionCheckSystem, // insert rtl version check into system unit init
+    coRTLVersionCheckUnit // insert rtl version check into every unit init
     );
     );
   TPasToJsConverterOptions = set of TPasToJsConverterOption;
   TPasToJsConverterOptions = set of TPasToJsConverterOption;
 const
 const
@@ -1470,6 +1476,7 @@ type
     FOnIsTypeInfoUsed: TPas2JSIsElementUsedEvent;
     FOnIsTypeInfoUsed: TPas2JSIsElementUsedEvent;
     FOptions: TPasToJsConverterOptions;
     FOptions: TPasToJsConverterOptions;
     FReservedWords: TJSReservedWordList; // sorted with CompareStr
     FReservedWords: TJSReservedWordList; // sorted with CompareStr
+    FRTLVersion: TJSNumber;
     FTargetPlatform: TPasToJsPlatform;
     FTargetPlatform: TPasToJsPlatform;
     FTargetProcessor: TPasToJsProcessor;
     FTargetProcessor: TPasToJsProcessor;
     Function CreatePrimitiveDotExpr(AName: string; Src: TPasElement): TJSElement;
     Function CreatePrimitiveDotExpr(AName: string; Src: TPasElement): TJSElement;
@@ -1643,6 +1650,7 @@ type
     Procedure AddInFrontOfFunctionTry(NewEl: TJSElement; PosEl: TPasElement;
     Procedure AddInFrontOfFunctionTry(NewEl: TJSElement; PosEl: TPasElement;
       FuncContext: TFunctionContext);
       FuncContext: TFunctionContext);
     Procedure AddInterfaceReleases(FuncContext: TFunctionContext; PosEl: TPasElement);
     Procedure AddInterfaceReleases(FuncContext: TFunctionContext; PosEl: TPasElement);
+    Procedure AddRTLVersionCheck(FuncContext: TFunctionContext; PosEl: TPasElement);
     // Statements
     // Statements
     Function ConvertImplBlockElements(El: TPasImplBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
     Function ConvertImplBlockElements(El: TPasImplBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
     Function ConvertBeginEndStatement(El: TPasImplBeginBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
     Function ConvertBeginEndStatement(El: TPasImplBeginBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
@@ -1783,6 +1791,7 @@ type
     Function ConvertPasElement(El: TPasElement; Resolver: TPas2JSResolver) : TJSElement;
     Function ConvertPasElement(El: TPasElement; Resolver: TPas2JSResolver) : TJSElement;
     // options
     // options
     Property Options: TPasToJsConverterOptions read FOptions write FOptions default DefaultPasToJSOptions;
     Property Options: TPasToJsConverterOptions read FOptions write FOptions default DefaultPasToJSOptions;
+    Property RTLVersion: TJSNumber read FRTLVersion write FRTLVersion;
     Property TargetPlatform: TPasToJsPlatform read FTargetPlatform write FTargetPlatform;
     Property TargetPlatform: TPasToJsPlatform read FTargetPlatform write FTargetPlatform;
     Property TargetProcessor: TPasToJsProcessor read FTargetProcessor write FTargetProcessor;
     Property TargetProcessor: TPasToJsProcessor read FTargetProcessor write FTargetProcessor;
     Property UseLowerCase: boolean read GetUseLowerCase write SetUseLowerCase default true;
     Property UseLowerCase: boolean read GetUseLowerCase write SetUseLowerCase default true;
@@ -5146,14 +5155,14 @@ Unit:
 *)
 *)
 Var
 Var
   OuterSrc , Src: TJSSourceElements;
   OuterSrc , Src: TJSSourceElements;
-  RegModuleCall: TJSCallExpression;
+  RegModuleCall, Call: TJSCallExpression;
   ArgArray: TJSArguments;
   ArgArray: TJSArguments;
   FunDecl, ImplFunc: TJSFunctionDeclarationStatement;
   FunDecl, ImplFunc: TJSFunctionDeclarationStatement;
   UsesSection: TPasSection;
   UsesSection: TPasSection;
   ModuleName, ModVarName: String;
   ModuleName, ModVarName: String;
   IntfContext: TSectionContext;
   IntfContext: TSectionContext;
   ImplVarSt: TJSVariableStatement;
   ImplVarSt: TJSVariableStatement;
-  HasImplUsesClause, ok: Boolean;
+  HasImplUsesClause, ok, NeedRTLCheckVersion: Boolean;
   UsesClause: TPasUsesClause;
   UsesClause: TPasUsesClause;
 begin
 begin
   Result:=Nil;
   Result:=Nil;
@@ -5191,6 +5200,16 @@ begin
       // "use strict" must be the first statement in a function
       // "use strict" must be the first statement in a function
       AddToSourceElements(Src,CreateLiteralString(El,'use strict'));
       AddToSourceElements(Src,CreateLiteralString(El,'use strict'));
 
 
+    NeedRTLCheckVersion:=(coRTLVersionCheckUnit in Options)
+        or ((coRTLVersionCheckSystem in Options) and IsSystemUnit(El));
+    if NeedRTLCheckVersion then
+      begin
+      Call:=CreateCallExpression(El);
+      Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnCheckVersion]]);
+      Call.AddArg(CreateLiteralNumber(El,RTLVersion));
+      AddToSourceElements(Src,Call);
+      end;
+
     ImplVarSt:=nil;
     ImplVarSt:=nil;
     HasImplUsesClause:=false;
     HasImplUsesClause:=false;
 
 
@@ -12654,7 +12673,7 @@ function TPasToJSConverter.ConvertInitializationSection(
 var
 var
   FDS: TJSFunctionDeclarationStatement;
   FDS: TJSFunctionDeclarationStatement;
   FunName: String;
   FunName: String;
-  IsMain: Boolean;
+  IsMain, NeedRTLCheckVersion: Boolean;
   AssignSt: TJSSimpleAssignStatement;
   AssignSt: TJSSimpleAssignStatement;
   FuncContext: TFunctionContext;
   FuncContext: TFunctionContext;
   Body: TJSFunctionBody;
   Body: TJSFunctionBody;
@@ -12681,13 +12700,17 @@ begin
     FunName:=FBuiltInNames[pbifnProgramMain]
     FunName:=FBuiltInNames[pbifnProgramMain]
   else
   else
     FunName:=FBuiltInNames[pbifnUnitInit];
     FunName:=FBuiltInNames[pbifnUnitInit];
+  NeedRTLCheckVersion:=IsMain and (coRTLVersionCheckMain in Options);
 
 
   FuncContext:=nil;
   FuncContext:=nil;
   AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
   AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
   try
   try
+    // $mod.$init =
     AssignSt.LHS:=CreateMemberExpression([FBuiltInNames[pbivnModule],FunName]);
     AssignSt.LHS:=CreateMemberExpression([FBuiltInNames[pbivnModule],FunName]);
-    FDS:=CreateFunctionSt(El,El.Elements.Count>0);
+    // = function(){...}
+    FDS:=CreateFunctionSt(El,(El.Elements.Count>0) or NeedRTLCheckVersion);
     AssignSt.Expr:=FDS;
     AssignSt.Expr:=FDS;
+
     if El.Elements.Count>0 then
     if El.Elements.Count>0 then
       begin
       begin
       Body:=FDS.AFunction.Body;
       Body:=FDS.AFunction.Body;
@@ -12700,6 +12723,16 @@ begin
       AddInterfaceReleases(FuncContext,El);
       AddInterfaceReleases(FuncContext,El);
       Body.A:=FuncContext.BodySt;
       Body.A:=FuncContext.BodySt;
       end;
       end;
+
+    if NeedRTLCheckVersion then
+      begin
+      // prepend rtl.versionCheck
+      Body:=FDS.AFunction.Body;
+      if FuncContext=nil then
+        FuncContext:=TFunctionContext.Create(El,Body,AContext);
+      AddRTLVersionCheck(FuncContext,El);
+      Body.A:=FuncContext.BodySt;
+      end;
     Result:=AssignSt;
     Result:=AssignSt;
   finally
   finally
     FuncContext.Free;
     FuncContext.Free;
@@ -14900,6 +14933,41 @@ begin
       end;
       end;
 end;
 end;
 
 
+procedure TPasToJSConverter.AddRTLVersionCheck(FuncContext: TFunctionContext;
+  PosEl: TPasElement);
+var
+  St: TJSElement;
+  Call: TJSCallExpression;
+  NewSt: TJSStatementList;
+begin
+  St:=FuncContext.BodySt;
+  // rtl.checkVersion(RTLVersion)
+  Call:=CreateCallExpression(PosEl);
+  Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnCheckVersion]]);
+  Call.AddArg(CreateLiteralNumber(PosEl,RTLVersion));
+  if St=nil then
+    FuncContext.BodySt:=Call
+  else if St is TJSEmptyBlockStatement then
+    begin
+    St.Free;
+    FuncContext.BodySt:=Call;
+    end
+  else if St is TJSStatementList then
+    begin
+    NewSt:=TJSStatementList(CreateElement(TJSStatementList,PosEl));
+    NewSt.A:=Call;
+    NewSt.B:=St;
+    FuncContext.BodySt:=NewSt;
+    end
+  else
+    begin
+    {$IFDEF VerbosePas2JS}
+    writeln('TPasToJSConverter.AddRTLVersionCheck St=',GetObjName(St));
+    {$ENDIF}
+    RaiseNotSupported(PosEl,FuncContext,20181002154026,GetObjName(St));
+    end;
+end;
+
 function TPasToJSConverter.ConvertImplBlock(El: TPasImplBlock;
 function TPasToJSConverter.ConvertImplBlock(El: TPasImplBlock;
   AContext: TConvertContext): TJSElement;
   AContext: TConvertContext): TJSElement;
 begin
 begin
@@ -16285,7 +16353,7 @@ end;
 
 
 function TPasToJSConverter.IsSystemUnit(aModule: TPasModule): boolean;
 function TPasToJSConverter.IsSystemUnit(aModule: TPasModule): boolean;
 begin
 begin
-  Result:=CompareText(aModule.Name,'system')=0;
+  Result:=(CompareText(aModule.Name,'system')=0) and (aModule.ClassType=TPasModule);
 end;
 end;
 
 
 function TPasToJSConverter.HasTypeInfo(El: TPasType; AContext: TConvertContext
 function TPasToJSConverter.HasTypeInfo(El: TPasType; AContext: TConvertContext

+ 28 - 0
packages/pastojs/src/pas2jscompiler.pp

@@ -116,8 +116,15 @@ type
     );
     );
   TP2jsCompilerOptions = set of TP2jsCompilerOption;
   TP2jsCompilerOptions = set of TP2jsCompilerOption;
   TP2jsOptimization = coEnumValuesAsNumbers..coKeepNotUsedDeclarationsWPO;
   TP2jsOptimization = coEnumValuesAsNumbers..coKeepNotUsedDeclarationsWPO;
+  TP2jsRTLVersionCheck = (
+    rvcNone,
+    rvcMain,
+    rvcSystem,
+    rvcUnit
+    );
 const
 const
   DefaultP2jsCompilerOptions = [coShowErrors,coSourceMapXSSIHeader,coUseStrict];
   DefaultP2jsCompilerOptions = [coShowErrors,coSourceMapXSSIHeader,coUseStrict];
+  DefaultP2jsRTLVersionCheck = rvcNone;
   coShowAll = [coShowErrors..coShowDebug];
   coShowAll = [coShowErrors..coShowDebug];
   coO1Enable = [coEnumValuesAsNumbers];
   coO1Enable = [coEnumValuesAsNumbers];
   coO1Disable = [coKeepNotUsedPrivates,coKeepNotUsedDeclarationsWPO];
   coO1Disable = [coKeepNotUsedPrivates,coKeepNotUsedDeclarationsWPO];
@@ -418,6 +425,7 @@ type
   private
   private
     FInterfaceType: TPasClassInterfaceType;
     FInterfaceType: TPasClassInterfaceType;
     FPrecompileInitialFlags: TPCUInitialFlags;
     FPrecompileInitialFlags: TPCUInitialFlags;
+    FRTLVersionCheck: TP2jsRTLVersionCheck;
     procedure AddDefinesForTargetPlatform;
     procedure AddDefinesForTargetPlatform;
     procedure AddDefinesForTargetProcessor;
     procedure AddDefinesForTargetProcessor;
     procedure AddReadingModule(aFile: TPas2jsCompilerFile);
     procedure AddReadingModule(aFile: TPas2jsCompilerFile);
@@ -507,6 +515,7 @@ type
     property ParamMacros: TPas2jsMacroEngine read FParamMacros;
     property ParamMacros: TPas2jsMacroEngine read FParamMacros;
     property PrecompileGUID: TGUID read FPrecompileGUID write FPrecompileGUID;
     property PrecompileGUID: TGUID read FPrecompileGUID write FPrecompileGUID;
     property PrecompileInitialFlags: TPCUInitialFlags read FPrecompileInitialFlags;
     property PrecompileInitialFlags: TPCUInitialFlags read FPrecompileInitialFlags;
+    property RTLVersionCheck: TP2jsRTLVersionCheck read FRTLVersionCheck write FRTLVersionCheck;
     property SrcMapEnable: boolean read GetSrcMapEnable write SetSrcMapEnable;
     property SrcMapEnable: boolean read GetSrcMapEnable write SetSrcMapEnable;
     property SrcMapSourceRoot: string read FSrcMapSourceRoot write FSrcMapSourceRoot;
     property SrcMapSourceRoot: string read FSrcMapSourceRoot write FSrcMapSourceRoot;
     property SrcMapBaseDir: string read GetSrcMapBaseDir write SetSrcMapBaseDir;
     property SrcMapBaseDir: string read GetSrcMapBaseDir write SetSrcMapBaseDir;
@@ -828,6 +837,13 @@ begin
     Include(Result,fppas2js.coLowerCase)
     Include(Result,fppas2js.coLowerCase)
   else
   else
     Exclude(Result,fppas2js.coLowerCase);
     Exclude(Result,fppas2js.coLowerCase);
+
+  case Compiler.RTLVersionCheck of
+    rvcNone: ;
+    rvcMain: Include(Result,fppas2js.coRTLVersionCheckMain);
+    rvcSystem: Include(Result,fppas2js.coRTLVersionCheckSystem);
+    rvcUnit: Include(Result,fppas2js.coRTLVersionCheckUnit);
+  end;
 end;
 end;
 
 
 procedure TPas2jsCompilerFile.CreateScannerAndParser(aFileResolver: TPas2jsFileResolver);
 procedure TPas2jsCompilerFile.CreateScannerAndParser(aFileResolver: TPas2jsFileResolver);
@@ -920,6 +936,7 @@ procedure TPas2jsCompilerFile.CreateConverter;
 begin
 begin
   if FConverter<>nil then exit;
   if FConverter<>nil then exit;
   FConverter:=TPasToJSConverter.Create;
   FConverter:=TPasToJSConverter.Create;
+  FConverter.RTLVersion:=(VersionMajor*100+VersionMinor)*100+VersionRelease;
   FConverter.Options:=GetInitialConverterOptions;
   FConverter.Options:=GetInitialConverterOptions;
   FConverter.TargetPlatform:=Compiler.TargetPlatform;
   FConverter.TargetPlatform:=Compiler.TargetPlatform;
   FConverter.TargetProcessor:=Compiler.TargetProcessor;
   FConverter.TargetProcessor:=Compiler.TargetProcessor;
@@ -3280,6 +3297,12 @@ begin
                 FileCache.SearchLikeFPC:=Enable
                 FileCache.SearchLikeFPC:=Enable
               else if SameText(Identifier,'UseStrict') then
               else if SameText(Identifier,'UseStrict') then
                 SetOption(coUseStrict,Enable)
                 SetOption(coUseStrict,Enable)
+              else if Enable and SameText(Identifier,'CheckVersion=main') then
+                RTLVersionCheck:=rvcMain
+              else if Enable and SameText(Identifier,'CheckVersion=system') then
+                RTLVersionCheck:=rvcSystem
+              else if Enable and SameText(Identifier,'CheckVersion=unit') then
+                RTLVersionCheck:=rvcUnit
               else
               else
                 UnknownParam;
                 UnknownParam;
             end;
             end;
@@ -3837,6 +3860,7 @@ begin
 
 
   FCompilerExe:='';
   FCompilerExe:='';
   FOptions:=DefaultP2jsCompilerOptions;
   FOptions:=DefaultP2jsCompilerOptions;
+  FRTLVersionCheck:=DefaultP2jsRTLVersionCheck;
   FMode:=p2jmObjFPC;
   FMode:=p2jmObjFPC;
   FTargetPlatform:=PlatformBrowser;
   FTargetPlatform:=PlatformBrowser;
   FTargetProcessor:=ProcessorECMAScript5;
   FTargetProcessor:=ProcessorECMAScript5;
@@ -4063,6 +4087,10 @@ begin
   l('   -Jo<x> : Enable or disable extra option. The x is case insensitive:');
   l('   -Jo<x> : Enable or disable extra option. The x is case insensitive:');
   l('     -JoSearchLikeFPC : search source files like FPC, default: search case insensitive.');
   l('     -JoSearchLikeFPC : search source files like FPC, default: search case insensitive.');
   l('     -JoUseStrict : add "use strict" to modules, default.');
   l('     -JoUseStrict : add "use strict" to modules, default.');
+  l('     -JoCheckVersion- : do not add rtl version check, default.');
+  l('     -JoCheckVersion=main : insert rtl version check into main.');
+  l('     -JoCheckVersion=system : insert rtl version check into system unit init.');
+  l('     -JoCheckVersion=unit : insert rtl version check into every unit init.');
   l('   -Ju<x> : Add <x> to foreign unit paths. Foreign units are not compiled.');
   l('   -Ju<x> : Add <x> to foreign unit paths. Foreign units are not compiled.');
   if PrecompileFormats.Count>0 then
   if PrecompileFormats.Count>0 then
   begin
   begin

+ 4 - 1
packages/pastojs/src/pas2jsfiler.pp

@@ -211,7 +211,10 @@ const
     'UseStrict',
     'UseStrict',
     'NoTypeInfo',
     'NoTypeInfo',
     'EliminateDeadCode',
     'EliminateDeadCode',
-    'StoreImplJS'
+    'StoreImplJS',
+    'RTLVersionCheckMain',
+    'RTLVersionCheckSystem',
+    'RTLVersionCheckUnit'
     );
     );
 
 
   PCUDefaultTargetPlatform = PlatformBrowser;
   PCUDefaultTargetPlatform = PlatformBrowser;

+ 104 - 8
packages/pastojs/tests/tcprecompile.pas

@@ -25,7 +25,7 @@ interface
 
 
 uses
 uses
   Classes, SysUtils,
   Classes, SysUtils,
-  fpcunit, testregistry, Pas2jsFileUtils, Pas2JsFiler,
+  fpcunit, testregistry, Pas2jsFileUtils, Pas2JsFiler, Pas2jsCompiler,
   tcunitsearch, tcmodules;
   tcunitsearch, tcmodules;
 
 
 type
 type
@@ -42,6 +42,7 @@ type
       SharedParams: TStringList = nil;
       SharedParams: TStringList = nil;
       FirstRunParams: TStringList = nil;
       FirstRunParams: TStringList = nil;
       SecondRunParams: TStringList = nil; ExpExitCode: integer = 0);
       SecondRunParams: TStringList = nil; ExpExitCode: integer = 0);
+    function GetJSFilename(ModuleName: string): string; virtual;
   public
   public
     constructor Create; override;
     constructor Create; override;
     property PCUFormat: TPas2JSPrecompileFormat read FPCUFormat write FPCUFormat;
     property PCUFormat: TPas2JSPrecompileFormat read FPCUFormat write FPCUFormat;
@@ -62,6 +63,9 @@ type
     procedure TestPCU_ClassConstructor;
     procedure TestPCU_ClassConstructor;
     procedure TestPCU_ClassInterface;
     procedure TestPCU_ClassInterface;
     procedure TestPCU_Namespace;
     procedure TestPCU_Namespace;
+    procedure TestPCU_CheckVersionMain;
+    procedure TestPCU_CheckVersionMain2;
+    procedure TestPCU_CheckVersionSystem;
   end;
   end;
 
 
 function LinesToList(const Lines: array of string): TStringList;
 function LinesToList(const Lines: array of string): TStringList;
@@ -98,13 +102,15 @@ begin
     writeln('TTestCLI_Precompile.CheckPrecompile create pcu files=========================');
     writeln('TTestCLI_Precompile.CheckPrecompile create pcu files=========================');
     {$ENDIF}
     {$ENDIF}
     Params.Clear;
     Params.Clear;
+    Params.Add('-Jminclude');
+    Params.Add('-Jc');
     if SharedParams<>nil then
     if SharedParams<>nil then
-      Params.Assign(SharedParams);
+      Params.AddStrings(SharedParams);
     if FirstRunParams<>nil then
     if FirstRunParams<>nil then
       Params.AddStrings(FirstRunParams);
       Params.AddStrings(FirstRunParams);
-    Compile([MainFile,'-Jc','-Fu'+UnitPaths,'-JU'+PCUFormat.Ext,'-FU'+UnitOutputDir,'-Jminclude']);
+    Compile([MainFile,'-Fu'+UnitPaths,'-JU'+PCUFormat.Ext,'-FU'+UnitOutputDir]);
     AssertFileExists(UnitOutputDir+'/system.'+PCUFormat.Ext);
     AssertFileExists(UnitOutputDir+'/system.'+PCUFormat.Ext);
-    JSFilename:=UnitOutputDir+PathDelim+ExtractFilenameOnly(MainFile)+'.js';
+    JSFilename:=GetJSFilename(MainFile);
     AssertFileExists(JSFilename);
     AssertFileExists(JSFilename);
     JSFile:=FindFile(JSFilename);
     JSFile:=FindFile(JSFilename);
     OrigSrc:=JSFile.Source;
     OrigSrc:=JSFile.Source;
@@ -115,19 +121,21 @@ begin
     JSFile.Source:='';
     JSFile.Source:='';
     Compiler.Reset;
     Compiler.Reset;
     Params.Clear;
     Params.Clear;
+    Params.Add('-Jminclude');
+    Params.Add('-Jc');
     if SharedParams<>nil then
     if SharedParams<>nil then
-      Params.Assign(SharedParams);
+      Params.AddStrings(SharedParams);
     if SecondRunParams<>nil then
     if SecondRunParams<>nil then
       Params.AddStrings(SecondRunParams);
       Params.AddStrings(SecondRunParams);
-    Compile([MainFile,'-Jc','-FU'+UnitOutputDir,'-Jminclude'],ExpExitCode);
+    Compile([MainFile,'-FU'+UnitOutputDir],ExpExitCode);
     if ExpExitCode=0 then
     if ExpExitCode=0 then
       begin
       begin
       NewSrc:=JSFile.Source;
       NewSrc:=JSFile.Source;
       if not CheckSrcDiff(OrigSrc,NewSrc,s) then
       if not CheckSrcDiff(OrigSrc,NewSrc,s) then
-      begin
+        begin
         WriteSources;
         WriteSources;
         Fail('test1.js: '+s);
         Fail('test1.js: '+s);
-      end;
+        end;
       end;
       end;
   finally
   finally
     SharedParams.Free;
     SharedParams.Free;
@@ -136,6 +144,11 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TCustomTestCLI_Precompile.GetJSFilename(ModuleName: string): string;
+begin
+  Result:=UnitOutputDir+PathDelim+ExtractFilenameOnly(ModuleName)+'.js';
+end;
+
 constructor TCustomTestCLI_Precompile.Create;
 constructor TCustomTestCLI_Precompile.Create;
 begin
 begin
   inherited Create;
   inherited Create;
@@ -461,6 +474,89 @@ begin
   AssertFileExists(UnitOutputDir+'/Web.Unit1.'+PCUFormat.Ext);
   AssertFileExists(UnitOutputDir+'/Web.Unit1.'+PCUFormat.Ext);
 end;
 end;
 
 
+procedure TTestCLI_Precompile.TestPCU_CheckVersionMain;
+var
+  aFile: TCLIFile;
+  s, JSFilename, ExpectedSrc: string;
+begin
+  AddUnit('src/system.pp',[
+    'type integer = longint;'],
+    ['']);
+  AddFile('test1.pas',[
+    'begin',
+    'end.']);
+  CheckPrecompile('test1.pas','src',LinesToList(['-JoCheckVersion=Main','-Jm-','-Jc-']));
+  JSFilename:=GetJSFilename('test1.js');
+  aFile:=FindFile(JSFilename);
+  AssertNotNull('File not found '+JSFilename,aFile);
+  ExpectedSrc:=LinesToStr([
+    UTF8BOM+'rtl.module("program",["system"],function () {',
+    '  "use strict";',
+    '  var $mod = this;',
+    '  $mod.$main = function () {',
+    '    rtl.checkVersion('+IntToStr((VersionMajor*100+VersionMinor)*100+VersionRelease)+');',
+    '  };',
+    '});']);
+  if not CheckSrcDiff(ExpectedSrc,aFile.Source,s) then
+    Fail('TTestCLI_Precompile.TestPCU_CheckVersionMain src diff: '+s);
+end;
+
+procedure TTestCLI_Precompile.TestPCU_CheckVersionMain2;
+var
+  aFile: TCLIFile;
+  s, JSFilename, ExpectedSrc: string;
+begin
+  AddUnit('src/system.pp',[
+    'type integer = longint;',
+    'procedure Writeln; varargs;'],
+    ['procedure Writeln; begin end;']);
+  AddFile('test1.pas',[
+    'begin',
+    '  Writeln;',
+    'end.']);
+  CheckPrecompile('test1.pas','src',LinesToList(['-JoCheckVersion=Main','-Jm-','-Jc-']));
+  JSFilename:=GetJSFilename('test1.js');
+  aFile:=FindFile(JSFilename);
+  AssertNotNull('File not found '+JSFilename,aFile);
+  ExpectedSrc:=LinesToStr([
+    UTF8BOM+'rtl.module("program",["system"],function () {',
+    '  "use strict";',
+    '  var $mod = this;',
+    '  $mod.$main = function () {',
+    '    rtl.checkVersion('+IntToStr((VersionMajor*100+VersionMinor)*100+VersionRelease)+');',
+    '    pas.system.Writeln();',
+    '  };',
+    '});']);
+  if not CheckSrcDiff(ExpectedSrc,aFile.Source,s) then
+    Fail('TTestCLI_Precompile.TestPCU_CheckVersionMain src diff: '+s);
+end;
+
+procedure TTestCLI_Precompile.TestPCU_CheckVersionSystem;
+var
+  aFile: TCLIFile;
+  s, JSFilename, ExpectedSrc: string;
+begin
+  AddUnit('src/system.pp',[
+    'type integer = longint;'],
+    ['']);
+  AddFile('test1.pas',[
+    'begin',
+    'end.']);
+  CheckPrecompile('test1.pas','src',LinesToList(['-JoCheckVersion=system','-Jm-','-Jc-']));
+  JSFilename:=GetJSFilename('system.js');
+  aFile:=FindFile(JSFilename);
+  AssertNotNull('File not found '+JSFilename,aFile);
+  writeln('TTestCLI_Precompile.TestPCU_CheckVersionMain ',aFile.Source);
+  ExpectedSrc:=LinesToStr([
+    UTF8BOM+'rtl.module("system",[],function () {',
+    '  "use strict";',
+    '  rtl.checkVersion(10101);',
+    '  var $mod = this;',
+    '});']);
+  if not CheckSrcDiff(ExpectedSrc,aFile.Source,s) then
+    Fail('TTestCLI_Precompile.TestPCU_CheckVersionMain src diff: '+s);
+end;
+
 Initialization
 Initialization
   {$IFDEF EnablePas2jsPrecompiled}
   {$IFDEF EnablePas2jsPrecompiled}
   RegisterTests([TTestCLI_Precompile]);
   RegisterTests([TTestCLI_Precompile]);

+ 6 - 0
utils/pas2js/dist/rtl.js

@@ -2,6 +2,8 @@
 
 
 var rtl = {
 var rtl = {
 
 
+  version: 10101,
+
   quiet: false,
   quiet: false,
   debug_load_units: false,
   debug_load_units: false,
   debug_rtti: false,
   debug_rtti: false,
@@ -20,6 +22,10 @@ var rtl = {
     rtl.debug('Warn: ',s);
     rtl.debug('Warn: ',s);
   },
   },
 
 
+  checkVersion: function(v){
+    if (rtl.version != v) throw "expected rtl version "+v+", but found "+rtl.version;
+  },
+
   hasString: function(s){
   hasString: function(s){
     return rtl.isString(s) && (s.length>0);
     return rtl.isString(s) && (s.length>0);
   },
   },