123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- { See procedure "Usage". This code is in the public domain. }
- Program GParMake;
- Uses
- SysUtils, Classes;
- procedure Usage;
- begin
- writeln('GParMake: create make rules for parallel execution of testsuite');
- writeln('Usage: gparmake [-a] [-f] <outputfile> <dirname> <startchunk> <tests_per_chunk> <test1> [<test2> ...]');
- writeln('Output: makefile fragment with rules to run the tests in sequences of <tests_per_chunk>');
- writeln(' -a: Append to existing files');
- writeln(' -f: redirect output to separate files');
- writeln;
- halt(1);
- end;
- var
- doappend: boolean;
- doredirect: boolean;
- { make all numbers of the same string length so they can be sorted
- lexographically }
- function rulenr2str(rulenr: longint): string;
- var
- i: longint;
- begin
- str(rulenr:9,rulenr2str);
- for i:=1 to length(rulenr2str)-1 do
- if rulenr2str[i]=' ' then
- rulenr2str[i]:='0';
- end;
- procedure WriteChunkRule(rulenr: longint; const dirname, files: ansistring);
- var
- rulestr, redirectfile: string;
- begin
- rulestr:=rulenr2str(rulenr)+dirname;
- writeln('$(TEST_OUTPUTDIR)/testchunk_',rulestr,'-stamp.$(TEST_FULL_TARGET): testprep-stamp.$(TEST_FULL_TARGET)');
- writeln(#9'$(Q)$(ECHOREDIR) "Starting testchunk_'+rulestr+'"');
- write(#9'$(Q)$(DOTEST) $(DOTESTOPT) -Lchunk',rulestr,' -e ',files);
- if doredirect then
- begin
- redirectfile:='$(TEST_OUTPUTDIR)/seplog.chunk'+rulestr;
- writeln(' > '+redirectfile);
- end
- else
- writeln;
- writeln(#9'$(ECHOREDIR) $(TEST_DATETIME) > $@');
- writeln;
- writeln('$(addsuffix .chunk',rulestr,', $(LOGFILES)) : $(TEST_OUTPUTDIR)/testchunk_',rulestr,'-stamp.$(TEST_FULL_TARGET)');
- writeln;
- writeln('.INTERMEDIATE: $(addsuffix .chunk',rulestr,', $(LOGFILES)) $(TEST_OUTPUTDIR)/testchunk_',rulestr,'-stamp.$(TEST_FULL_TARGET)');
- writeln;
- end;
- var
- startchunk: longint;
- dirname : ansistring;
- FileList : TStringList;
- Function ProcessArgs: longint;
- var
- i,
- paramnr,
- chunktargetsize,
- chunksize,
- chunknr,
- nextfileindex,
- error: longint;
- testname,
- nexttestname,
- testlist,
- s,
- outputname: ansistring;
- filelist : array of ansistring;
- responsefile : text;
- procedure AddFile(const s : ansistring);
- begin
- if nextfileindex>high(filelist) then
- SetLength(filelist,length(filelist)+128);
- filelist[nextfileindex]:=s;
- inc(nextfileindex);
- end;
- procedure FlushChunk;
- begin
- WriteChunkRule(chunknr,dirname,testlist);
- inc(chunknr);
- testlist:='';
- chunksize:=0;
- end;
- begin
- if paramcount < 3 then
- Usage;
- doappend:=false;
- doredirect:=false;
- paramnr:=1;
- if paramstr(paramnr)='-a' then
- begin
- doappend:=true;
- inc(paramnr);
- end;
- if paramstr(paramnr)='-f' then
- begin
- doredirect:=true;
- inc(paramnr);
- end;
- outputname:=paramstr(paramnr);
- inc(paramnr);
- dirname:=paramstr(paramnr);
- inc(paramnr);
- val(paramstr(paramnr),startchunk,error);
- if error<>0 then
- Usage;
- inc(paramnr);
- val(paramstr(paramnr),chunktargetsize,error);
- if error<>0 then
- Usage;
- inc(paramnr);
- { only redirect output after all possible cases where we may have to write
- the usage screen }
- assign(output,outputname);
- if doappend then
- append(output)
- else
- rewrite(output);
- chunknr:=startchunk;
- chunksize:=0;
- testlist:='';
- nextfileindex:=0;
- for i := paramnr to paramcount do
- begin
- if paramstr(i)[1]='@' then
- begin
- assign(responsefile,copy(paramstr(i),2,length(paramstr(i))));
- reset(responsefile);
- while not(eof(responsefile)) do
- begin
- readln(responsefile,s);
- AddFile(s);
- end;
- close(responsefile);
- end
- else
- AddFile(paramstr(i));
- end;
- for i := 0 to nextfileindex-1 do
- begin
- testname:=filelist[i];
- testlist:=testlist+' '+testname;
- inc(chunksize);
- if chunksize>=chunktargetsize then
- begin
- if (i=nextfileindex-1) then
- FlushChunk
- else
- begin
- { keep tests with the same name except for the last character in the same chunk,
- because they may have to be executed in order (skip ".pp" suffix and last char) }
- if i+1>=nextfileindex then
- nexttestname:=''
- else
- nexttestname:=filelist[i+1];
- if not SameText(copy(testname,1,length(testname)-4),copy(nexttestname,1,length(nexttestname)-4)) then
- FlushChunk;
- end;
- end;
- end;
- if chunksize<>0 then
- FlushChunk;
- ProcessArgs:=chunknr-1;
- end;
- procedure WriteWrapperRules(totalchunks: longint);
- const
- lognames: array[1..4] of string[11] = ('log','faillist','longlog','seplog');
- var
- logi,
- i: longint;
- begin
- for logi:=low(lognames) to high(lognames) do
- begin
- if (logi=4) and not doredirect then
- continue;
- write('$(TEST_OUTPUTDIR)/',lognames[logi],' :');
- for i:=startchunk to totalchunks do
- write(' $(TEST_OUTPUTDIR)/',lognames[logi],'.chunk',rulenr2str(i)+dirname);
- writeln;
- { if you have multiple rules for one (non-pattern) target, all
- prerequisites will be merged, but only one of the rules can have a
- recipe }
- if not doappend then
- begin
- writeln(#9'$(Q)$(CONCAT) $(sort $^) $@');
- writeln;
- end;
- writeln;
- end;
- if not doappend then
- begin
- writeln('gparmake_allexectests : $(LOGFILES)');
- writeln;
- end;
- end;
- var
- totalchunks: longint;
- begin
- totalchunks:=ProcessArgs;
- WriteWrapperRules(totalchunks);
- close(output);
- end.
|