gparmake.pp 5.3 KB

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