2
0

rewritemakefile.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. unit rewritemakefile;
  2. {$mode ObjFPC}{$H+}
  3. interface
  4. uses strutils, regexpr, sysutils, classes, types, prefixer;
  5. Type
  6. { TRewriteMakeFile }
  7. TMakeFileToolLogEvent = procedure(Sender : TObject; EventType : TEventType; Const Msg : String) of object;
  8. TRewriteMakeFile = Class(TComponent)
  9. private
  10. FAliasesFileName: String;
  11. FNew,
  12. FCommon,
  13. FNames,
  14. FSkip,
  15. FAliases : TStrings;
  16. FOnLog: TMakeFileToolLogEvent;
  17. FCommonUnitsFileName: String;
  18. FSkipUnitsFileName: String;
  19. procedure SetAliasesFileName(AValue: String);
  20. procedure SetCommonUnitsFileName(AValue: String);
  21. procedure SetSkipUnitsFileName(AValue: String);
  22. Protected
  23. procedure DoMsg(const aFmt: String; const aArgs: array of const;
  24. EventType: TEventType=etInfo); overload;
  25. procedure DoMsg(const aMessage: String; EventType: TEventType=etInfo); overload;
  26. procedure LoadNames(const aFileName: String; aAliases, aNames: TStrings); virtual;
  27. procedure addRecipe(aRecipe: TStrings); virtual;
  28. function GetNextLine(aLines: TStrings; var I: integer; var aLine: String): Boolean;
  29. function GetDottedUnitSrc(const aUnit,DottedUnit, aExt : String) : String; virtual;
  30. Public
  31. class function ExtractSourceExt(aLine, aUnit: string): String;
  32. class function ReplaceSourceFile(aLine, aUnit: string): String;
  33. class function CheckContinue(aLine: String): Boolean;
  34. class function CorrectSpaces(S: String; aIndent: String): string;
  35. class procedure FixTabs(sl: TStrings);
  36. class function IsRule(aLine: String): Boolean;
  37. class function ReplaceUnits(const aLine: string; aUnitNames: TStrings): String;
  38. class function ReplaceWord(aLine, aName, aFull: String): String;
  39. class function StripMacroChars(S: String): String;
  40. Public
  41. Constructor Create(aOwner : TComponent); override;
  42. Destructor Destroy; override;
  43. procedure HandleMakeFile(aFileName: string);
  44. Property AliasesFileName : String Read FAliasesFileName Write SetAliasesFileName;
  45. Property CommonUnitsFileName : String Read FCommonUnitsFileName Write SetCommonUnitsFileName;
  46. Property SkipUnitsFileName : String Read FSkipUnitsFileName Write SetSkipUnitsFileName;
  47. Property OnLog : TMakeFileToolLogEvent Read FOnLog Write FOnLog;
  48. end;
  49. Implementation
  50. class function TRewriteMakeFile.ReplaceWord(aLine, aName, aFull: String): String;
  51. var
  52. RE : TRegExpr;
  53. begin
  54. RE:=TRegExpr.Create('\b'+aName+'\b');
  55. try
  56. RE.ModifierI:=True;
  57. Result:=RE.Replace(aLine,aFull);
  58. // Writeln(aLine,': ',aName,' -> ',aFull,' = ',Result);
  59. finally
  60. RE.Free;
  61. end;
  62. end;
  63. class function TRewriteMakeFile.ReplaceUnits(const aLine: string; aUnitNames: TStrings): String;
  64. Var
  65. res,aName,aFull : String;
  66. begin
  67. Res:=aLine;
  68. for aName in aUnitNames do
  69. begin
  70. aFull:='$('+UpperCase(aName)+'UNIT)';
  71. Res:=ReplaceWord(Res,aName,aFull);
  72. end;
  73. Result:=Res;
  74. end;
  75. procedure TRewriteMakeFile.SetAliasesFileName(AValue: String);
  76. begin
  77. if FAliasesFileName=AValue then Exit;
  78. FAliasesFileName:=AValue;
  79. if aValue='' then
  80. FAliases.Clear;
  81. FNames.Clear;
  82. LoadNames(aValue,FAliases,FNames);
  83. end;
  84. procedure TRewriteMakeFile.SetCommonUnitsFileName(AValue: String);
  85. begin
  86. if FCommonUnitsFileName=AValue then Exit;
  87. FCommonUnitsFileName:=AValue;
  88. if aValue='' then
  89. FCommon.Clear
  90. else
  91. FCommon.LoadFromFile(aValue);
  92. end;
  93. procedure TRewriteMakeFile.SetSkipUnitsFileName(AValue: String);
  94. begin
  95. if FSkipUnitsFileName=AValue then Exit;
  96. FSkipUnitsFileName:=AValue;
  97. if aValue='' then
  98. FSkip.Clear
  99. else
  100. FSkip.LoadFromFile(aValue);
  101. end;
  102. procedure TRewriteMakeFile.DoMsg(const aFmt: String;
  103. const aArgs: array of const; EventType: TEventType);
  104. begin
  105. DoMsg(Format(aFmt,aArgs),EventType);
  106. end;
  107. procedure TRewriteMakeFile.DoMsg(const aMessage: String; EventType: TEventType);
  108. begin
  109. if assigned(OnLog) then
  110. OnLog(Self,EventType, aMessage);
  111. end;
  112. procedure TRewriteMakeFile.LoadNames(const aFileName: String; aAliases,
  113. aNames: TStrings);
  114. var
  115. I : integer;
  116. N,V : String;
  117. begin
  118. aAliases.LoadFromFile(aFileName);
  119. for I:=0 to aAliases.Count-1 do
  120. begin
  121. aAliases.GetNameValue(I,N,V);
  122. if SameText(N,'unixcp') then
  123. Writeln('Aloha');
  124. aAliases[I]:=N+'='+TPrefixer.ApplyAliasRule(N,V);
  125. aNames.Add(N);
  126. end;
  127. end;
  128. class function TRewriteMakeFile.CheckContinue(aLine: String): Boolean;
  129. Var
  130. L : Integer;
  131. begin
  132. L:=Length(aLine);
  133. Result:=(L>0) and (aLine[L]='\');
  134. end;
  135. class function TRewriteMakeFile.IsRule(aLine: String): Boolean;
  136. begin
  137. Result:=(aLine='') or (aLine[1]=#9)
  138. end;
  139. function TRewriteMakeFile.GetNextLine(aLines: TStrings; var I: integer;
  140. var aLine: String): Boolean;
  141. begin
  142. Result:=I<aLines.Count-1;
  143. if Result then
  144. begin
  145. Inc(I);
  146. aLine:=aLines[i];
  147. end;
  148. end;
  149. function TRewriteMakeFile.GetDottedUnitSrc(const aUnit, DottedUnit, aExt: String
  150. ): String;
  151. begin
  152. if FCommon.IndexOf(aUnit)=-1 then
  153. Result:='$(NSOSDIR)/'
  154. else
  155. Result:='$(NSINC)/';
  156. Result:=Result+DottedUnit+aExt
  157. end;
  158. class function TRewriteMakeFile.ReplaceSourceFile(aLine, aUnit: string): String;
  159. Procedure AddToResult(S: String);
  160. begin
  161. if Result<>'' then
  162. Result:=Result+' ';
  163. Result:=Result+S;
  164. end;
  165. Function ReplacePath(S : String) : String;
  166. begin
  167. if pos(aUnit+'.pp',S)>0 then
  168. Result:='$<'
  169. else if pos(aUnit+'.pas',S)>0 then
  170. Result:='$<'
  171. else
  172. Result:=S;
  173. end;
  174. Var
  175. a : Array of string;
  176. S : String;
  177. begin
  178. Result:='';
  179. A:=SplitString(aLine,' ');
  180. For S in a do
  181. begin
  182. if Pos(aUnit,S)=0 then
  183. AddToResult(S)
  184. else
  185. AddToResult(ReplacePath(S));
  186. end;
  187. end;
  188. class function TRewriteMakeFile.StripMacroChars(S: String): String;
  189. begin
  190. if Pos('$(',S)=0 then
  191. Result:=S
  192. else
  193. begin
  194. Result:=StringReplace(S,'$(','',[]);
  195. Result:=StringReplace(Result,')','',[]);
  196. end;
  197. end;
  198. constructor TRewriteMakeFile.Create(aOwner: TComponent);
  199. begin
  200. inherited Create(aOwner);
  201. FAliases:=TStringList.Create;
  202. FNames:=TStringList.Create;
  203. FCommon:=TStringList.Create;
  204. FNew:=TStringList.Create;
  205. FSkip:=TStringList.Create;
  206. end;
  207. destructor TRewriteMakeFile.Destroy;
  208. begin
  209. FreeAndNil(FSkip);
  210. FreeAndNil(FNew);
  211. FreeAndNil(FAliases);
  212. FreeAndNil(FNames);
  213. FreeAndNil(FCommon);
  214. inherited Destroy;
  215. end;
  216. class function TRewriteMakeFile.CorrectSpaces(S: String; aIndent: String
  217. ): string;
  218. var
  219. len,aCount : Integer;
  220. begin
  221. aCount:=0;
  222. len:=Length(aIndent);
  223. While (aCount<Length(S)) and (S[aCount+1]=' ') do
  224. inc(aCount);
  225. Result:=S;
  226. if aCount<Len then
  227. Result:=Copy(aIndent,1,Len-aCount)+Result
  228. else if aCount>Len then
  229. Delete(Result,1,aCount-Len);
  230. end;
  231. class function TRewriteMakeFile.ExtractSourceExt(aLine, aUnit: string): String;
  232. Var
  233. a : Array of string;
  234. S : String;
  235. begin
  236. Result:='';
  237. A:=SplitString(aLine,' ');
  238. For S in a do
  239. begin
  240. if Pos(aUnit,S)<>0 then
  241. begin
  242. Result:=ExtractFileExt(S);
  243. exit;
  244. end;
  245. end;
  246. end;
  247. procedure TRewriteMakeFile.addRecipe(aRecipe: TStrings);
  248. var
  249. aTarget, aCompileLine, aExt, aUnit, aDottedUnit, aCasedUnit, aLine,aDeps,aUpper,aIndent,UnitDeps : String;
  250. P,NameIdx,Idx,I,iRules : Integer;
  251. begin
  252. aLine:=aRecipe[0];
  253. P:=Pos('$(PPUEXT)',aLine);
  254. aUnit:=Trim(Copy(aLine,1,P-1));
  255. if FSkip.IndexOf(aUnit)<>-1 then
  256. begin
  257. DoMsg('Skipping unit "%s"',[aUnit],etWarning);
  258. Exit;
  259. end;
  260. NameIdx:=FNames.IndexOf(aUnit);
  261. if NameIdx<>-1 then
  262. FNames.Delete(NameIdx);
  263. P:=Pos(':',aLine);
  264. aTarget:=Copy(aLine,1,P);
  265. aDeps:=Copy(aLine,P+1);
  266. aUpper:=UpperCase(aUnit);
  267. UnitDeps:=StripMacroChars(aUpper)+'_DEPS';
  268. FNew.Add('');
  269. aExt:=ExtractSourceExt(aDeps,aUnit);
  270. aDeps:=UNITDEPS+'='+Trim(ReplaceUnits(aDeps,FNames));
  271. if aDeps[Length(aDeps)]<>'\' then
  272. aDeps:=aDeps+'\';
  273. FNew.Add(aDeps);
  274. aIndent:=StringOfChar(' ',Length(UnitDeps)+1);
  275. i:=0;
  276. While CheckContinue(aLine) and GetNextLine(aRecipe,I,aLine) do
  277. begin
  278. if aExt='' then
  279. aExt:=ExtractSourceExt(aDeps,aUnit);
  280. aDeps:=CorrectSpaces(ReplaceUnits(aLine,FNames),aIndent);
  281. if aDeps[Length(aDeps)]<>'\' then
  282. aDeps:=aDeps+'\';
  283. FNew.Add(aDeps);
  284. end;
  285. FNew.Add(aIndent+'$('+UnitDeps+'_OS) '+'$('+UnitDeps+'_CPU)');
  286. FNew.Add('');
  287. FNew.Add(aTarget+' $('+UnitDeps+')');
  288. iRules:=I;
  289. While GetNextLine(aRecipe,I,aLine) and IsRule(aLine) do
  290. begin
  291. aCompileLine:=ReplaceSourceFile(aLine,aUnit);
  292. FNew.Add(ReplaceUnits(aCompileLine,FNames));
  293. end;
  294. Idx:=FAliases.IndexOfName(aUnit);
  295. if Idx<>-1 then
  296. begin
  297. FAliases.GetNameValue(Idx,aCasedUnit,aDottedunit);
  298. aTarget:=StringReplace(aTarget,aUnit,aDottedUnit,[]);
  299. FNew.Add('');
  300. FNew.Add(aTarget+' '+GetDottedUnitSrc(aUnit,aDottedUnit,aExt)+' $('+UnitDeps+')');
  301. I:=iRules;
  302. While GetNextLine(aRecipe,I,aLine) and IsRule(aLine) do
  303. begin
  304. aCompileLine:=ReplaceSourceFile(aLine,aUnit);
  305. FNew.Add(ReplaceUnits(aCompileLine,FNames));
  306. end;
  307. end;
  308. if NameIdx<>-1 then
  309. FNames.Insert(NameIdx,aUnit);
  310. end;
  311. class procedure TRewriteMakeFile.FixTabs(sl:TStrings);
  312. var
  313. i,j,k : integer;
  314. s,s2 : string;
  315. isContinue : Boolean;
  316. begin
  317. isContinue:=False;
  318. i:=0;
  319. while (i<sl.Count) do
  320. begin
  321. s:=sl[i];
  322. if Not IsContinue then
  323. begin
  324. if (s<>'') and (s[1] in [' ',#9]) then
  325. begin
  326. k:=0;
  327. j:=0;
  328. repeat
  329. inc(j);
  330. case s[j] of
  331. ' ' :
  332. inc(k);
  333. #9 :
  334. k:=(k+7) and not(7);
  335. else
  336. break;
  337. end;
  338. until (j=length(s));
  339. if k>7 then
  340. begin
  341. s2:='';
  342. Delete(s,1,j-1);
  343. while (k>7) do
  344. begin
  345. s2:=s2+#9;
  346. dec(k,8);
  347. end;
  348. while (k>0) do
  349. begin
  350. s2:=s2+' ';
  351. dec(k);
  352. end;
  353. sl[i]:=s2+s;
  354. end;
  355. end;
  356. end;
  357. IsContinue:=(S<>'') and (S[Length(S)]='\');
  358. inc(i);
  359. end;
  360. end;
  361. procedure TRewriteMakeFile.HandleMakeFile(aFileName: string);
  362. Var
  363. aMakeFile : TStrings;
  364. Function DoGetNextLine(var I : integer; var aLine : String) : Boolean;
  365. begin
  366. Result:=GetNextLine(aMakeFile,I,aLine);
  367. end;
  368. var
  369. i,P : Integer;
  370. aRecipe : TStrings;
  371. aSection,aLine : String;
  372. begin
  373. aLine:='';
  374. aRecipe:=Nil;
  375. aMakeFile:=TStringList.Create;
  376. try
  377. aRecipe:=TstringList.Create;
  378. aMakeFile.LoadFromFile(aFileName);
  379. FixTabs(aMakeFile);
  380. I:=-1;
  381. While DoGetNextLine(I,aLine) do
  382. begin
  383. aLine:=aMakefile[I];
  384. if Copy(aLine,1,1)='[' then
  385. aSection:=LowerCase(Copy(aLine,2,Length(aLine)-2));
  386. Case asection of
  387. 'rules',
  388. 'prerules' :
  389. begin
  390. P:=Pos('$(PPUEXT)',aLine);
  391. if (P>0) and (Pos(':',aLine)>P) then
  392. begin
  393. aRecipe.Clear;
  394. aRecipe.Add(aLine);
  395. // Add continuation lines
  396. While CheckContinue(aLine) and DoGetNextLine(I,aLine) do
  397. aRecipe.Add(aLine);
  398. // Add compiler rules
  399. While DoGetNextLine(I,aLine) and (IsRule(aLine)) do
  400. aRecipe.add(aLine);
  401. addRecipe(aRecipe);
  402. Dec(I); // Go back to previous line.
  403. end
  404. else
  405. FNew.Add(aLine);
  406. end;
  407. 'shared',
  408. 'target':
  409. begin
  410. P:=Pos('=',aLine);
  411. if (P>0) and (IndexText(Trim(Copy(aLine,1,P-1)),['units','implicitunits','libunits'])<>-1) then
  412. begin
  413. FNew.Add(ReplaceUnits(aLine,FNames));
  414. While CheckContinue(aLine) and DoGetNextLine(I,aLine) do
  415. FNew.Add(ReplaceUnits(aLine,FNames));
  416. end
  417. else
  418. FNew.Add(aLine);
  419. end;
  420. else
  421. FNew.Add(aLine);
  422. end;
  423. end;
  424. // ReplaceUnits(aMakefile[I],aNames);
  425. FNew.SaveToFile(aFileName+'.new');
  426. finally
  427. aMakeFile.Free;
  428. aRecipe.Free;
  429. end;
  430. end;
  431. end.