gparmake.pp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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. if not (copy(s,1,5)='make[') then
  119. AddFile(s);
  120. end;
  121. close(responsefile);
  122. end
  123. else
  124. AddFile(paramstr(i));
  125. end;
  126. for i := 0 to nextfileindex-1 do
  127. begin
  128. testname:=filelist[i];
  129. testlist:=testlist+' '+testname;
  130. inc(chunksize);
  131. if chunksize>=chunktargetsize then
  132. begin
  133. if (i=nextfileindex-1) then
  134. FlushChunk
  135. else
  136. begin
  137. { keep tests with the same name except for the last character in the same chunk,
  138. because they may have to be executed in order (skip ".pp" suffix and last char) }
  139. if i+1>=nextfileindex then
  140. nexttestname:=''
  141. else
  142. nexttestname:=filelist[i+1];
  143. if lowercase(copy(testname,1,length(testname)-4))<>lowercase(copy(nexttestname,1,length(nexttestname)-4)) then
  144. FlushChunk;
  145. end;
  146. end;
  147. end;
  148. if chunksize<>0 then
  149. FlushChunk;
  150. ProcessArgs:=chunknr-1;
  151. end;
  152. procedure WriteWrapperRules(totalchunks: longint);
  153. const
  154. lognames: array[1..3] of string[11] = ('log','faillist','longlog');
  155. var
  156. logi,
  157. i: longint;
  158. begin
  159. for logi:=1 to 3 do
  160. begin
  161. write('$(TEST_OUTPUTDIR)/',lognames[logi],' :');
  162. for i:=startchunk to totalchunks do
  163. write(' $(TEST_OUTPUTDIR)/',lognames[logi],'.chunk',rulenr2str(i)+dirname);
  164. writeln;
  165. { if you have multiple rules for one (non-pattern) target, all
  166. prerequisites will be merged, but only one of the rules can have a
  167. recipe }
  168. if not doappend then
  169. begin
  170. writeln(#9'$(Q)$(CONCAT) $(sort $^) $@');
  171. writeln;
  172. end;
  173. writeln;
  174. end;
  175. if not doappend then
  176. begin
  177. writeln('gparmake_allexectests : $(LOGFILES)');
  178. writeln;
  179. end;
  180. end;
  181. var
  182. totalchunks: longint;
  183. begin
  184. totalchunks:=ProcessArgs;
  185. WriteWrapperRules(totalchunks);
  186. close(output);
  187. end.