gparmake.pp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. { See procedure "Usage". This code is in the public domain. }
  2. Program GParMake;
  3. Uses
  4. SysUtils, Classes;
  5. procedure Usage;
  6. begin
  7. writeln('GParMake: create make rules for parallel execution of testsuite');
  8. writeln('Usage: gparmake [-a] [-f] <outputfile> <dirname> <startchunk> <tests_per_chunk> <test1> [<test2> ...]');
  9. writeln('Output: makefile fragment with rules to run the tests in sequences of <tests_per_chunk>');
  10. writeln(' -a: Append to existing files');
  11. writeln(' -f: redirect output to separate files');
  12. writeln;
  13. halt(1);
  14. end;
  15. var
  16. doappend: boolean;
  17. doredirect: boolean;
  18. { make all numbers of the same string length so they can be sorted
  19. lexographically }
  20. function rulenr2str(rulenr: longint): string;
  21. var
  22. i: longint;
  23. begin
  24. str(rulenr:9,rulenr2str);
  25. for i:=1 to length(rulenr2str)-1 do
  26. if rulenr2str[i]=' ' then
  27. rulenr2str[i]:='0';
  28. end;
  29. procedure WriteChunkRule(rulenr: longint; const dirname, files: ansistring);
  30. var
  31. rulestr, redirectfile: string;
  32. begin
  33. rulestr:=rulenr2str(rulenr)+dirname;
  34. writeln('$(TEST_OUTPUTDIR)/testchunk_',rulestr,'-stamp.$(TEST_FULL_TARGET): testprep-stamp.$(TEST_FULL_TARGET)');
  35. writeln(#9'$(Q)$(ECHOREDIR) "Starting testchunk_'+rulestr+'"');
  36. write(#9'$(Q)$(DOTEST) $(DOTESTOPT) -Lchunk',rulestr,' -e ',files);
  37. if doredirect then
  38. begin
  39. redirectfile:='$(TEST_OUTPUTDIR)/seplog.chunk'+rulestr;
  40. writeln(' > '+redirectfile);
  41. end
  42. else
  43. writeln;
  44. writeln(#9'$(ECHOREDIR) $(TEST_DATETIME) > $@');
  45. writeln;
  46. writeln('$(addsuffix .chunk',rulestr,', $(LOGFILES)) : $(TEST_OUTPUTDIR)/testchunk_',rulestr,'-stamp.$(TEST_FULL_TARGET)');
  47. writeln;
  48. writeln('.INTERMEDIATE: $(addsuffix .chunk',rulestr,', $(LOGFILES)) $(TEST_OUTPUTDIR)/testchunk_',rulestr,'-stamp.$(TEST_FULL_TARGET)');
  49. writeln;
  50. end;
  51. var
  52. startchunk: longint;
  53. dirname : ansistring;
  54. FileList : TStringList;
  55. Function ProcessArgs: longint;
  56. var
  57. i,
  58. paramnr,
  59. chunktargetsize,
  60. chunksize,
  61. chunknr,
  62. nextfileindex,
  63. error: longint;
  64. testname,
  65. nexttestname,
  66. testlist,
  67. s,
  68. outputname: ansistring;
  69. filelist : array of ansistring;
  70. responsefile : text;
  71. procedure AddFile(const s : ansistring);
  72. begin
  73. if nextfileindex>high(filelist) then
  74. SetLength(filelist,length(filelist)+128);
  75. filelist[nextfileindex]:=s;
  76. inc(nextfileindex);
  77. end;
  78. procedure FlushChunk;
  79. begin
  80. WriteChunkRule(chunknr,dirname,testlist);
  81. inc(chunknr);
  82. testlist:='';
  83. chunksize:=0;
  84. end;
  85. begin
  86. if paramcount < 3 then
  87. Usage;
  88. doappend:=false;
  89. doredirect:=false;
  90. paramnr:=1;
  91. if paramstr(paramnr)='-a' then
  92. begin
  93. doappend:=true;
  94. inc(paramnr);
  95. end;
  96. if paramstr(paramnr)='-f' then
  97. begin
  98. doredirect:=true;
  99. inc(paramnr);
  100. end;
  101. outputname:=paramstr(paramnr);
  102. inc(paramnr);
  103. dirname:=paramstr(paramnr);
  104. inc(paramnr);
  105. val(paramstr(paramnr),startchunk,error);
  106. if error<>0 then
  107. Usage;
  108. inc(paramnr);
  109. val(paramstr(paramnr),chunktargetsize,error);
  110. if error<>0 then
  111. Usage;
  112. inc(paramnr);
  113. { only redirect output after all possible cases where we may have to write
  114. the usage screen }
  115. assign(output,outputname);
  116. if doappend then
  117. append(output)
  118. else
  119. rewrite(output);
  120. chunknr:=startchunk;
  121. chunksize:=0;
  122. testlist:='';
  123. nextfileindex:=0;
  124. for i := paramnr to paramcount do
  125. begin
  126. if paramstr(i)[1]='@' then
  127. begin
  128. assign(responsefile,copy(paramstr(i),2,length(paramstr(i))));
  129. reset(responsefile);
  130. while not(eof(responsefile)) do
  131. begin
  132. readln(responsefile,s);
  133. AddFile(s);
  134. end;
  135. close(responsefile);
  136. end
  137. else
  138. AddFile(paramstr(i));
  139. end;
  140. for i := 0 to nextfileindex-1 do
  141. begin
  142. testname:=filelist[i];
  143. testlist:=testlist+' '+testname;
  144. inc(chunksize);
  145. if chunksize>=chunktargetsize then
  146. begin
  147. if (i=nextfileindex-1) then
  148. FlushChunk
  149. else
  150. begin
  151. { keep tests with the same name except for the last character in the same chunk,
  152. because they may have to be executed in order (skip ".pp" suffix and last char) }
  153. if i+1>=nextfileindex then
  154. nexttestname:=''
  155. else
  156. nexttestname:=filelist[i+1];
  157. if not SameText(copy(testname,1,length(testname)-4),copy(nexttestname,1,length(nexttestname)-4)) then
  158. FlushChunk;
  159. end;
  160. end;
  161. end;
  162. if chunksize<>0 then
  163. FlushChunk;
  164. ProcessArgs:=chunknr-1;
  165. end;
  166. procedure WriteWrapperRules(totalchunks: longint);
  167. const
  168. lognames: array[1..4] of string[11] = ('log','faillist','longlog','seplog');
  169. var
  170. logi,
  171. i: longint;
  172. begin
  173. for logi:=low(lognames) to high(lognames) do
  174. begin
  175. if (logi=4) and not doredirect then
  176. continue;
  177. write('$(TEST_OUTPUTDIR)/',lognames[logi],' :');
  178. for i:=startchunk to totalchunks do
  179. write(' $(TEST_OUTPUTDIR)/',lognames[logi],'.chunk',rulenr2str(i)+dirname);
  180. writeln;
  181. { if you have multiple rules for one (non-pattern) target, all
  182. prerequisites will be merged, but only one of the rules can have a
  183. recipe }
  184. if not doappend then
  185. begin
  186. writeln(#9'$(Q)$(CONCAT) $(sort $^) $@');
  187. writeln;
  188. end;
  189. writeln;
  190. end;
  191. if not doappend then
  192. begin
  193. writeln('gparmake_allexectests : $(LOGFILES)');
  194. writeln;
  195. end;
  196. end;
  197. var
  198. totalchunks: longint;
  199. begin
  200. totalchunks:=ProcessArgs;
  201. WriteWrapperRules(totalchunks);
  202. close(output);
  203. end.