pkgmkconv.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. unit pkgmkconv;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils,pkghandler;
  6. { TMakeFileConverter }
  7. Type
  8. TSectionType = (stNone,stPackage,stTarget,stclean,stinstall,stCompiler,
  9. stDefault,stRequire,stRules,stPrerules);
  10. TMakeFileConverter = Class(TPackagehandler)
  11. Private
  12. FSection : TSectionType;
  13. FPackageName,
  14. FpackageDir,
  15. FPackageOptions,
  16. FPackageDeps,
  17. FBuilDUnit,
  18. FSubName,
  19. FPackageVersion : String;
  20. // Reading;
  21. procedure DoPackageLine(Const S : String);
  22. Procedure DoTargetLine(Line : String; Var T,R,D : TStrings);
  23. Procedure DoInstallLine(Line : String; Var IFL : TStrings);
  24. procedure DoCleanLine(Line : String; Var CFL : TStrings);
  25. procedure DoRequireLine(Line : String);
  26. procedure DoCompilerLine(Line : String;Var SD : TStrings);
  27. // Writing;
  28. procedure WriteOSCPUCheck(Src: TStrings;OS,CPU : String);
  29. procedure StartPackage(Src : TStrings; Dir,OS : String);
  30. procedure EndPackage(Src : TStrings; Dir,OS : String);
  31. procedure DoTargets(Src,T,R,SD : TStrings; Dir,Prefix : String);
  32. procedure DoCleans(Src,CFL : TStrings);
  33. procedure DoInstalls(Src,IFL : TStrings);
  34. Procedure StartInstaller(Src : TStrings);
  35. Procedure EndInstaller(Src : TStrings);
  36. Function GetLine (L : TStrings; Var I : Integer) : String;
  37. procedure ConvertFile(const AFileName: String; Src: TStrings; Dir,OS : String);
  38. Procedure ConvertFile(Const Source,Dest: String);
  39. Public
  40. Function Execute(const Args:TActionArgs):boolean;override;
  41. end;
  42. implementation
  43. uses
  44. TypInfo,
  45. pkgglobals,
  46. pkgmessages;
  47. Function GetWord(var S : String; Sep : Char) : String;
  48. Var
  49. L : Integer;
  50. begin
  51. L:=Pos(Sep,S);
  52. If (L=0) then
  53. L:=Length(S)+1;
  54. Result:=Copy(S,1,L-1);
  55. Delete(S,1,L);
  56. S:=Trim(S);
  57. end;
  58. Function GetWord(var S : String) : String;
  59. begin
  60. Result:=GetWord(S,' ');
  61. end;
  62. Function IsCPU (S: String) : Boolean;
  63. begin
  64. Result:=Pos(lowercase(S)+',','i386,powerpc,arm,alpha,sparc,x86_64,powerpc64,')<>0
  65. end;
  66. Procedure GetOSCPU(L : String; var OS,CPU : String);
  67. Procedure Add(Var A : String; ad : String);
  68. begin
  69. If (A<>'') then
  70. A:=A+',';
  71. A:=A+ad;
  72. end;
  73. Var
  74. S : String;
  75. begin
  76. OS:='';
  77. CPU:='';
  78. S:=GetWord(L,',');
  79. While (S<>'') do
  80. begin
  81. If (S<>'all') then
  82. If IsCPU(S) then
  83. Add(CPU,S)
  84. else
  85. Add(OS,S);
  86. S:=GetWord(L,',');
  87. end;
  88. end;
  89. { TMakeFileConverter }
  90. procedure TMakeFileConverter.StartInstaller(Src: TStrings);
  91. begin
  92. With Src do
  93. begin
  94. Add('{$mode objfpc}{$H+}');
  95. Add('program fpmake;');
  96. Add('');
  97. Add(' { Generated automatically by '+ExtractFileName(Paramstr(0))+' on '+DateToStr(Sysutils.Date)+' }');
  98. Add('');
  99. Add('uses fpmkunit;');
  100. Add('');
  101. Add('Var');
  102. Add(' P : TPackage;');
  103. Add(' T : TTarget;');
  104. Add('');
  105. Add('begin');
  106. Add(' With Installer do ');
  107. Add(' begin');
  108. end;
  109. end;
  110. procedure TMakeFileConverter.EndInstaller(Src: TStrings);
  111. begin
  112. With Src do
  113. begin
  114. Add(' Run;');
  115. Add(' end;');
  116. Add('end.');
  117. Add('');
  118. end;
  119. end;
  120. Function TMakeFileConverter.GetLine (L : TStrings; Var I : Integer) : String;
  121. Var
  122. P : Integer;
  123. OK : Boolean;
  124. begin
  125. OK:=False;
  126. Result:='';
  127. Repeat
  128. Result:=Result+L[i];
  129. P:=Pos('#',Result);
  130. If (P>0) then
  131. Result:=Copy(Result,1,P-1);
  132. Result:=Trim(Result);
  133. P:=Length(Result);
  134. If (P>0) and (Result[P]='\') then
  135. Result:=Copy(Result,1,P-1)
  136. else
  137. OK:=(Result<>'');
  138. if Not OK then
  139. Inc(I);
  140. Until OK or (I>L.Count-1);
  141. end;
  142. Function SplitNamevalue(Const S : String; Var AName,AValue : String) : boolean;
  143. var
  144. L : Integer;
  145. begin
  146. L:=Pos('=',S);
  147. Result:=(L<>0);
  148. If Result then
  149. begin
  150. AName:=LowerCase(trim(Copy(S,1,L-1)));
  151. AValue:=S;
  152. Delete(AValue,1,L);
  153. AValue:=Trim(Avalue);
  154. end
  155. else
  156. begin
  157. AName:='';
  158. AValue:='';
  159. end;
  160. end;
  161. procedure TMakeFileConverter.StartPackage(Src : TStrings; Dir,OS : String);
  162. Var
  163. S : String;
  164. begin
  165. With Src do
  166. begin
  167. Add(' { ');
  168. Add(' '+FPackageName);
  169. Add(' } ');
  170. Add(' P:=AddPackage('''+FPackageName+''');');
  171. If (Dir<>'') then
  172. Add(' P.Directory:='''+ExcludeTrailingPathDelimiter(Dir)+''';');
  173. If (OS<>'') and (OS<>'all') then
  174. Add(' P.OS:=['+OS+'];');
  175. If (FPackageVersion<>'') then
  176. Add(' P.Version:='''+FPackageVersion+''';');
  177. If (FPackageOptions<>'') then
  178. Add(' P.Options:='''+FPackageOptions+''';');
  179. If (FPackageDeps<>'') then
  180. begin
  181. S:=GetWord(FPackageDeps);
  182. While S<>'' do
  183. begin
  184. Add(' P.Dependencies.Add('''+S+''');');
  185. S:=GetWord(FPackageDeps);
  186. end;
  187. end;
  188. end;
  189. end;
  190. procedure TMakeFileConverter.EndPackage(Src : TStrings; Dir,OS : String);
  191. begin
  192. FPackageName:='';
  193. FPackageVersion:='';
  194. FPackageOptions:='';
  195. FBuilDUnit:='';
  196. FPackageDeps:='';
  197. end;
  198. procedure TMakeFileConverter.DoPackageLine(Const S : String);
  199. Var V,N : String;
  200. begin
  201. SplitNameValue(S,N,V);
  202. If (N='name') then
  203. FPackageName:=V
  204. else If (N='version') then
  205. FPackageVersion:=V
  206. else If (N='main') then
  207. begin
  208. FPackageName:='sub';
  209. FSubName:=V;
  210. end
  211. else
  212. Writeln(StdErr,'Unknown name/value pair in package section :',N);
  213. end;
  214. {
  215. Convert various entries of type
  216. XXYY_OSN=words
  217. to entries of type
  218. prefix_word=OS1,OS2,OS3
  219. OS is never empty, 'all' is default.
  220. }
  221. Procedure AddStrings(Var L : TStrings; Values,Prefix,OS : String) ;
  222. Var
  223. S,O : String;
  224. i : integer;
  225. begin
  226. If (L=Nil) then
  227. L:=TstringList.Create;
  228. If prefix<>'' then
  229. prefix:=prefix+'_';
  230. S:=GetWord(Values);
  231. While (S<>'') do
  232. begin
  233. S:=Prefix+S;
  234. I:=L.IndexOfName(S);
  235. If (I<>-1) then
  236. begin
  237. O:=L.Values[S];
  238. If (O='all') then
  239. O:='';
  240. If (O<>'') then
  241. O:=O+',';
  242. O:=O+OS;
  243. L.Values[S]:=O;
  244. end
  245. else
  246. L.Add(S+'='+OS);
  247. S:=GetWord(Values);
  248. end;
  249. end;
  250. procedure TMakeFileConverter.DoTargetLine(Line : String; Var T,R,D : TStrings);
  251. Var
  252. V,N,OS : String;
  253. P : Integer;
  254. begin
  255. SplitNameValue(Line,N,V);
  256. P:=Pos('_',N);
  257. If (P=0) then
  258. OS:='all'
  259. else
  260. begin
  261. OS:=N;
  262. Delete(OS,1,P);
  263. N:=Copy(N,1,P-1);
  264. end;
  265. If (N='dirs') then
  266. AddStrings(D,V,'',OS)
  267. else If (N='units') then
  268. AddStrings(T,V,'unit',OS)
  269. else If (N='implicitunits') then
  270. AddStrings(T,V,'unit',OS)
  271. else If (N='programs') then
  272. AddStrings(T,V,'program',OS)
  273. else If (N='examples') then
  274. AddStrings(T,V,'exampleunit',OS)
  275. else If (N='rsts') then
  276. AddStrings(R,V,'',OS)
  277. else
  278. Writeln(StdErr,'Unknown name/value pair in target section : ',Line);
  279. end;
  280. procedure TMakeFileConverter.DoInstallLine(Line : String; Var IFL : TStrings);
  281. Var
  282. S,V,N,OS : String;
  283. P : Integer;
  284. begin
  285. SplitNameValue(Line,N,V);
  286. P:=Pos('_',N);
  287. If (P=0) then
  288. OS:='all'
  289. else
  290. begin
  291. OS:=N;
  292. Delete(OS,1,P);
  293. N:=Copy(N,1,P-1);
  294. end;
  295. If (N='fpcpackage') then
  296. P:=0 // temporary, needs fixing.
  297. else If (N='buildunit') then
  298. FBuildUnit:=V // temporary, needs fixing.
  299. else If (N='units') then
  300. begin
  301. S:=GetWord(V);
  302. While (S<>'') do
  303. begin
  304. AddStrings(IFL,S+'.o','',OS);
  305. AddStrings(IFL,S+'.ppu','',OS);
  306. S:=GetWord(V);
  307. end;
  308. end
  309. else
  310. Writeln(StdErr,'Unknown name/value pair in install section : ',N);
  311. end;
  312. procedure TMakeFileConverter.DoCleanLine(Line : String; Var CFL : TStrings);
  313. Var
  314. V,N,S,OS : String;
  315. P : Integer;
  316. begin
  317. SplitNameValue(Line,N,V);
  318. P:=Pos('_',N);
  319. If (P=0) then
  320. OS:='all'
  321. else
  322. begin
  323. OS:=N;
  324. Delete(OS,1,P);
  325. N:=Copy(N,1,P-1);
  326. end;
  327. If (N='fpcpackage') then
  328. P:=0 // temporary, needs fixing.
  329. else If (N='units') then
  330. begin
  331. S:=GetWord(V);
  332. While (S<>'') do
  333. begin
  334. AddStrings(CFL,S+'.o','',OS);
  335. AddStrings(CFL,S+'.ppu','',OS);
  336. S:=GetWord(V);
  337. end;
  338. end
  339. else
  340. Writeln(StdErr,'Unknown name/value pair in clean section : ',N);
  341. end;
  342. procedure TMakeFileConverter.DoRequireLine(Line : String);
  343. Var
  344. V,N,OS : String;
  345. P : Integer;
  346. begin
  347. SplitNameValue(Line,N,V);
  348. P:=Pos('_',N);
  349. If (P=0) then
  350. OS:='all'
  351. else
  352. begin
  353. OS:=N;
  354. Delete(OS,1,P);
  355. N:=Copy(N,1,P-1);
  356. end;
  357. if (N='packages') then
  358. FPackageDeps:=V
  359. else If (N='libc') and (Upcase(V)='Y') then
  360. P:=0 // Set options ?
  361. else
  362. Writeln(StdErr,'Unknown name/value pair in require section : ',N);
  363. end;
  364. procedure TMakeFileConverter.DoCompilerLine(Line : String;Var SD : TStrings);
  365. Var
  366. V,N,OS : String;
  367. P : Integer;
  368. begin
  369. SplitNameValue(Line,N,V);
  370. P:=Pos('_',N);
  371. If (P=0) then
  372. OS:='all'
  373. else
  374. begin
  375. OS:=N;
  376. Delete(OS,1,P);
  377. N:=Copy(N,1,P-1);
  378. end;
  379. If (N='includedir') then
  380. FPackageOptions:=Trim(FPackageOptions+' -Fi'+V)
  381. else If (N='options') then
  382. FPackageOptions:=Trim(FPackageOptions+' '+V)
  383. else If (N='targetdir') then
  384. P:=0 // Ignore
  385. else if (N='sourcedir') or (N='unitdir') then
  386. begin
  387. If (SD=Nil) then
  388. SD:=TStringList.Create;
  389. SD.Add(OS+'='+V);
  390. end
  391. else
  392. Writeln(StdErr,'Unknown name/value pair in compiler section : ',N);
  393. end;
  394. Function SearchInDirs(Prefix,AName, Dirs : String) : string;
  395. Var
  396. D,S : String;
  397. begin
  398. S:=GetWord(Dirs);
  399. Result:='';
  400. While (Result='') and (S<>'') do
  401. begin
  402. D:=Prefix+S+PathDelim;
  403. If FileExists(D+AName+'.pp') or FileExists(D+AName+'.pas') then
  404. Result:=S;
  405. S:=GetWord(Dirs);
  406. end;
  407. end;
  408. procedure TMakeFileConverter.DoTargets(Src,T,R,SD : TStrings; Dir,Prefix : String);
  409. Var
  410. I,J,P : Integer;
  411. Pre,N,V,D,DOS,OS,CPU : String;
  412. Res : Boolean;
  413. begin
  414. If (Dir<>'') then
  415. Dir:=IncludeTrailingPathDelimiter(Dir);
  416. If (Prefix<>'') then
  417. Prefix:=IncludeTrailingPathDelimiter(Prefix);
  418. Dir:=Prefix+Dir;
  419. Res:=False;
  420. If Assigned(T) then
  421. For I:=0 to T.Count-1 do
  422. begin
  423. T.GetNamevalue(I,N,V);
  424. P:=Pos('_',N);
  425. If (P<>0) then
  426. begin
  427. Pre:=Copy(N,1,P-1);
  428. Delete(N,1,P);
  429. end;
  430. If Assigned(R) then
  431. Res:=R.IndexOfName(N)<>-1;
  432. GetOSCPU(V,OS,CPU);
  433. Pre[1]:=Upcase(Pre[1]);
  434. Src.Add(' T:=P.Targets.Add'+Pre+'('''+Prefix+N+'.pp'');');
  435. If (CPU<>'') then
  436. Src.Add(' T.CPU:=['+CPU+'];');
  437. If (OS<>'') then
  438. Src.Add(' T.OS:=['+OS+'];');
  439. If res then
  440. Src.add(' T.ResourceStrings:=True;');
  441. If (CompareText(FBuildUnit,N)=0) then
  442. Src.add(' T.Install:=False;');
  443. if Assigned(SD) then
  444. for J:=0 to SD.Count-1 do
  445. begin
  446. SD.GetNameValue(J,DOS,D);
  447. If (DOS<>'all') then
  448. Src.Add(' if (Defaults.OS='+DOS+') then');
  449. Src.add(' T.Directory:='''+SearchInDirs(Dir,N,D)+''';');
  450. end;
  451. end;
  452. end;
  453. procedure TMakeFileConverter.WriteOSCPUCheck(Src: TStrings;OS,CPU : String);
  454. Var
  455. S : String;
  456. begin
  457. If (CPU<>'') then
  458. S:='(Defaults.CPU='+CPU+')';
  459. If (OS<>'') then
  460. begin
  461. IF (S<>'') then
  462. S:=S+' OR ';
  463. S:=S+'(Defaults.OS='+CPU+')';
  464. end;
  465. If (S<>'') then
  466. Src.Add(' If '+S+' then');
  467. end;
  468. procedure TMakeFileConverter.DoInstalls(Src,IFL : TStrings);
  469. Var
  470. I : Integer;
  471. N,V,OS,CPU : String;
  472. begin
  473. If Assigned(IFL) then
  474. For I:=0 to IFL.Count-1 do
  475. begin
  476. IFL.GetNamevalue(I,N,V);
  477. GetOSCPU(V,OS,CPU);
  478. WriteOSCPUCheck(Src,OS,CPU);
  479. Src.add(' P.InstallFiles.Add('''+N+''');');
  480. end;
  481. end;
  482. procedure TMakeFileConverter.DoCleans(Src,CFL : TStrings);
  483. Var
  484. I : Integer;
  485. N,V,OS,CPU : String;
  486. begin
  487. If Assigned(CFL) then
  488. For I:=0 to CFL.Count-1 do
  489. begin
  490. CFL.GetNamevalue(I,N,V);
  491. GetOSCPU(V,OS,CPU);
  492. WriteOSCPUCheck(Src,OS,CPU);
  493. Src.add(' P.CleanFiles.Add('''+N+''');');
  494. end;
  495. end;
  496. procedure TMakeFileConverter.ConvertFile(const AFileName: String; Src: TStrings; Dir,OS : String);
  497. Function IsSection(var S : String) : Boolean;
  498. Var
  499. L : Integer;
  500. begin
  501. L:=Length(S);
  502. Result:=(L>0) and (S[1]='[') and (S[L]=']');
  503. If Result then
  504. S:=trim(Copy(S,2,L-2));
  505. end;
  506. Var
  507. R,L,T,D,S,SD,IFL,CFL : TStrings;
  508. I,J : Integer;
  509. Prefix,Line,DN : String;
  510. B : Boolean;
  511. begin
  512. Log(vlDebug,'Converting '+AFileName);
  513. T:=Nil;
  514. D:=Nil;
  515. S:=Nil;
  516. SD:=Nil;
  517. R:=Nil;
  518. IFL:=Nil;
  519. CFL:=Nil;
  520. FPackageOptions:='';
  521. FPackageDir:='';
  522. L:=TStringList.Create;
  523. try
  524. L.LoadFromFile(AFileName);
  525. I:=0;
  526. While (I<L.Count) do
  527. begin
  528. Line:=GetLine(L,I);
  529. If IsSection(Line) then
  530. begin
  531. J:=GetEnumValue(TypeInfo(TSectionType),'st'+Line);
  532. If (J=-1) then
  533. begin
  534. FSection:=stNone;
  535. Error('Unsupported section: '+Line);
  536. end
  537. else
  538. FSection:=TSectiontype(J);
  539. end
  540. else
  541. case FSection of
  542. stPackage : DoPackageLine(Line);
  543. stTarget : DoTargetLine(Line,T,R,D);
  544. stInstall : DoInstallLine(Line,IFL);
  545. stClean : DoCleanLine(Line,CFL);
  546. stCompiler : DoCompilerLine(Line,SD);
  547. strequire : DoRequireLine(Line);
  548. end;
  549. inc(I);
  550. end;
  551. // If there are only 'dir' entries, then there is no package name.
  552. B:=False;
  553. if (FPackageName<>'') then
  554. begin
  555. Prefix:='';
  556. B:=FPackageName<>'sub';
  557. If B then
  558. StartPackage(Src,Dir,OS)
  559. else
  560. Prefix:=Dir;
  561. DoTargets(Src,T,R,SD,Dir,Prefix);
  562. DoInstalls(Src,IFL);
  563. DoCleans(Src,CFL);
  564. end;
  565. If Assigned(D) then
  566. begin
  567. If (Dir<>'') then
  568. Dir:=IncludeTrailingPathDelimiter(Dir);
  569. For I:=0 to D.Count-1 do
  570. begin
  571. D.GetNameValue(I,DN,Line);
  572. If (Line<>'all') and (Line<>'') then
  573. OS:=Line;
  574. DN:=Dir+DN+PathDelim;
  575. If FileExists(DN+'Makefile.fpc') then
  576. ConvertFile(DN+'Makefile.fpc',Src,DN,OS);
  577. end;
  578. end;
  579. If B then
  580. EndPackage(Src,Dir,OS);
  581. Finally
  582. S.Free;
  583. IFL.Free;
  584. CFL.Free;
  585. D.Free;
  586. SD.Free;
  587. T.Free;
  588. L.Free;
  589. end;
  590. end;
  591. procedure TMakeFileConverter.ConvertFile(const Source, Dest: String);
  592. Var
  593. L : TStrings;
  594. begin
  595. Log(vlInfo,SLogGeneratingFPMake);
  596. L:=TStringList.Create;
  597. Try
  598. StartInstaller(L);
  599. ConvertFile(Source,L,'','');
  600. EndInstaller(L);
  601. L.SaveToFile(Dest);
  602. Finally
  603. L.Free;
  604. end;
  605. end;
  606. function TMakeFileConverter.Execute(const Args:TActionArgs):boolean;
  607. begin
  608. if not FileExists('fpmake.pp') then
  609. ConvertFile('Makefile.fpc','fpmake.pp')
  610. else
  611. Error(SErrConvertFPMakeExists);
  612. result:=true;
  613. end;
  614. begin
  615. RegisterPkgHandler('convertmk',TMakeFileConverter);
  616. end.