dotest.pp 63 KB

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