gparmake.pp 5.5 KB

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