dotest.pp 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202
  1. {
  2. This file is part of the Free Pascal test suite.
  3. Copyright (c) 1999-2002 by the Free Pascal development team.
  4. This program makes the compilation and
  5. execution of individual test sources.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$mode objfpc}
  13. {$goto on}
  14. {$H+}
  15. program dotest;
  16. uses
  17. sysutils,
  18. strutils,
  19. dos,
  20. {$ifdef macos}
  21. macutils,
  22. {$endif}
  23. tsstring,
  24. tsutils,
  25. tstypes,
  26. redir,
  27. bench,
  28. classes;
  29. {$ifdef go32v2}
  30. {$define LIMIT83FS}
  31. {$endif}
  32. {$ifdef os2}
  33. {$define LIMIT83FS}
  34. {$endif}
  35. {$ifdef msdos}
  36. {$define LIMIT83FS}
  37. {$endif}
  38. type
  39. tcompinfo = (compver,comptarget,compcpu);
  40. tdelexecutable = (deBefore, deAfter);
  41. tdelexecutables = set of tdelexecutable;
  42. const
  43. ObjExt='o';
  44. PPUExt='ppu';
  45. {$ifdef UNIX}
  46. SrcExeExt='';
  47. {$else UNIX}
  48. {$ifdef MACOS}
  49. SrcExeExt='';
  50. {$else MACOS}
  51. SrcExeExt='.exe';
  52. {$endif MACOS}
  53. {$endif UNIX}
  54. ExeExt : string = '';
  55. DllExt : string = '.so';
  56. DllPrefix: string = 'lib';
  57. DefaultTimeout=60;
  58. READ_ONLY = 0;
  59. var
  60. Config : TConfig;
  61. CompilerLogFile,
  62. ExeLogFile,
  63. LongLogfile,
  64. FailLogfile,
  65. RTLUnitsDir,
  66. TestOutputDir,
  67. OutputDir : string;
  68. CompilerBin,
  69. { CompilerCPU and CompilerTarget are lowercased at start
  70. to avoid need to call lowercase again and again ... }
  71. CompilerCPU,
  72. CompilerTarget,
  73. CompilerVersion,
  74. DefaultCompilerCPU,
  75. DefaultCompilerTarget,
  76. DefaultCompilerVersion : string;
  77. PPFile : TStringList;
  78. PPFileInfo : TStringList;
  79. TestName : string;
  80. Current : longint;
  81. const
  82. DoGraph : boolean = false;
  83. UseOSOnly : boolean = false;
  84. DoInteractive : boolean = false;
  85. DoExecute : boolean = false;
  86. DoKnown : boolean = false;
  87. DoAll : boolean = false;
  88. DoUsual : boolean = true;
  89. ForceTestThreads : Boolean = false;
  90. { TargetDir : string = ''; unused }
  91. BenchmarkInfo : boolean = false;
  92. ExtraCompilerOpts : string = '';
  93. DelExecutable : TDelExecutables = [];
  94. RemoteAddr : string = '';
  95. RemotePathPrefix : string = '';
  96. RemotePath : string = '/tmp';
  97. RemotePara : string = '';
  98. RemoteRshParas : string = '';
  99. RemoteShell : string = '';
  100. RemoteShellBase : string = '';
  101. RemoteShellNeedsExport : boolean = false;
  102. rshprog : string = 'rsh';
  103. rcpprog : string = 'rcp';
  104. rquote : string = '''';
  105. UseTimeout : boolean = false;
  106. emulatorname : string = '';
  107. EmulatorOpts : string = '';
  108. TargetCanCompileLibraries : boolean = true;
  109. UniqueSuffix: string = '';
  110. const
  111. NoSharedLibSupportPattern='$nosharedlib';
  112. TargetHasNoSharedLibSupport = 'msdos,go32v2';
  113. NoWorkingUnicodeSupport='$nounicode';
  114. TargetHasNoWorkingUnicodeSupport = 'msdos';
  115. NoWorkingThread='$nothread';
  116. TargetHasNoWorkingThreadSupport = 'go32v2,msdos,wasip1';
  117. procedure TranslateConfig(var AConfig: TConfig);
  118. begin
  119. AConfig.SkipTarget:=ReplaceText(AConfig.SkipTarget, NoSharedLibSupportPattern, TargetHasNoSharedLibSupport);
  120. AConfig.SkipTarget:=ReplaceText(AConfig.SkipTarget, NoWorkingUnicodeSupport, TargetHasNoWorkingUnicodeSupport);
  121. if not ForceTestThreads then
  122. AConfig.SkipTarget:=ReplaceText(AConfig.SkipTarget, NoWorkingThread, TargetHasNoWorkingThreadSupport);
  123. end;
  124. const
  125. VerbosePrefix : string = '';
  126. procedure Verbose(lvl:TVerboseLevel;const s:string);
  127. var
  128. su : string;
  129. begin
  130. if UniqueSuffix<>'' then
  131. begin
  132. if VerbosePrefix='' then
  133. VerbosePrefix:='#'+UniqueSuffix+'# ';
  134. su:=VerbosePrefix+s;
  135. tsutils.Verbose(lvl,su);
  136. end
  137. else
  138. tsutils.Verbose(lvl,s);
  139. end;
  140. function ToStr(l:longint):string;
  141. var
  142. s : string;
  143. begin
  144. Str(l,s);
  145. ToStr:=s;
  146. end;
  147. function ToStrZero(l:longint;nbzero : byte):string;
  148. var
  149. s : string;
  150. begin
  151. Str(l,s);
  152. while length(s)<nbzero do
  153. s:='0'+s;
  154. ToStrZero:=s;
  155. end;
  156. function trimspace(const s:string):string;
  157. var
  158. i,j : longint;
  159. begin
  160. i:=length(s);
  161. while (i>0) and (s[i] in [#9,' ']) do
  162. dec(i);
  163. j:=1;
  164. while (j<i) and (s[j] in [#9,' ']) do
  165. inc(j);
  166. trimspace:=Copy(s,j,i-j+1);
  167. end;
  168. function IsInList(const entry,list:string):boolean;
  169. var
  170. i,istart : longint;
  171. begin
  172. IsInList:=false;
  173. i:=0;
  174. while (i<length(list)) do
  175. begin
  176. { Find list item }
  177. istart:=i+1;
  178. while (i<length(list)) and
  179. (list[i+1]<>',') do
  180. inc(i);
  181. if Upcase(entry)=Upcase(TrimSpace(Copy(list,istart,i-istart+1))) then
  182. begin
  183. IsInList:=true;
  184. exit;
  185. end;
  186. { skip , }
  187. inc(i);
  188. end;
  189. end;
  190. procedure SetPPFileInfo;
  191. Var
  192. info : searchrec;
  193. dt : DateTime;
  194. begin
  195. FindFirst (PPFile[current],anyfile,Info);
  196. If DosError=0 then
  197. begin
  198. UnpackTime(info.time,dt);
  199. PPFileInfo.Insert(current,PPFile[current]+' '+ToStr(dt.year)+'/'+ToStrZero(dt.month,2)+'/'+
  200. ToStrZero(dt.day,2)+' '+ToStrZero(dt.Hour,2)+':'+ToStrZero(dt.min,2)+':'+ToStrZero(dt.sec,2));
  201. end
  202. else
  203. PPFileInfo.Insert(current,PPFile[current]);
  204. FindClose (Info);
  205. end;
  206. function ForceExtension(Const HStr,ext:String):String;
  207. {
  208. Return a filename which certainly has the extension ext
  209. }
  210. var
  211. j : longint;
  212. begin
  213. j:=length(Hstr);
  214. while (j>0) and (Hstr[j]<>'.') do
  215. dec(j);
  216. if j=0 then
  217. j:=length(Hstr)+1;
  218. if Ext<>'' then
  219. begin
  220. if Ext[1]='.' then
  221. ForceExtension:=Copy(Hstr,1,j-1)+Ext
  222. else
  223. ForceExtension:=Copy(Hstr,1,j-1)+'.'+Ext
  224. end
  225. else
  226. ForceExtension:=Copy(Hstr,1,j-1);
  227. end;
  228. procedure mkdirtree(const s:string);
  229. var
  230. SErr, hs : string;
  231. Err: longint;
  232. begin
  233. if s='' then
  234. exit;
  235. if s[length(s)] in ['\','/'{$IFDEF MACOS},':'{$ENDIF}] then
  236. hs:=Copy(s,1,length(s)-1)
  237. else
  238. hs:=s;
  239. if not PathExists(hs) then
  240. begin
  241. { Try parent first }
  242. mkdirtree(SplitPath(hs));
  243. { make this dir }
  244. Verbose(V_Debug,'Making directory '+s);
  245. {$I-}
  246. MkDir (HS);
  247. {$I+}
  248. Err := IOResult;
  249. if Err <> 0 then
  250. begin
  251. { did another parallel instance create it in the mean time? }
  252. if not PathExists(hs) then
  253. begin
  254. { no -> error }
  255. Str (Err, SErr);
  256. Verbose (V_Error, 'Directory creation of "'+HS+'" failed ' + SErr);
  257. end;
  258. end;
  259. end;
  260. end;
  261. Function RemoveFile(const f:string):boolean;
  262. var
  263. g : file;
  264. begin
  265. assign(g,f);
  266. {$I-}
  267. erase(g);
  268. {$I+}
  269. RemoveFile:=(ioresult=0);
  270. end;
  271. function Copyfile(const fn1,fn2:string;append:boolean) : longint;
  272. const
  273. bufsize = 16384;
  274. var
  275. f,g : file;
  276. oldfilemode : byte;
  277. st : string;
  278. addsize,
  279. i : longint;
  280. buf : pointer;
  281. begin
  282. if Append then
  283. Verbose(V_Debug,'Appending '+fn1+' to '+fn2)
  284. else
  285. Verbose(V_Debug,'Copying '+fn1+' to '+fn2);
  286. assign(g,fn2);
  287. if append then
  288. begin
  289. {$I-}
  290. reset(g,1);
  291. {$I+}
  292. if ioresult<>0 then
  293. append:=false
  294. else
  295. seek(g,filesize(g));
  296. end;
  297. if not append then
  298. begin
  299. {$I-}
  300. rewrite(g,1);
  301. {$I+}
  302. if ioresult<>0 then
  303. Verbose(V_Error,'Can''t open '+fn2+' for output');
  304. end;
  305. assign(f,fn1);
  306. {$I-}
  307. { Try using read only file mode }
  308. oldfilemode:=filemode;
  309. filemode:=READ_ONLY;
  310. reset(f,1);
  311. {$I+}
  312. addsize:=0;
  313. getmem(buf,bufsize);
  314. if ioresult<>0 then
  315. begin
  316. sleep(1000);
  317. {$I-}
  318. reset(f,1);
  319. {$I+}
  320. if ioresult<>0 then
  321. begin
  322. Verbose(V_Warning,'Can''t open '+fn1);
  323. st:='Can''t open '+fn1;
  324. i:=length(st);
  325. // blocksize is larger than 255, so no check is needed
  326. move(st[1],buf^,i);
  327. blockwrite(g,buf^,i);
  328. freemem(buf,bufsize);
  329. close(g);
  330. filemode:=oldfilemode;
  331. exit;
  332. end;
  333. end;
  334. filemode:=oldfilemode;
  335. repeat
  336. blockread(f,buf^,bufsize,i);
  337. blockwrite(g,buf^,i);
  338. addsize:=addsize+i;
  339. until i<bufsize;
  340. freemem(buf,bufsize);
  341. close(f);
  342. close(g);
  343. CopyFile:=addsize;
  344. end;
  345. procedure AddLog(const logfile,s:string);
  346. var
  347. t : text;
  348. begin
  349. assign(t,logfile);
  350. {$I-}
  351. append(t);
  352. {$I+}
  353. if ioresult<>0 then
  354. begin
  355. {$I-}
  356. rewrite(t);
  357. {$I+}
  358. if ioresult<>0 then
  359. Verbose(V_Abort,'Can''t append to '+logfile);
  360. end;
  361. writeln(t,s);
  362. close(t);
  363. end;
  364. procedure ForceLog(const logfile:string);
  365. var
  366. t : text;
  367. begin
  368. assign(t,logfile);
  369. {$I-}
  370. append(t);
  371. {$I+}
  372. if ioresult<>0 then
  373. begin
  374. {$I-}
  375. rewrite(t);
  376. {$I+}
  377. if ioresult<>0 then
  378. Verbose(V_Abort,'Can''t Create '+logfile);
  379. end;
  380. close(t);
  381. end;
  382. function GetCompilerInfo(c:tcompinfo):boolean;
  383. var
  384. t : text;
  385. hs : string;
  386. begin
  387. GetCompilerInfo:=false;
  388. { Try to get all information in one call, this is
  389. supported in 1.1. Older compilers 1.0.x will only
  390. return the first info }
  391. case c of
  392. compver :
  393. begin
  394. if DefaultCompilerVersion<>'' then
  395. begin
  396. GetCompilerInfo:=true;
  397. exit;
  398. end;
  399. hs:='-iVTPTO';
  400. end;
  401. compcpu :
  402. begin
  403. if DefaultCompilerCPU<>'' then
  404. begin
  405. GetCompilerInfo:=true;
  406. exit;
  407. end;
  408. hs:='-iTPTOV';
  409. end;
  410. comptarget :
  411. begin
  412. if DefaultCompilerTarget<>'' then
  413. begin
  414. GetCompilerInfo:=true;
  415. exit;
  416. end;
  417. hs:='-iTOTPV';
  418. end;
  419. end;
  420. ExecuteRedir(CompilerBin,hs,'','out.'+UniqueSuffix,'');
  421. assign(t,'out.'+UniqueSuffix);
  422. {$I-}
  423. reset(t);
  424. {$ifdef windows}
  425. { try to cope with Windows problems related to AntiVirus scanner
  426. that generate lag time during which access to a given if is forbidden }
  427. if (inoutres=5) then
  428. begin
  429. Sleep(5000);
  430. ioresult;
  431. Verbose(V_Warning,'Windows file not accessible out.'+UniqueSuffix);
  432. reset(t);
  433. end;
  434. {$endif windows}
  435. readln(t,hs);
  436. close(t);
  437. erase(t);
  438. {$I+}
  439. if ioresult<>0 then
  440. Verbose(V_Error,'Can''t get Compiler Info')
  441. else
  442. begin
  443. Verbose(V_Debug,'Retrieved Compiler Info: "'+hs+'"');
  444. case c of
  445. compver :
  446. begin
  447. DefaultCompilerVersion:=GetToken(hs);
  448. DefaultCompilerCPU:=GetToken(hs);
  449. DefaultCompilerTarget:=GetToken(hs);
  450. end;
  451. compcpu :
  452. begin
  453. DefaultCompilerCPU:=GetToken(hs);
  454. DefaultCompilerTarget:=GetToken(hs);
  455. DefaultCompilerVersion:=GetToken(hs);
  456. end;
  457. comptarget :
  458. begin
  459. DefaultCompilerTarget:=GetToken(hs);
  460. DefaultCompilerCPU:=GetToken(hs);
  461. DefaultCompilerVersion:=GetToken(hs);
  462. end;
  463. end;
  464. GetCompilerInfo:=true;
  465. end;
  466. end;
  467. function GetCompilerVersion:boolean;
  468. const
  469. CompilerVersionDebugWritten : boolean = false;
  470. begin
  471. if CompilerVersion='' then
  472. begin
  473. GetCompilerVersion:=GetCompilerInfo(compver);
  474. CompilerVersion:=DefaultCompilerVersion;
  475. end
  476. else
  477. GetCompilerVersion:=true;
  478. if GetCompilerVersion and not CompilerVersionDebugWritten then
  479. begin
  480. Verbose(V_Debug,'Compiler Version: "'+CompilerVersion+'"');
  481. CompilerVersionDebugWritten:=true;
  482. end;
  483. end;
  484. function GetCompilerCPU:boolean;
  485. const
  486. CompilerCPUDebugWritten : boolean = false;
  487. begin
  488. if CompilerCPU='' then
  489. begin
  490. GetCompilerCPU:=GetCompilerInfo(compcpu);
  491. CompilerCPU:=lowercase(DefaultCompilerCPU);
  492. end
  493. else
  494. GetCompilerCPU:=true;
  495. if GetCompilerCPU and not CompilerCPUDebugWritten then
  496. begin
  497. Verbose(V_Debug,'Compiler CPU: "'+CompilerCPU+'"');
  498. CompilerCPUDebugWritten:=true;
  499. end;
  500. end;
  501. function GetCompilerTarget:boolean;
  502. const
  503. CompilerTargetDebugWritten : boolean = false;
  504. begin
  505. if CompilerTarget='' then
  506. begin
  507. GetCompilerTarget:=GetCompilerInfo(comptarget);
  508. CompilerTarget:=lowercase(DefaultCompilerTarget);
  509. end
  510. else
  511. GetCompilerTarget:=true;
  512. if GetCompilerTarget and not CompilerTargetDebugWritten then
  513. begin
  514. Verbose(V_Debug,'Compiler Target: "'+CompilerTarget+'"');
  515. CompilerTargetDebugWritten:=true;
  516. end;
  517. end;
  518. function CompilerFullTarget:string;
  519. begin
  520. if UseOSOnly then
  521. CompilerFullTarget:=CompilerTarget
  522. else
  523. CompilerFullTarget:=CompilerCPU+'-'+CompilerTarget;
  524. end;
  525. { Set the three constants above according to
  526. the current target }
  527. procedure SetTargetDirectoriesStyle;
  528. var
  529. LTarget : string;
  530. begin
  531. { Call this first to ensure that CompilerTarget is not empty }
  532. GetCompilerTarget;
  533. LTarget := CompilerTarget;
  534. TargetHasDosStyleDirectories :=
  535. (LTarget='emx') or
  536. (LTarget='go32v2') or
  537. (LTarget='msdos') or
  538. (LTarget='nativent') or
  539. (LTarget='os2') or
  540. (LTarget='symbian') or
  541. (LTarget='watcom') or
  542. (LTarget='wdosx') or
  543. (LTarget='win16') or
  544. (LTarget='win32') or
  545. (LTarget='win64');
  546. TargetAmigaLike:=
  547. (LTarget='amiga') or
  548. (LTarget='morphos');
  549. TargetIsMacOS:=
  550. (LTarget='macos');
  551. { Base on whether UNIX is defined as default macro
  552. in extradefines in systesms/i_XXX.pas units }
  553. TargetIsUnix:=
  554. (LTarget='linux') or
  555. (LTarget='linux6432') or
  556. (LTarget='freebsd') or
  557. (LTarget='openbsd') or
  558. (LTarget='netbsd') or
  559. (LTarget='beos') or
  560. (LTarget='haiku') or
  561. (LTarget='solaris') or
  562. (LTarget='iphonesim') or
  563. (LTarget='darwin') or
  564. (LTarget='aix') or
  565. (LTarget='android');
  566. { Set ExeExt for CompilerTarget.
  567. This list has been set up 2013-01 using the information in
  568. compiler/system/i_XXX.pas units.
  569. We should update this list when adding new targets PM }
  570. if (TargetHasDosStyleDirectories) or (LTarget='wince') then
  571. begin
  572. ExeExt:='.exe';
  573. DllExt:='.dll';
  574. DllPrefix:='';
  575. end
  576. else if LTarget='atari' then
  577. begin
  578. ExeExt:='.tpp';
  579. DllExt:='.dll';
  580. DllPrefix:='';
  581. end
  582. else if LTarget='gba' then
  583. ExeExt:='.gba'
  584. else if LTarget='nds' then
  585. ExeExt:='.bin'
  586. else if (LTarget='netware') or (LTarget='netwlibc') then
  587. begin
  588. ExeExt:='.nlm';
  589. DllExt:='.nlm';
  590. DllPrefix:='';
  591. end
  592. else if LTarget='wii' then
  593. ExeExt:='.dol'
  594. else if (LTarget='wasip1') or (LTarget='wasip1threads') then
  595. ExeExt:='.wasm';
  596. end;
  597. {$ifndef LIMIT83FS}
  598. { Set the UseOSOnly constant above according to
  599. the current target }
  600. procedure SetUseOSOnly;
  601. var
  602. LTarget : string;
  603. begin
  604. { Call this first to ensure that CompilerTarget is not empty }
  605. GetCompilerTarget;
  606. LTarget := CompilerTarget;
  607. UseOSOnly:= (LTarget='emx') or
  608. (LTarget='go32v2') or
  609. (LTarget='msdos') or
  610. (LTarget='os2');
  611. end;
  612. {$endif not LIMIT83FS}
  613. procedure SetTargetCanCompileLibraries;
  614. var
  615. LTarget : string;
  616. begin
  617. { Call this first to ensure that CompilerTarget is not empty }
  618. GetCompilerTarget;
  619. LTarget := CompilerTarget;
  620. { Feel free to add other targets here }
  621. if (LTarget='go32v2') then
  622. TargetCanCompileLibraries:=false;
  623. end;
  624. function OutputFileName(Const s,ext:String):String;
  625. begin
  626. {$ifndef macos}
  627. OutputFileName:=OutputDir+'/'+ForceExtension(s,ext);
  628. {$else macos}
  629. OutputFileName:=ConcatMacPath(OutputDir,ForceExtension(s,ext));
  630. {$endif macos}
  631. end;
  632. function TestOutputFileName(Const pref,base,ext:String):String;
  633. begin
  634. {$ifndef macos}
  635. TestOutputFileName:=TestOutputDir+'/'+ForceExtension(pref+SplitFileName(base),ext);
  636. {$else macos}
  637. TestOutputFileName:=ConcatMacPath(TestOutputDir,ForceExtension(pref+SplitFileName(base),ext));
  638. {$endif macos}
  639. end;
  640. function TestLogFileName(Const pref,base,ext:String):String;
  641. var
  642. LogDir: String;
  643. begin
  644. LogDir:=TestOutputDir;
  645. {$ifndef macos}
  646. if UniqueSuffix<>'' then
  647. LogDir:=LogDir+'/..';
  648. TestLogFileName:=LogDir+'/'+ForceExtension(pref+SplitFileName(base),ext);
  649. {$else macos}
  650. if UniqueSuffix<>'' then
  651. LogDir:=LogDir+'::';
  652. TestLogFileName:=ConcatMacPath(LogDir,ForceExtension(pref+SplitFileName(base),ext));
  653. {$endif macos}
  654. end;
  655. function ExitWithInternalError(const OutName:string):boolean;
  656. var
  657. t : text;
  658. s : string;
  659. begin
  660. ExitWithInternalError:=false;
  661. { open logfile }
  662. assign(t,Outname);
  663. {$I-}
  664. reset(t);
  665. {$I+}
  666. if ioresult<>0 then
  667. exit;
  668. while not eof(t) do
  669. begin
  670. readln(t,s);
  671. if (pos('Fatal: Internal error ',s)>0) or
  672. (pos('Error: Compilation raised exception internally',s)>0) then
  673. begin
  674. ExitWithInternalError:=true;
  675. break;
  676. end;
  677. end;
  678. close(t);
  679. end;
  680. function CheckForMessages(const OutName:string;const Msgs:array of longint;var Found:array of boolean):boolean;
  681. var
  682. t : text;
  683. s,id : string;
  684. fnd,i : longint;
  685. begin
  686. CheckForMessages:=false;
  687. for i:=0 to high(Found) do
  688. Found[i]:=False;
  689. if length(Msgs)<>length(Found) then
  690. exit;
  691. assign(t,Outname);
  692. {$I-}
  693. reset(t);
  694. {$I+}
  695. if ioresult<>0 then
  696. exit;
  697. fnd:=0;
  698. for i:=0 to high(Found) do
  699. Found[i]:=False;
  700. while not eof(t) do
  701. begin
  702. readln(t,s);
  703. for i:=0 to high(Msgs) do
  704. begin
  705. str(Msgs[i],id);
  706. id:='('+id+')';
  707. if startsstr(id,s) or (pos(': '+id,s)>0) then
  708. begin
  709. if not Found[i] then
  710. inc(fnd);
  711. Found[i]:=True;
  712. { there can only be a single message per line }
  713. break;
  714. end;
  715. end;
  716. end;
  717. close(t);
  718. CheckForMessages:=fnd=Length(Msgs);
  719. end;
  720. { Takes each option from AddOptions list
  721. considered as a space separated list
  722. and adds the option to args
  723. unless option contains a percent sign,
  724. in that case, the option after % will be added
  725. to args only if CompilerTarget is listed in
  726. the string part before %.
  727. NOTE: this function does not check for
  728. quoted options...
  729. The list before % must of course contain no spaces. }
  730. procedure AppendOptions(AddOptions : string;var args : string);
  731. var
  732. endopt,percentpos : longint;
  733. opttarget, currentopt : string;
  734. begin
  735. Verbose(V_Debug,'AppendOptions called with AddOptions="'+AddOptions+'"');
  736. AddOptions:=trimspace(AddOptions);
  737. repeat
  738. endopt:=pos(' ',AddOptions);
  739. if endopt=0 then
  740. endopt:=length(AddOptions);
  741. currentopt:=trimspace(copy(AddOptions,1,endopt));
  742. AddOptions:=trimspace(copy(Addoptions,endopt+1,length(AddOptions)));
  743. if currentopt<>'' then
  744. begin
  745. percentpos:=pos('%',currentopt);
  746. if (percentpos=0) then
  747. begin
  748. Verbose(V_Debug,'Adding option="'+currentopt+'"');
  749. args:=args+' '+currentopt;
  750. end
  751. else
  752. begin
  753. opttarget:=lowercase(copy(currentopt,1,percentpos-1));
  754. if IsInList(CompilerTarget, opttarget) then
  755. begin
  756. Verbose(V_Debug,'Adding target specific option="'+currentopt+'" for '+opttarget);
  757. args:=args+' '+copy(currentopt,percentpos+1,length(currentopt))
  758. end
  759. else
  760. Verbose(V_Debug,'No matching target "'+currentopt+'"');
  761. end;
  762. end;
  763. until AddOptions='';
  764. end;
  765. { This function removes some incompatible
  766. options from TEST_OPT before adding them to
  767. the list of options passed to the compiler.
  768. %DELOPT=XYZ will remove XYZ exactly
  769. %DELOPT=XYZ* will remove all options starting with XYZ.
  770. NOTE: This fuinction does not handle quoted options. }
  771. function DelOptions(Pattern, opts : string) : string;
  772. var
  773. currentopt : string;
  774. optpos, endopt, startpos, endpos : longint;
  775. iswild : boolean;
  776. begin
  777. opts:=trimspace(opts);
  778. pattern:=trimspace(pattern);
  779. repeat
  780. endpos:=pos(' ',pattern);
  781. if endpos=0 then
  782. endpos:=length(pattern);
  783. currentopt:=trimspace(copy(pattern,1,endpos));
  784. pattern:=trimspace(copy(pattern,endpos+1,length(pattern)));
  785. if currentopt<>'' then
  786. begin
  787. if currentopt[length(currentopt)]='*' then
  788. begin
  789. iswild:=true;
  790. system.delete(currentopt,length(currentopt),1);
  791. end
  792. else
  793. iswild:=false;
  794. startpos:=1;
  795. repeat
  796. optpos:=pos(currentopt,copy(opts,startpos,length(opts)));
  797. if optpos>0 then
  798. begin
  799. { move to index in full opts string }
  800. optpos:=optpos+startpos-1;
  801. { compute position of end of opt }
  802. endopt:=optpos+length(currentopt);
  803. { use that end as start position for next round }
  804. startpos:=endopt;
  805. if iswild then
  806. begin
  807. while (opts[endopt]<>' ') and
  808. (endopt<length(opts)) do
  809. begin
  810. inc(endopt);
  811. inc(startpos);
  812. end;
  813. Verbose(V_Debug,'Pattern match found "'+currentopt+'*" in "'+opts+'"');
  814. system.delete(opts,optpos,endopt-optpos+1);
  815. Verbose(V_Debug,'After opts="'+opts+'"');
  816. end
  817. else
  818. begin
  819. if (endopt>length(opts)) or (opts[endopt]=' ') then
  820. begin
  821. Verbose(V_Debug,'Exact match found "'+currentopt+'" in "'+opts+'"');
  822. system.delete(opts,optpos,endopt-optpos+1);
  823. Verbose(V_Debug,'After opts="'+opts+'"');
  824. end
  825. else
  826. begin
  827. Verbose(V_Debug,'No exact match "'+currentopt+'" in "'+opts+'"');
  828. end;
  829. end;
  830. end;
  831. until optpos=0;
  832. end;
  833. until pattern='';
  834. DelOptions:=opts;
  835. end;
  836. function RunCompiler(const ExtraPara: string):boolean;
  837. var
  838. args,LocalExtraArgs,msgid,
  839. wpoargs,wposuffix : string;
  840. i,
  841. passnr,
  842. passes : longint;
  843. execres : boolean;
  844. EndTicks,
  845. StartTicks : int64;
  846. fndmsgs : array of boolean;
  847. begin
  848. RunCompiler:=false;
  849. args:='-n -T'+CompilerTarget+' -Fu'+RTLUnitsDir;
  850. if ExtraPara<>'' then
  851. args:=args+' '+ExtraPara;
  852. { the helper object files have been copied to the common directory }
  853. if UniqueSuffix<>'' then
  854. args:=args+' -Fo'+TestOutputDir+'/..';
  855. args:=args+' -FE'+TestOutputDir;
  856. if TargetIsMacOS then
  857. args:=args+' -WT '; {tests should be compiled as MPWTool}
  858. if Config.DelOptions<>'' then
  859. LocalExtraArgs:=DelOptions(Config.DelOptions,ExtraCompilerOpts)
  860. else
  861. LocalExtraArgs:=ExtraCompilerOpts;
  862. if LocalExtraArgs<>'' then
  863. args:=args+' '+LocalExtraArgs;
  864. if TargetIsUnix then
  865. begin
  866. { Add runtime library path to current dir to find .so files }
  867. if Config.NeedLibrary then
  868. begin
  869. if (CompilerTarget='darwin') or
  870. (CompilerTarget='aix') then
  871. args:=args+' -Fl'+TestOutputDir
  872. else
  873. { do not use single quote for -k as they are mishandled on
  874. Windows Shells }
  875. args:=args+' -Fl'+TestOutputDir+' -k-rpath -k.'
  876. end;
  877. end;
  878. if Config.NeedOptions<>'' then
  879. AppendOptions(Config.NeedOptions,args);
  880. { we need to check for message IDs, so request them }
  881. if Length(Config.ExpectMsgs) <> 0 then
  882. begin
  883. AppendOptions('-vq',args);
  884. SetLength(fndmsgs,Length(Config.ExpectMsgs));
  885. end;
  886. wpoargs:='';
  887. wposuffix:='';
  888. if (Config.WpoPasses=0) or
  889. (Config.WpoParas='') then
  890. passes:=1
  891. else
  892. passes:=config.wpopasses+1;
  893. args:=args+' '+PPFile[current];
  894. for passnr:=1 to passes do
  895. begin
  896. if (passes>1) then
  897. begin
  898. wposuffix:='_'+tostr(passnr);
  899. wpoargs:=' -OW'+config.wpoparas+' -FW'+TestOutputFileName('',PPFile[current],'wp'+tostr(passnr));
  900. if (passnr>1) then
  901. wpoargs:=wpoargs+' -Ow'+config.wpoparas+' -Fw'+TestOutputFileName('',PPFile[current],'wp'+tostr(passnr-1));
  902. end;
  903. Verbose(V_Debug,'Executing '+compilerbin+' '+args+wpoargs);
  904. { also get the output from as and ld that writes to stderr sometimes }
  905. StartTicks:=GetMicroSTicks;
  906. {$ifndef macos}
  907. execres:=ExecuteRedir(CompilerBin,args+wpoargs,'',CompilerLogFile+wposuffix,'stdout');
  908. {$else macos}
  909. {Due to that Toolserver is not reentrant, we have to asm and link via script.}
  910. execres:=ExecuteRedir(CompilerBin,'-s '+args+wpoargs,'',CompilerLogFile+wposuffix,'stdout');
  911. if execres then
  912. execres:=ExecuteRedir(TestOutputDir + ':ppas','','',CompilerLogFile+wpo_suffix,'stdout');
  913. {$endif macos}
  914. EndTicks:=GetMicroSTicks;
  915. Verbose(V_Debug,'Exitcode '+ToStr(ExecuteResult));
  916. if BenchmarkInfo then
  917. begin
  918. Verbose(V_Normal,'Compilation took '+ToStr(EndTicks-StartTicks)+' us');
  919. end;
  920. if passes > 1 then
  921. CopyFile(CompilerLogFile+wposuffix,CompilerLogFile,true);
  922. { Error during execution? }
  923. if (not execres) and (ExecuteResult=0) then
  924. begin
  925. AddLog(FailLogFile,TestName);
  926. AddLog(ResLogFile,failed_to_compile+PPFileInfo[current]);
  927. AddLog(LongLogFile,line_separation);
  928. AddLog(LongLogFile,failed_to_compile+PPFileInfo[current]);
  929. if CopyFile(CompilerLogFile,LongLogFile,true)=0 then
  930. AddLog(LongLogFile,'IOStatus'+ToStr(IOStatus));
  931. { avoid to try again }
  932. AddLog(ExeLogFile,failed_to_compile+PPFileInfo[current]);
  933. Verbose(V_Warning,'IOStatus: '+ToStr(IOStatus));
  934. exit;
  935. end;
  936. { Check for internal error }
  937. if ExitWithInternalError(CompilerLogFile) then
  938. begin
  939. AddLog(FailLogFile,TestName);
  940. if Config.Note<>'' then
  941. AddLog(FailLogFile,Config.Note);
  942. AddLog(ResLogFile,failed_to_compile+PPFileInfo[current]+' internalerror generated');
  943. AddLog(LongLogFile,line_separation);
  944. AddLog(LongLogFile,failed_to_compile+PPFileInfo[current]);
  945. if Config.Note<>'' then
  946. AddLog(LongLogFile,Config.Note);
  947. if CopyFile(CompilerLogFile,LongLogFile,true)=0 then
  948. AddLog(LongLogFile,'Internal error in compiler');
  949. { avoid to try again }
  950. AddLog(ExeLogFile,failed_to_compile+PPFileInfo[current]);
  951. Verbose(V_Warning,'Internal error in compiler');
  952. exit;
  953. end;
  954. if length(Config.ExpectMsgs)<>0 then
  955. begin
  956. Verbose(V_Debug,'Checking for messages: '+ToStr(Length(Config.ExpectMsgs)));
  957. if not CheckForMessages(CompilerLogFile,Config.ExpectMsgs,fndmsgs) then
  958. begin
  959. AddLog(FailLogFile,TestName);
  960. if Config.Note<>'' then
  961. AddLog(FailLogFile,Config.Note);
  962. AddLog(ResLogFile,message_missing+PPFileInfo[current]);
  963. AddLog(LongLogFile,line_separation);
  964. AddLog(LongLogFile,message_missing+PPFileInfo[current]);
  965. if Config.Note<>'' then
  966. AddLog(LongLogFile,Config.Note);
  967. for i:=0 to length(Config.ExpectMsgs) do
  968. if not fndmsgs[i] then
  969. begin
  970. str(Config.ExpectMsgs[i],msgid);
  971. AddLog(LongLogFile,message_missing+msgid);
  972. end;
  973. CopyFile(CompilerLogFile,LongLogFile,true);
  974. { avoid to try again }
  975. AddLog(ExeLogFile,message_missing+PPFileInfo[current]);
  976. exit;
  977. end
  978. else
  979. Verbose(V_Debug,'All messages found');
  980. end;
  981. end;
  982. { Should the compile fail ? }
  983. if Config.ShouldFail then
  984. begin
  985. if ExecuteResult<>0 then
  986. begin
  987. AddLog(ResLogFile,success_compilation_failed+PPFileInfo[current]);
  988. { avoid to try again }
  989. AddLog(ExeLogFile,success_compilation_failed+PPFileInfo[current]);
  990. RunCompiler:=true;
  991. end
  992. else
  993. begin
  994. AddLog(FailLogFile,TestName);
  995. if Config.Note<>'' then
  996. AddLog(FailLogFile,Config.Note);
  997. AddLog(ResLogFile,failed_compilation_successful+PPFileInfo[current]);
  998. AddLog(LongLogFile,line_separation);
  999. AddLog(LongLogFile,failed_compilation_successful+PPFileInfo[current]);
  1000. { avoid to try again }
  1001. AddLog(ExeLogFile,failed_compilation_successful+PPFileInfo[current]);
  1002. if Config.Note<>'' then
  1003. AddLog(LongLogFile,Config.Note);
  1004. CopyFile(CompilerLogFile,LongLogFile,true);
  1005. end;
  1006. end
  1007. else
  1008. begin
  1009. if (ExecuteResult<>0) and
  1010. (((Config.KnownCompileNote<>'') and (Config.KnownCompileError=0)) or
  1011. ((Config.KnownCompileError<>0) and (ExecuteResult=Config.KnownCompileError))) then
  1012. begin
  1013. AddLog(FailLogFile,TestName+known_problem+Config.KnownCompileNote);
  1014. AddLog(ResLogFile,failed_to_compile+PPFileInfo[current]+known_problem+Config.KnownCompileNote);
  1015. AddLog(LongLogFile,line_separation);
  1016. AddLog(LongLogFile,known_problem+Config.KnownCompileNote);
  1017. AddLog(LongLogFile,failed_to_compile+PPFileInfo[current]+' ('+ToStr(ExecuteResult)+')');
  1018. if Copyfile(CompilerLogFile,LongLogFile,true)=0 then
  1019. AddLog(LongLogFile,known_problem+'exitcode: '+ToStr(ExecuteResult));
  1020. Verbose(V_Warning,known_problem+'exitcode: '+ToStr(ExecuteResult));
  1021. end
  1022. else if ExecuteResult<>0 then
  1023. begin
  1024. AddLog(FailLogFile,TestName);
  1025. if Config.Note<>'' then
  1026. AddLog(FailLogFile,Config.Note);
  1027. AddLog(ResLogFile,failed_to_compile+PPFileInfo[current]);
  1028. AddLog(LongLogFile,line_separation);
  1029. AddLog(LongLogFile,failed_to_compile+PPFileInfo[current]);
  1030. if Config.Note<>'' then
  1031. AddLog(LongLogFile,Config.Note);
  1032. if CopyFile(CompilerLogFile,LongLogFile,true)=0 then
  1033. AddLog(LongLogFile,'Exitcode: '+ToStr(ExecuteResult)+' (expected 0)');
  1034. { avoid to try again }
  1035. AddLog(ExeLogFile,failed_to_compile+PPFileInfo[current]);
  1036. Verbose(V_Warning,'Exitcode: '+ToStr(ExecuteResult)+' (expected 0)');
  1037. end
  1038. else
  1039. begin
  1040. AddLog(ResLogFile,successfully_compiled+PPFileInfo[current]);
  1041. RunCompiler:=true;
  1042. end;
  1043. end;
  1044. end;
  1045. function CheckTestExitCode(const OutName:string):boolean;
  1046. var
  1047. t : text;
  1048. s : string;
  1049. i,code : integer;
  1050. is_wasi :boolean;
  1051. begin
  1052. CheckTestExitCode:=false;
  1053. { open logfile }
  1054. assign(t,Outname);
  1055. {$I-}
  1056. reset(t);
  1057. {$I+}
  1058. if ioresult<>0 then
  1059. exit;
  1060. GetCompilerTarget;
  1061. is_wasi:=(CompilerTarget='wasip1') or (CompilerTarget='wasip1threads');
  1062. while not eof(t) do
  1063. begin
  1064. readln(t,s);
  1065. if is_wasi then
  1066. begin
  1067. i:=pos('##WASI-EXITCODE: ',s);
  1068. if i>0 then
  1069. begin
  1070. delete(s,1,i+17-1);
  1071. val(s,ExecuteResult,code);
  1072. if code>1 then
  1073. val(copy(s,1,code-1),ExecuteResult,code);
  1074. if code=0 then
  1075. CheckTestExitCode:=true;
  1076. break;
  1077. end;
  1078. end
  1079. else
  1080. begin
  1081. i:=pos('TestExitCode: ',s);
  1082. if i>0 then
  1083. begin
  1084. delete(s,1,i+14-1);
  1085. val(s,ExecuteResult,code);
  1086. if code=0 then
  1087. CheckTestExitCode:=true;
  1088. break;
  1089. end;
  1090. end;
  1091. end;
  1092. close(t);
  1093. end;
  1094. function LibraryExists(const PPFile : string; out FileName : string) : boolean;
  1095. begin
  1096. { Check if a dynamic library XXX was created }
  1097. { Windows XXX.dll style }
  1098. FileName:=TestOutputFilename('',PPFile,'dll');
  1099. if FileExists(FileName) then
  1100. begin
  1101. LibraryExists:=true;
  1102. exit;
  1103. end;
  1104. { Linux libXXX.so style }
  1105. FileName:=TestOutputFilename('lib',PPFile,'so');
  1106. if FileExists(FileName) then
  1107. begin
  1108. LibraryExists:=true;
  1109. exit;
  1110. end;
  1111. { Darwin libXXX.dylib style }
  1112. FileName:=TestOutputFilename('lib',PPFile,'dylib');
  1113. if FileExists(FileName) then
  1114. begin
  1115. LibraryExists:=true;
  1116. exit;
  1117. end;
  1118. { MacOS LibXXX style }
  1119. FileName:=TestOutputFilename('Lib',PPFile,'');
  1120. if FileExists(FileName) then
  1121. begin
  1122. LibraryExists:=true;
  1123. exit;
  1124. end;
  1125. { Netware wlic XXX.nlm style }
  1126. FileName:=TestOutputFilename('',PPFile,'nlm');
  1127. if FileExists(FileName) then
  1128. begin
  1129. LibraryExists:=true;
  1130. exit;
  1131. end;
  1132. { Amiga XXX.library style }
  1133. FileName:=TestOutputFilename('',PPFile,'library');
  1134. if FileExists(FileName) then
  1135. begin
  1136. LibraryExists:=true;
  1137. exit;
  1138. end;
  1139. LibraryExists:=false;
  1140. end;
  1141. function ExecuteRemote(prog,args:string;out StartTicks,EndTicks : int64):boolean;
  1142. const
  1143. MaxTrials = 5;
  1144. var
  1145. Trials : longint;
  1146. Res : boolean;
  1147. begin
  1148. if SplitFileExt(prog)='' then
  1149. prog:=prog+SrcExeExt;
  1150. Verbose(V_Debug,'RemoteExecuting '+Prog+' '+args);
  1151. StartTicks:=GetMicroSTicks;
  1152. Res:=false;
  1153. Trials:=0;
  1154. While (Trials<MaxTrials) and not Res do
  1155. begin
  1156. inc(Trials);
  1157. Res:=ExecuteRedir(prog,args,'',EXELogFile,'stdout');
  1158. if not Res then
  1159. Verbose(V_Debug,'Call to '+prog+' failed: '+
  1160. 'IOStatus='+ToStr(IOStatus)+
  1161. ' RedirErrorOut='+ToStr(RedirErrorOut)+
  1162. ' RedirErrorIn='+ToStr(RedirErrorIn)+
  1163. ' RedirErrorError='+ToStr(RedirErrorError)+
  1164. ' ExecuteResult='+ToStr(ExecuteResult));
  1165. end;
  1166. if Trials>1 then
  1167. Verbose(V_Debug,'Done in '+tostr(trials)+' trials');
  1168. EndTicks:=GetMicroSTicks;
  1169. ExecuteRemote:=res;
  1170. end;
  1171. function ExecuteEmulated(const prog,args,FullExeLogFile:string;out StartTicks,EndTicks : int64):boolean;
  1172. begin
  1173. Verbose(V_Debug,'EmulatorExecuting '+Prog+' '+args);
  1174. StartTicks:=GetMicroSTicks;
  1175. ExecuteEmulated:=ExecuteRedir(prog,args,'',FullExeLogFile,'stdout');
  1176. EndTicks:=GetMicroSTicks;
  1177. end;
  1178. function MaybeCopyFiles(const FileToCopy : string) : boolean;
  1179. var
  1180. TestRemoteExe,
  1181. pref : string;
  1182. LocalFile, RemoteFile, s: string;
  1183. LocalPath: string;
  1184. i : integer;
  1185. execres : boolean;
  1186. EndTicks,
  1187. StartTicks : int64;
  1188. FileList : TStringList;
  1189. RelativeToConfigMarker : TObject;
  1190. function BuildFileList: TStringList;
  1191. var
  1192. s : string;
  1193. index : longint;
  1194. begin
  1195. s:=Config.Files;
  1196. if (length(s) = 0) and (Config.ConfigFileSrc='') then
  1197. begin
  1198. Result:=nil;
  1199. exit;
  1200. end;
  1201. Result:=TStringList.Create;
  1202. if s<>'' then
  1203. repeat
  1204. index:=pos(' ',s);
  1205. if index=0 then
  1206. LocalFile:=s
  1207. else
  1208. LocalFile:=copy(s,1,index-1);
  1209. Result.Add(LocalFile);
  1210. if index=0 then
  1211. break;
  1212. s:=copy(s,index+1,length(s)-index);
  1213. until false;
  1214. if Config.ConfigFileSrc<>'' then
  1215. begin
  1216. if Config.ConfigFileSrc=Config.ConfigFileDst then
  1217. Result.AddObject(Config.ConfigFileSrc,RelativeToConfigMarker)
  1218. else
  1219. Result.AddObject(Config.ConfigFileSrc+'='+Config.ConfigFileDst,RelativeToConfigMarker);
  1220. end;
  1221. end;
  1222. begin
  1223. RelativeToConfigMarker:=TObject.Create;
  1224. if RemoteAddr='' then
  1225. begin
  1226. FileList:=BuildFileList;
  1227. if assigned(FileList) then
  1228. begin
  1229. LocalPath:=SplitPath(PPFile[current]);
  1230. if Length(LocalPath) > 0 then
  1231. LocalPath:=LocalPath+'/';
  1232. for i:=0 to FileList.count-1 do
  1233. begin
  1234. if FileList.Names[i]<>'' then
  1235. begin
  1236. LocalFile:=FileList.Names[i];
  1237. RemoteFile:=FileList.ValueFromIndex[i];
  1238. end
  1239. else
  1240. begin
  1241. LocalFile:=FileList[i];
  1242. RemoteFile:=LocalFile;
  1243. end;
  1244. if FileList.Objects[i]=RelativeToConfigMarker then
  1245. s:='config/'+LocalFile
  1246. else
  1247. s:=LocalPath+LocalFile;
  1248. CopyFile(s,TestOutputDir+'/'+RemoteFile,false);
  1249. end;
  1250. FileList.Free;
  1251. end;
  1252. RelativeToConfigMarker.Free;
  1253. exit(true);
  1254. end;
  1255. execres:=true;
  1256. { Check if library should be deleted. Do not copy to remote target in such case. }
  1257. if (deAfter in DelExecutable) and (Config.DelFiles <> '') then
  1258. if SplitFileName(FileToCopy) = DllPrefix + Trim(Config.DelFiles) + DllExt then
  1259. exit;
  1260. { We don't want to create subdirs, remove paths from the test }
  1261. TestRemoteExe:=RemotePath+'/'+SplitFileName(FileToCopy);
  1262. if deBefore in DelExecutable then
  1263. begin
  1264. s:=RemoteRshParas+' rm ';
  1265. if rshprog <> 'adb' then
  1266. s:=s+'-f ';
  1267. ExecuteRemote(rshprog,s+TestRemoteExe,
  1268. StartTicks,EndTicks);
  1269. end;
  1270. execres:=ExecuteRemote(rcpprog,RemotePara+' '+FileToCopy+' '+
  1271. RemotePathPrefix+TestRemoteExe,StartTicks,EndTicks);
  1272. if not execres then
  1273. begin
  1274. Verbose(V_normal, 'Could not copy executable '+FileToCopy);
  1275. RelativeToConfigMarker.Free;
  1276. exit(execres);
  1277. end;
  1278. FileList:=BuildFileList;
  1279. if assigned(FileList) then
  1280. begin
  1281. LocalPath:=SplitPath(PPFile[current]);
  1282. if Length(LocalPath) > 0 then
  1283. LocalPath:=LocalPath+'/';
  1284. for i:=0 to FileList.count-1 do
  1285. begin
  1286. if FileList.Names[i]<>'' then
  1287. begin
  1288. LocalFile:=FileList.Names[i];
  1289. RemoteFile:=FileList.ValueFromIndex[i];
  1290. end
  1291. else
  1292. begin
  1293. LocalFile:=FileList[i];
  1294. RemoteFile:=LocalFile;
  1295. end;
  1296. RemoteFile:=RemotePath+'/'+SplitFileName(RemoteFile);
  1297. if FileList.Objects[i]=RelativeToConfigMarker then
  1298. LocalFile:='config/'+LocalFile
  1299. else
  1300. LocalFile:=LocalPath+LocalFile;
  1301. if DoVerbose and (rcpprog='pscp') then
  1302. pref:='-v '
  1303. else
  1304. pref:='';
  1305. execres:=ExecuteRemote(rcpprog,pref+RemotePara+' '+LocalFile+' '+
  1306. RemotePathPrefix+RemoteFile,StartTicks,EndTicks);
  1307. if not execres then
  1308. begin
  1309. Verbose(V_normal, 'Could not copy required file '+LocalFile);
  1310. FileList.Free;
  1311. RelativeToConfigMarker.Free;
  1312. exit(false);
  1313. end;
  1314. end;
  1315. end;
  1316. FileList.Free;
  1317. MaybeCopyFiles:=execres;
  1318. RelativeToConfigMarker.Free;
  1319. end;
  1320. function RunExecutable:boolean;
  1321. const
  1322. {$ifdef unix}
  1323. CurrDir = './';
  1324. {$else}
  1325. CurrDir = '';
  1326. {$endif}
  1327. var
  1328. OldDir, s, ss,
  1329. execcmd,
  1330. FullExeLogFile,
  1331. TestRemoteExe,
  1332. TestExe : string;
  1333. execres : boolean;
  1334. EndTicks,
  1335. StartTicks : int64;
  1336. OldExecuteResult: longint;
  1337. begin
  1338. RunExecutable:=false;
  1339. execres:=true;
  1340. TestExe:=TestOutputFilename('',PPFile[current],ExeExt);
  1341. execres:=MaybeCopyFiles(TestExe);
  1342. if EmulatorName<>'' then
  1343. begin
  1344. { Get full name out log file, because we change the directory during
  1345. execution }
  1346. FullExeLogFile:=FExpand(EXELogFile);
  1347. {$I-}
  1348. GetDir(0,OldDir);
  1349. ChDir(TestOutputDir);
  1350. {$I+}
  1351. ioresult;
  1352. s:=CurrDir+SplitFileName(TestExe);
  1353. { Add -Ssource_file_name for dosbox_wrapper }
  1354. if pos('dosbox_wrapper',EmulatorName)>0 then
  1355. s:=s+' -S'+PPFile[current];
  1356. execres:=ExecuteEmulated(EmulatorName,EmulatorOpts+' '+s,FullExeLogFile,StartTicks,EndTicks);
  1357. {$I-}
  1358. ChDir(OldDir);
  1359. {$I+}
  1360. GetCompilerTarget;
  1361. if (CompilerTarget='wasip1') or (CompilerTarget='wasip1threads') then
  1362. begin
  1363. CheckTestExitCode(FullEXELogFile);
  1364. end;
  1365. end
  1366. else if RemoteAddr<>'' then
  1367. begin
  1368. TestRemoteExe:=RemotePath+'/'+SplitFileName(TestExe);
  1369. { rsh doesn't pass the exitcode, use a second command to print the exitcode
  1370. on the remoteshell to stdout }
  1371. if DoVerbose and (rshprog='plink') then
  1372. execcmd:='-v '+RemoteRshParas
  1373. else
  1374. execcmd:=RemoteRshParas;
  1375. execcmd:=execcmd+' '+rquote+
  1376. 'chmod 755 '+TestRemoteExe+
  1377. ' && cd '+RemotePath+' && { ';
  1378. { Using -rpath . at compile time does not seem
  1379. to work for programs copied over to remote machine,
  1380. at least not for FreeBSD.
  1381. Does this work for all shells? }
  1382. if Config.NeedLibrary then
  1383. begin
  1384. if RemoteShellNeedsExport then
  1385. if CompilerTarget='darwin' then
  1386. execcmd:=execcmd+' DYLD_LIBRARY_PATH=.; export DYLD_LIBRARY_PATH;'
  1387. else
  1388. execcmd:=execcmd+' LD_LIBRARY_PATH=.; export LD_LIBRARY_PATH;'
  1389. else
  1390. if CompilerTarget='darwin' then
  1391. execcmd:=execcmd+' setenv DYLD_LIBRARY_PATH=.; '
  1392. else
  1393. execcmd:=execcmd+' setenv LD_LIBRARY_PATH=.; '
  1394. end;
  1395. if UseTimeout then
  1396. begin
  1397. if Config.Timeout=0 then
  1398. Config.Timeout:=DefaultTimeout;
  1399. str(Config.Timeout,s);
  1400. if (RemoteShellBase='bash') then
  1401. execcmd:=execcmd+'ulimit -t '+s+'; '
  1402. else
  1403. execcmd:=execcmd+'timeout -9 '+s;
  1404. end;
  1405. { as we moved to RemotePath, if path is not absolute
  1406. we need to use ./execfilename only }
  1407. if not isabsolute(TestRemoteExe) then
  1408. execcmd:=execcmd+' ./'+SplitFileName(TestRemoteExe)
  1409. else
  1410. execcmd:=execcmd+' '+TestRemoteExe;
  1411. execcmd:=execcmd+' ; echo TestExitCode: $?';
  1412. if (deAfter in DelExecutable) and
  1413. not Config.NeededAfter then
  1414. begin
  1415. { Delete executable if not needed after }
  1416. execcmd:=execcmd+' ; rm ';
  1417. if rshprog <> 'adb' then
  1418. execcmd:=execcmd+'-f ';
  1419. execcmd:=execcmd+SplitFileName(TestRemoteExe);
  1420. end;
  1421. execcmd:=execcmd+'; }'+rquote;
  1422. execres:=ExecuteRemote(rshprog,execcmd,StartTicks,EndTicks);
  1423. { Check for TestExitCode error in output, sets ExecuteResult }
  1424. if not CheckTestExitCode(EXELogFile) then
  1425. Verbose(V_Debug,'Failed to check exit code for '+execcmd);
  1426. if (deAfter in DelExecutable) and ( (Config.DelFiles <> '') or (Config.Files <> '')) then
  1427. begin
  1428. ss:=Trim(Config.DelFiles + ' ' + Config.Files);
  1429. execcmd:=RemoteRshParas+' ' + rquote + 'cd ' + RemotePath + ' && { ';
  1430. while ss <> '' do
  1431. begin
  1432. s:=Trim(GetToken(ss, [' ',',',';']));
  1433. if s = '' then
  1434. break;
  1435. if ExtractFileExt(s) = '' then
  1436. // If file has no extension, treat it as exe or shared lib
  1437. execcmd:=execcmd + 'rm ' + s + ExeExt + '; rm ' + DllPrefix + s + DllExt
  1438. else
  1439. execcmd:=execcmd + 'rm ' + s;
  1440. execcmd:=execcmd + '; ';
  1441. end;
  1442. execcmd:=execcmd+'}'+rquote;
  1443. // Save ExecuteResult and EXELogFile
  1444. OldExecuteResult:=ExecuteResult;
  1445. s:=EXELogFile;
  1446. // Output results of cleanup commands to stdout
  1447. EXELogFile:='';
  1448. ExecuteRemote(rshprog,execcmd,StartTicks,EndTicks);
  1449. // Restore
  1450. EXELogFile:=s;
  1451. ExecuteResult:=OldExecuteResult;
  1452. end;
  1453. end
  1454. else
  1455. begin
  1456. { Get full name out log file, because we change the directory during
  1457. execution }
  1458. FullExeLogFile:=FExpand(EXELogFile);
  1459. Verbose(V_Debug,'Executing '+TestExe);
  1460. {$I-}
  1461. GetDir(0,OldDir);
  1462. ChDir(TestOutputDir);
  1463. {$I+}
  1464. ioresult;
  1465. { don't redirect interactive and graph programs }
  1466. StartTicks:=GetMicroSTicks;
  1467. if Config.IsInteractive or Config.UsesGraph then
  1468. execres:=ExecuteRedir(CurrDir+SplitFileName(TestExe),'','','','')
  1469. else
  1470. execres:=ExecuteRedir(CurrDir+SplitFileName(TestExe),'','',FullExeLogFile,'stdout');
  1471. EndTicks:=GetMicroSTicks;
  1472. {$I-}
  1473. ChDir(OldDir);
  1474. {$I+}
  1475. ioresult;
  1476. end;
  1477. { Error during execution? }
  1478. Verbose(V_Debug,'Exitcode '+ToStr(ExecuteResult));
  1479. if BenchmarkInfo then
  1480. begin
  1481. Verbose(V_Normal,'Execution took '+ToStr(EndTicks-StartTicks)+' us');
  1482. end;
  1483. if (not execres) and (ExecuteResult=0) then
  1484. begin
  1485. AddLog(FailLogFile,TestName);
  1486. AddLog(ResLogFile,failed_to_run+PPFileInfo[current]);
  1487. AddLog(LongLogFile,line_separation);
  1488. AddLog(LongLogFile,failed_to_run+PPFileInfo[current]);
  1489. if CopyFile(EXELogFile,LongLogFile,true)=0 then
  1490. AddLog(LongLogFile,'IOStatus: '+ToStr(IOStatus));
  1491. { avoid to try again }
  1492. AddLog(ExeLogFile,failed_to_run+PPFileInfo[current]);
  1493. Verbose(V_Warning,'IOStatus: '+ToStr(IOStatus));
  1494. exit;
  1495. end;
  1496. if ExecuteResult<>Config.ResultCode then
  1497. begin
  1498. if (ExecuteResult<>0) and
  1499. (ExecuteResult=Config.KnownRunError) then
  1500. begin
  1501. AddLog(FailLogFile,TestName+known_problem+Config.KnownRunNote);
  1502. AddLog(ResLogFile,failed_to_run+PPFileInfo[current]+known_problem+Config.KnownRunNote);
  1503. AddLog(LongLogFile,line_separation);
  1504. AddLog(LongLogFile,known_problem+Config.KnownRunNote);
  1505. AddLog(LongLogFile,failed_to_run+PPFileInfo[current]+' ('+ToStr(ExecuteResult)+')');
  1506. if Copyfile(EXELogFile,LongLogFile,true)=0 then
  1507. begin
  1508. AddLog(LongLogFile,known_problem+'exitcode: '+ToStr(ExecuteResult)+' (expected '+ToStr(Config.ResultCode)+')');
  1509. AddLog(ExeLogFile,known_problem+'exitcode: '+ToStr(ExecuteResult)+' (expected '+ToStr(Config.ResultCode)+')');
  1510. end;
  1511. Verbose(V_Warning,known_problem+'exitcode: '+ToStr(ExecuteResult)+' (expected '+ToStr(Config.ResultCode)+')');
  1512. end
  1513. else
  1514. begin
  1515. AddLog(FailLogFile,TestName);
  1516. AddLog(ResLogFile,failed_to_run+PPFileInfo[current]);
  1517. AddLog(LongLogFile,line_separation);
  1518. AddLog(LongLogFile,failed_to_run+PPFileInfo[current]+' ('+ToStr(ExecuteResult)+')');
  1519. if Copyfile(EXELogFile,LongLogFile,true)=0 then
  1520. begin
  1521. AddLog(LongLogFile,'Exitcode: '+ToStr(ExecuteResult)+' (expected '+ToStr(Config.ResultCode)+')');
  1522. AddLog(ExeLogFile,'Exitcode: '+ToStr(ExecuteResult)+' (expected '+ToStr(Config.ResultCode)+')');
  1523. end;
  1524. Verbose(V_Warning,'Exitcode: '+ToStr(ExecuteResult)+' (expected '+ToStr(Config.ResultCode)+')');
  1525. end
  1526. end
  1527. else
  1528. begin
  1529. AddLog(ResLogFile,successfully_run+PPFileInfo[current]);
  1530. RunExecutable:=true;
  1531. end;
  1532. if (deAfter in DelExecutable) and not Config.NeededAfter then
  1533. begin
  1534. Verbose(V_Debug,'Deleting executable '+TestExe);
  1535. RemoveFile(TestExe);
  1536. RemoveFile(ForceExtension(TestExe,ObjExt));
  1537. RemoveFile(ForceExtension(TestExe,PPUExt));
  1538. end;
  1539. end;
  1540. { Try to collect information concerning the remote configuration
  1541. Currently only records RemoteShell name and sets
  1542. RemoteShellNeedsExport boolean variable }
  1543. procedure SetRemoteConfiguration;
  1544. var
  1545. f : text;
  1546. StartTicks,EndTicks : int64;
  1547. begin
  1548. if RemoteAddr='' then
  1549. exit;
  1550. if rshprog = 'adb' then
  1551. begin
  1552. RemoteShellNeedsExport:=true;
  1553. exit;
  1554. end;
  1555. ExeLogFile:='__remote.tmp';
  1556. ExecuteRemote(rshprog,RemoteRshParas+
  1557. ' "echo SHELL=${SHELL}"',StartTicks,EndTicks);
  1558. Assign(f,ExeLogFile);
  1559. Reset(f);
  1560. While not eof(f) do
  1561. begin
  1562. Readln(f,RemoteShellBase);
  1563. if pos('SHELL=',RemoteShellBase)>0 then
  1564. begin
  1565. RemoteShell:=TrimSpace(Copy(RemoteShellBase,pos('SHELL=',RemoteShellBase)+6,
  1566. length(RemoteShellBase)));
  1567. Verbose(V_Debug,'Remote shell is "'+RemoteShell+'"');
  1568. RemoteShellBase:=SplitFileBase(RemoteShell);
  1569. if (RemoteShellBase='bash') or (RemoteShellBase='sh') then
  1570. RemoteShellNeedsExport:=true;
  1571. end;
  1572. end;
  1573. Close(f);
  1574. end;
  1575. procedure getargs;
  1576. procedure helpscreen;
  1577. begin
  1578. writeln('dotest [Options] <File>');
  1579. writeln;
  1580. writeln('Options can be:');
  1581. writeln(' !ENV_NAME parse environment variable ENV_NAME for options');
  1582. writeln(' -A include ALL tests');
  1583. writeln(' -ADB use ADB to run tests');
  1584. writeln(' -B delete executable before remote upload');
  1585. writeln(' -C<compiler> set compiler to use');
  1586. writeln(' -D display execution time');
  1587. writeln(' -E execute test also');
  1588. writeln(' -G include graph tests');
  1589. writeln(' -I include interactive tests');
  1590. writeln(' -K include known bug tests');
  1591. writeln(' -L<ext> set extension of temporary files (prevent conflicts with parallel invocations)');
  1592. writeln(' -M<emulator> run the tests using the given emulator');
  1593. writeln(' -N<emulator opts.> pass options to the emulator');
  1594. writeln(' -O use timeout wrapper for (remote) execution');
  1595. writeln(' -P<path> path to the tests tree on the remote machine');
  1596. writeln(' -R<remote> run the tests remotely with the given rsh/ssh address');
  1597. writeln(' -S use ssh instead of rsh');
  1598. writeln(' -T[cpu-]<os> run tests for target cpu and os');
  1599. writeln(' -U<remotepara>');
  1600. writeln(' pass additional parameter to remote program. Multiple -U can be used');
  1601. writeln(' -V be verbose');
  1602. writeln(' -W use putty compatible file names when testing (plink and pscp)');
  1603. writeln(' -X don''t use COMSPEC');
  1604. writeln(' -Y<opts> extra options passed to the compiler. Several -Y<opt> can be given.');
  1605. writeln(' -Z remove temporary files (executable,ppu,o)');
  1606. halt(1);
  1607. end;
  1608. procedure interpret_option (para : string);
  1609. var
  1610. ch : char;
  1611. j : longint;
  1612. begin
  1613. Verbose(V_Debug,'Interpreting option"'+para+'"');
  1614. ch:=Upcase(para[2]);
  1615. delete(para,1,2);
  1616. case ch of
  1617. 'A' :
  1618. if UpperCase(para) = 'DB' then
  1619. begin
  1620. rshprog:='adb';
  1621. rcpprog:='adb';
  1622. rquote:='"';
  1623. if RemoteAddr = '' then
  1624. RemoteAddr:='1'; // fake remote addr (default device will be used)
  1625. end
  1626. else
  1627. begin
  1628. DoGraph:=true;
  1629. DoInteractive:=true;
  1630. DoKnown:=true;
  1631. DoAll:=true;
  1632. end;
  1633. 'B' : Include(DelExecutable,deBefore);
  1634. 'C' : CompilerBin:=Para;
  1635. 'D' : BenchMarkInfo:=true;
  1636. 'E' : DoExecute:=true;
  1637. 'G' : begin
  1638. DoGraph:=true;
  1639. if para='-' then
  1640. DoUsual:=false;
  1641. end;
  1642. 'I' : begin
  1643. DoInteractive:=true;
  1644. if para='-' then
  1645. DoUsual:=false;
  1646. end;
  1647. 'K' : begin
  1648. DoKnown:=true;
  1649. if para='-' then
  1650. DoUsual:=false;
  1651. end;
  1652. 'L' : begin
  1653. UniqueSuffix:=Para;
  1654. if UniqueSuffix='' then
  1655. UniqueSuffix:=toStr(system.GetProcessID);
  1656. end;
  1657. 'M' : EmulatorName:=Para;
  1658. 'N' : EmulatorOpts:=Para;
  1659. 'O' : UseTimeout:=true;
  1660. 'P' : RemotePath:=Para;
  1661. 'R' : RemoteAddr:=Para;
  1662. 'S' :
  1663. begin
  1664. rshprog:='ssh';
  1665. rcpprog:='scp';
  1666. end;
  1667. 'T' :
  1668. begin
  1669. j:=Pos('-',Para);
  1670. if j>0 then
  1671. begin
  1672. CompilerCPU:=Copy(Para,1,j-1);
  1673. CompilerTarget:=Copy(Para,j+1,length(para));
  1674. end
  1675. else
  1676. CompilerTarget:=Para
  1677. end;
  1678. 'U' :
  1679. RemotePara:=RemotePara+' '+Para;
  1680. 'V' : DoVerbose:=true;
  1681. 'W' :
  1682. begin
  1683. rshprog:='plink';
  1684. rcpprog:='pscp';
  1685. rquote:='"';
  1686. end;
  1687. 'X' : UseComSpec:=false;
  1688. 'Y' : ExtraCompilerOpts:= ExtraCompilerOpts +' '+ Para;
  1689. 'Z' : Include(DelExecutable,deAfter);
  1690. end;
  1691. end;
  1692. procedure interpret_env(arg : string);
  1693. var
  1694. para : string;
  1695. pspace : longint;
  1696. begin
  1697. Verbose(V_Debug,'Interpreting environment option"'+arg+'"');
  1698. { Get rid of leading '!' }
  1699. delete(arg,1,1);
  1700. arg:=getenv(arg);
  1701. Verbose(V_Debug,'Environment value is "'+arg+'"');
  1702. while (length(arg)>0) do
  1703. begin
  1704. while (length(arg)>0) and (arg[1]=' ') do
  1705. delete(arg,1,1);
  1706. pspace:=pos(' ',arg);
  1707. if pspace=0 then
  1708. pspace:=length(arg)+1;
  1709. para:=copy(arg,1,pspace-1);
  1710. if (length(para)>0) and (para[1]='-') then
  1711. interpret_option (para)
  1712. else
  1713. begin
  1714. PPFile.Insert(current,ForceExtension(Para,'pp'));
  1715. inc(current);
  1716. end;
  1717. delete(arg,1,pspace);
  1718. end;
  1719. end;
  1720. var
  1721. param : string;
  1722. i : longint;
  1723. begin
  1724. CompilerBin:='ppc386'+srcexeext;
  1725. for i:=1 to paramcount do
  1726. begin
  1727. param:=Paramstr(i);
  1728. if (param[1]='-') then
  1729. interpret_option(param)
  1730. else if (param[1]='!') then
  1731. interpret_env(param)
  1732. else
  1733. begin
  1734. PPFile.Insert(current,ForceExtension(Param,'pp'));
  1735. inc(current);
  1736. end;
  1737. end;
  1738. if current=0 then
  1739. HelpScreen;
  1740. { disable graph,interactive when running remote }
  1741. if RemoteAddr<>'' then
  1742. begin
  1743. DoGraph:=false;
  1744. DoInteractive:=false;
  1745. end;
  1746. { If we use PuTTY plink program with -load option,
  1747. the IP address or name should not be added to
  1748. the command line }
  1749. if (rshprog='plink') and (pos('-load',RemotePara)>0) then
  1750. RemoteRshParas:=RemotePara
  1751. else
  1752. if rshprog='adb' then
  1753. begin
  1754. if RemoteAddr <> '1' then
  1755. RemotePara:=Trim('-s ' + RemoteAddr + ' ' + RemotePara);
  1756. RemoteRshParas:=Trim(RemotePara + ' shell');
  1757. end
  1758. else
  1759. RemoteRshParas:=RemotePara+' '+RemoteAddr;
  1760. if rcpprog = 'adb' then
  1761. begin
  1762. RemotePathPrefix:='';
  1763. RemotePara:=Trim(RemotePara + ' push');
  1764. end
  1765. else
  1766. RemotePathPrefix:=RemoteAddr + ':';
  1767. end;
  1768. procedure RunTest;
  1769. var
  1770. PPDir,LibraryName,LogSuffix,PPPrefix : string;
  1771. Res : boolean;
  1772. begin
  1773. Res:=GetConfig('',PPFile[current],Config);
  1774. TranslateConfig(Config);
  1775. if Res then
  1776. begin
  1777. Res:=GetCompilerCPU;
  1778. Res:=GetCompilerTarget;
  1779. {$ifndef MACOS}
  1780. RTLUnitsDir:='tstunits/'+CompilerFullTarget;
  1781. {$else MACOS}
  1782. RTLUnitsDir:=':tstunits:'+CompilerFullTarget;
  1783. {$endif MACOS}
  1784. if not PathExists(RTLUnitsDir) then
  1785. Verbose(V_Abort,'Unit path "'+RTLUnitsDir+'" does not exists');
  1786. {$ifndef MACOS}
  1787. OutputDir:='output/'+CompilerFullTarget;
  1788. {$else MACOS}
  1789. OutputDir:=':output:'+CompilerFullTarget;
  1790. {$endif MACOS}
  1791. if not PathExists(OutputDir) then
  1792. Verbose(V_Abort,'Output path "'+OutputDir+'" does not exists');
  1793. { Make subdir in output if needed }
  1794. PPDir:=SplitPath(PPFile[current]);
  1795. if PPDir[length(PPDir)] in ['/','\'{$ifdef MACOS},':'{$endif MACOS}] then
  1796. Delete(PPDir,length(PPDir),1);
  1797. if PPDir<>'' then
  1798. begin
  1799. {$ifndef MACOS}
  1800. { handle paths that are parallel to the tests directory (let's hope
  1801. that noone uses ../../ -.- ) }
  1802. { ToDo: check relative paths on MACOS }
  1803. PPPrefix:=Copy(PPDir,1,3);
  1804. if (PPPrefix='../') or (PPPrefix='..\') then
  1805. PPDir:='root/'+Copy(PPDir,4,length(PPDir));
  1806. TestOutputDir:=OutputDir+'/'+PPDir;
  1807. if UniqueSuffix<>'' then
  1808. TestOutputDir:=TestOutputDir+'/'+UniqueSuffix;
  1809. {$else MACOS}
  1810. TestOutputDir:=OutputDir+PPDir;
  1811. if UniqueSuffix<>'' then
  1812. TestOutputDir:=TestOutputDir+':'+UniqueSuffix;
  1813. {$endif MACOS}
  1814. mkdirtree(TestOutputDir);
  1815. end
  1816. else
  1817. TestOutputDir:=OutputDir;
  1818. if UniqueSuffix<>'' then
  1819. LogSuffix:=UniqueSuffix
  1820. else
  1821. LogSuffix:=SplitBasePath(PPDir)+'log';
  1822. ResLogFile:=OutputFileName('log',LogSuffix);
  1823. LongLogFile:=OutputFileName('longlog',LogSuffix);
  1824. FailLogFile:=OutputFileName('faillist',LogSuffix);
  1825. ForceLog(ResLogFile);
  1826. ForceLog(LongLogFile);
  1827. ForceLog(FailLogFile);
  1828. { Per test logfiles }
  1829. CompilerLogFile:=TestLogFileName('',SplitFileName(PPFile[current]),'log');
  1830. ExeLogFile:=TestLogFileName('',SplitFileName(PPFile[current]),'elg');
  1831. Verbose(V_Debug,'Using Compiler logfile: '+CompilerLogFile);
  1832. Verbose(V_Debug,'Using Execution logfile: '+ExeLogFile);
  1833. end;
  1834. if Res then
  1835. begin
  1836. if Config.UsesGraph and (not DoGraph) then
  1837. begin
  1838. AddLog(ResLogFile,skipping_graph_test+PPFileInfo[current]);
  1839. { avoid a second attempt by writing to elg file }
  1840. AddLog(EXELogFile,skipping_graph_test+PPFileInfo[current]);
  1841. Verbose(V_Warning,skipping_graph_test);
  1842. Res:=false;
  1843. end;
  1844. end;
  1845. if Res then
  1846. begin
  1847. if Config.IsInteractive and (not DoInteractive) then
  1848. begin
  1849. { avoid a second attempt by writing to elg file }
  1850. AddLog(EXELogFile,skipping_interactive_test+PPFileInfo[current]);
  1851. AddLog(ResLogFile,skipping_interactive_test+PPFileInfo[current]);
  1852. Verbose(V_Warning,skipping_interactive_test);
  1853. Res:=false;
  1854. end;
  1855. end;
  1856. if Res then
  1857. begin
  1858. if Config.IsKnownCompileError and (not DoKnown) then
  1859. begin
  1860. { avoid a second attempt by writing to elg file }
  1861. AddLog(EXELogFile,skipping_known_bug+PPFileInfo[current]);
  1862. AddLog(ResLogFile,skipping_known_bug+PPFileInfo[current]);
  1863. Verbose(V_Warning,skipping_known_bug);
  1864. Res:=false;
  1865. end;
  1866. end;
  1867. if Res and not DoUsual then
  1868. res:=(Config.IsInteractive and DoInteractive) or
  1869. (Config.IsKnownRunError and DoKnown) or
  1870. (Config.UsesGraph and DoGraph);
  1871. if Res then
  1872. begin
  1873. if (Config.MinVersion<>'') and not DoAll then
  1874. begin
  1875. Verbose(V_Debug,'Required compiler version: '+Config.MinVersion);
  1876. Res:=GetCompilerVersion;
  1877. if CompilerVersion<Config.MinVersion then
  1878. begin
  1879. { avoid a second attempt by writing to elg file }
  1880. AddLog(EXELogFile,skipping_compiler_version_too_low+PPFileInfo[current]);
  1881. AddLog(ResLogFile,skipping_compiler_version_too_low+PPFileInfo[current]);
  1882. Verbose(V_Warning,'Compiler version too low '+CompilerVersion+' < '+Config.MinVersion);
  1883. Res:=false;
  1884. end;
  1885. end;
  1886. end;
  1887. if Res then
  1888. begin
  1889. if (Config.MaxVersion<>'') and not DoAll then
  1890. begin
  1891. Verbose(V_Debug,'Highest compiler version: '+Config.MaxVersion);
  1892. Res:=GetCompilerVersion;
  1893. if CompilerVersion>Config.MaxVersion then
  1894. begin
  1895. { avoid a second attempt by writing to elg file }
  1896. AddLog(EXELogFile,skipping_compiler_version_too_high+PPFileInfo[current]);
  1897. AddLog(ResLogFile,skipping_compiler_version_too_high+PPFileInfo[current]);
  1898. Verbose(V_Warning,'Compiler version too high '+CompilerVersion+' > '+Config.MaxVersion);
  1899. Res:=false;
  1900. end;
  1901. end;
  1902. end;
  1903. if Res then
  1904. begin
  1905. if Config.NeedCPU<>'' then
  1906. begin
  1907. Verbose(V_Debug,'Required compiler cpu: '+Config.NeedCPU);
  1908. if not IsInList(CompilerCPU,Config.NeedCPU) then
  1909. begin
  1910. { avoid a second attempt by writing to elg file }
  1911. AddLog(EXELogFile,skipping_other_cpu+PPFileInfo[current]);
  1912. AddLog(ResLogFile,skipping_other_cpu+PPFileInfo[current]);
  1913. Verbose(V_Warning,'Compiler cpu "'+CompilerCPU+'" is not in list "'+Config.NeedCPU+'"');
  1914. Res:=false;
  1915. end;
  1916. end;
  1917. end;
  1918. if Res then
  1919. begin
  1920. if Config.SkipCPU<>'' then
  1921. begin
  1922. Verbose(V_Debug,'Skip compiler cpu: '+Config.SkipCPU);
  1923. if IsInList(CompilerCPU,Config.SkipCPU) then
  1924. begin
  1925. { avoid a second attempt by writing to elg file }
  1926. AddLog(EXELogFile,skipping_other_cpu+PPFileInfo[current]);
  1927. AddLog(ResLogFile,skipping_other_cpu+PPFileInfo[current]);
  1928. Verbose(V_Warning,'Compiler cpu "'+CompilerCPU+'" is in list "'+Config.SkipCPU+'"');
  1929. Res:=false;
  1930. end;
  1931. end;
  1932. end;
  1933. if Res then
  1934. begin
  1935. if Config.SkipEmu<>'' then
  1936. begin
  1937. Verbose(V_Debug,'Skip emulator: '+emulatorname);
  1938. if IsInList(emulatorname,Config.SkipEmu) then
  1939. begin
  1940. { avoid a second attempt by writing to elg file }
  1941. AddLog(EXELogFile,skipping_other_cpu+PPFileInfo[current]);
  1942. AddLog(ResLogFile,skipping_other_cpu+PPFileInfo[current]);
  1943. Verbose(V_Warning,'Emulator "'+emulatorname+'" is in list "'+Config.SkipEmu+'"');
  1944. Res:=false;
  1945. end;
  1946. end;
  1947. end;
  1948. if Res then
  1949. begin
  1950. if Config.NeedTarget<>'' then
  1951. begin
  1952. Verbose(V_Debug,'Required compiler target: '+Config.NeedTarget);
  1953. if not IsInList(CompilerTarget,Config.NeedTarget) then
  1954. begin
  1955. { avoid a second attempt by writing to elg file }
  1956. AddLog(EXELogFile,skipping_other_target+PPFileInfo[current]);
  1957. AddLog(ResLogFile,skipping_other_target+PPFileInfo[current]);
  1958. Verbose(V_Warning,'Compiler target "'+CompilerTarget+'" is not in list "'+Config.NeedTarget+'"');
  1959. Res:=false;
  1960. end;
  1961. end;
  1962. end;
  1963. if Res then
  1964. begin
  1965. if Config.SkipTarget<>'' then
  1966. begin
  1967. Verbose(V_Debug,'Skip compiler target: '+Config.SkipTarget);
  1968. if IsInList(CompilerTarget,Config.SkipTarget) then
  1969. begin
  1970. { avoid a second attempt by writing to elg file }
  1971. AddLog(EXELogFile,skipping_other_target+PPFileInfo[current]);
  1972. AddLog(ResLogFile,skipping_other_target+PPFileInfo[current]);
  1973. Verbose(V_Warning,'Compiler target "'+CompilerTarget+'" is in list "'+Config.SkipTarget+'"');
  1974. Res:=false;
  1975. end;
  1976. end;
  1977. end;
  1978. if Res then
  1979. begin
  1980. { Use known bug, to avoid adding a new entry for this PM 2011-06-24 }
  1981. if Config.NeedLibrary and not TargetCanCompileLibraries then
  1982. begin
  1983. AddLog(EXELogFile,skipping_known_bug+PPFileInfo[current]);
  1984. AddLog(ResLogFile,skipping_known_bug+PPFileInfo[current]);
  1985. Verbose(V_Warning,'Compiler target "'+CompilerTarget+'" does not support library compilation');
  1986. Res:=false;
  1987. end;
  1988. end;
  1989. if Res then
  1990. begin
  1991. Res:=RunCompiler('');
  1992. if Res and Config.NeedRecompile then
  1993. Res:=RunCompiler(Config.RecompileOpt);
  1994. end;
  1995. if Res and (not Config.ShouldFail) then
  1996. begin
  1997. if (Config.NoRun) then
  1998. begin
  1999. { avoid a second attempt by writing to elg file }
  2000. AddLog(EXELogFile,skipping_run_test+PPFileInfo[current]);
  2001. AddLog(ResLogFile,skipping_run_test+PPFileInfo[current]);
  2002. Verbose(V_Debug,skipping_run_test);
  2003. if LibraryExists(PPFile[current],LibraryName) then
  2004. MaybeCopyFiles(LibraryName);
  2005. end
  2006. else if Config.IsKnownRunError and (not DoKnown) then
  2007. begin
  2008. { avoid a second attempt by writing to elg file }
  2009. AddLog(EXELogFile,skipping_known_bug+PPFileInfo[current]);
  2010. AddLog(ResLogFile,skipping_known_bug+PPFileInfo[current]);
  2011. Verbose(V_Warning,skipping_known_bug);
  2012. end
  2013. else
  2014. begin
  2015. if DoExecute then
  2016. begin
  2017. if FileExists(TestOutputFilename('',PPFile[current],'ppu')) or
  2018. FileExists(TestOutputFilename('',PPFile[current],'ppo')) or
  2019. FileExists(TestOutputFilename('',PPFile[current],'ppw')) then
  2020. begin
  2021. AddLog(ExeLogFile,skipping_run_unit+PPFileInfo[current]);
  2022. AddLog(ResLogFile,skipping_run_unit+PPFileInfo[current]);
  2023. Verbose(V_Debug,'Unit found, skipping run test')
  2024. end
  2025. else if LibraryExists(PPFile[current],LibraryName) then
  2026. begin
  2027. Verbose(V_Debug,'Library found, skipping run test');
  2028. MaybeCopyFiles(LibraryName);
  2029. end
  2030. else
  2031. Res:=RunExecutable;
  2032. end;
  2033. end;
  2034. end;
  2035. end;
  2036. begin
  2037. if GetEnvironmentVariable('TEST_THREADS')='1' then
  2038. ForceTestThreads:=True;
  2039. Current:=0;
  2040. PPFile:=TStringList.Create;
  2041. PPFile.Capacity:=10;
  2042. PPFileInfo:=TStringList.Create;
  2043. PPFileInfo.Capacity:=10;
  2044. GetArgs;
  2045. SetTargetDirectoriesStyle;
  2046. SetTargetCanCompileLibraries;
  2047. SetRemoteConfiguration;
  2048. {$ifdef LIMIT83fs}
  2049. UseOSOnly:=true;
  2050. {$else not LIMIT83fs}
  2051. SetUseOSOnly;
  2052. {$endif not LIMIT83fs}
  2053. Verbose(V_Debug,'Found '+ToStr(PPFile.Count)+' tests to run');
  2054. if current>0 then
  2055. for current:=0 to PPFile.Count-1 do
  2056. begin
  2057. SetPPFileInfo;
  2058. TestName:=Copy(PPFile[current],1,Pos('.pp',PPFile[current])-1);
  2059. Verbose(V_Normal,'Running test '+TestName+', file '+PPFile[current]);
  2060. RunTest;
  2061. end;
  2062. PPFile.Free;
  2063. PPFileInfo.Free;
  2064. end.