fpcmwr.pp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896
  1. {
  2. Copyright (c) 2001 by Peter Vreman
  3. FPCMake - Makefile writer
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {$ifdef fpc}{$mode objfpc}{$endif}
  11. {$H+}
  12. unit fpcmwr;
  13. interface
  14. uses
  15. sysutils,classes,
  16. fpcmmain;
  17. type
  18. tsections=(sec_none,
  19. sec_units,sec_exes,sec_loaders,sec_examples,sec_rsts,
  20. sec_compile,sec_install,
  21. sec_distinstall,sec_zipinstall,sec_clean,sec_shared,
  22. sec_command,sec_exts,sec_dirs,sec_tools,sec_info,sec_makefile,
  23. sec_fpmake
  24. );
  25. trules=(
  26. r_all,r_debug,r_smart,r_release,r_units,
  27. r_examples,
  28. r_shared,
  29. r_install,r_sourceinstall,r_exampleinstall,r_distinstall,
  30. r_zipinstall,r_zipsourceinstall,r_zipexampleinstall,r_zipdistinstall,
  31. r_clean,r_distclean,r_cleanall,
  32. r_info,r_makefiles
  33. );
  34. const
  35. rule2str : array[trules] of string=(
  36. 'all','debug','smart','release','units',
  37. 'examples',
  38. 'shared',
  39. 'install','sourceinstall','exampleinstall','distinstall',
  40. 'zipinstall','zipsourceinstall','zipexampleinstall','zipdistinstall',
  41. 'clean','distclean','cleanall',
  42. 'info','makefiles'
  43. );
  44. rule2sec : array[trules] of tsections=(
  45. sec_compile,sec_compile,sec_compile,sec_compile,sec_compile,
  46. sec_examples,
  47. sec_shared,
  48. sec_install,sec_install,sec_install,sec_distinstall,
  49. sec_zipinstall,sec_zipinstall,sec_zipinstall,sec_zipinstall,
  50. sec_clean,sec_clean,sec_clean,
  51. sec_info,sec_makefile
  52. );
  53. type
  54. { TMakefileWriter }
  55. TMakefileWriter=class
  56. private
  57. FFileName : string;
  58. FIni : TFPCMake;
  59. FInput : TFPCMake;
  60. FOutput : TStringList;
  61. FPhony : string;
  62. FHasSection : array[tsections] of boolean;
  63. procedure LoadFPCMakeIni;
  64. procedure AddIniSection(const s:string);
  65. procedure AddCustomSection(const s:string);
  66. procedure AddTargetVariable(const inivar:string);
  67. procedure AddVariable(const inivar:string);
  68. function AddTargetDefines(const inivar,prefix:string):string;
  69. procedure AddMainPackage(const pack:string);
  70. procedure AddRequiredPackages;
  71. procedure AddTool(const varname,exename,altexename:string);
  72. procedure AddTools(const inivar:string);
  73. procedure AddRules;
  74. procedure AddPhony(const s:string);
  75. procedure WritePhony;
  76. procedure AddTargetDirs(const inivar:string);
  77. procedure AddDefaultTools;
  78. procedure AddMakefileTargets;
  79. procedure OptimizeSections;
  80. public
  81. constructor Create(AFPCMake:TFPCMake;const AFileName:string);
  82. destructor Destroy;override;
  83. procedure WriteGenericMakefile;
  84. end;
  85. implementation
  86. {$i fpcmake.inc}
  87. type
  88. TMyMemoryStream=class(TMemoryStream)
  89. public
  90. constructor Create(p:pointer;mysize:integer);
  91. end;
  92. {*****************************************************************************
  93. Helpers
  94. *****************************************************************************}
  95. function FixVariable(s:string):string;
  96. var
  97. i : integer;
  98. begin
  99. Result:=UpperCase(s);
  100. i:=pos('.',Result);
  101. if i>0 then
  102. Result[i]:='_';
  103. end;
  104. function VarName(const s:string):string;
  105. var
  106. i,j : longint;
  107. begin
  108. i:=0;
  109. result:=s;
  110. while i<length(result) do
  111. begin
  112. inc(i);
  113. case result[i] of
  114. '{' :
  115. begin
  116. { this are pkgs which are hold the dirs between the accolades }
  117. j:=PosIdx('}',result,i);
  118. if j>0 then
  119. Delete(result,i,j-i+1)
  120. else
  121. Delete(result,i,1);
  122. dec(i);
  123. end;
  124. '$','(',')' :
  125. begin
  126. Delete(result,i,1);
  127. dec(i);
  128. end;
  129. 'a'..'z' :
  130. result[i]:=chr(ord(result[i])-32);
  131. end;
  132. end;
  133. end;
  134. procedure FixTab(sl:TStringList);
  135. var
  136. i,j,k : integer;
  137. s,s2 : string;
  138. begin
  139. i:=0;
  140. while (i<sl.Count) do
  141. begin
  142. if (sl[i]<>'') and (sl[i][1] in [' ',#9]) then
  143. begin
  144. s:=sl[i];
  145. k:=0;
  146. j:=0;
  147. repeat
  148. inc(j);
  149. case s[j] of
  150. ' ' :
  151. inc(k);
  152. #9 :
  153. k:=(k+7) and not(7);
  154. else
  155. break;
  156. end;
  157. until (j=length(s));
  158. if k>7 then
  159. begin
  160. s2:='';
  161. Delete(s,1,j-1);
  162. while (k>7) do
  163. begin
  164. s2:=s2+#9;
  165. dec(k,8);
  166. end;
  167. while (k>0) do
  168. begin
  169. s2:=s2+' ';
  170. dec(k);
  171. end;
  172. sl[i]:=s2+s;
  173. end;
  174. end;
  175. inc(i);
  176. end;
  177. end;
  178. {*****************************************************************************
  179. TMyMemoryStream
  180. *****************************************************************************}
  181. constructor TMyMemoryStream.Create(p:pointer;mysize:integer);
  182. begin
  183. inherited Create;
  184. SetPointer(p,mysize);
  185. end;
  186. {*****************************************************************************
  187. TMakefileWriter
  188. *****************************************************************************}
  189. constructor TMakefileWriter.Create(AFPCMake:TFPCMake;const AFileName:string);
  190. begin
  191. FInput:=AFPCMake;
  192. FFileName:=AFileName;
  193. FOutput:=TStringList.Create;
  194. FPhony:='';
  195. FillChar(FHasSection,sizeof(FHasSection),1);
  196. LoadFPCMakeIni;
  197. end;
  198. destructor TMakefileWriter.Destroy;
  199. begin
  200. FOutput.Free;
  201. FIni.Free;
  202. end;
  203. procedure TMakefileWriter.LoadFPCMakeIni;
  204. var
  205. IniStream : TStream;
  206. begin
  207. try
  208. IniStream:=TMyMemoryStream.Create(@fpcmakeini,sizeof(fpcmakeini));
  209. FIni:=TFPCMake.CreateFromStream(IniStream,'fpcmake.ini');
  210. { Leave the '#' comments in the output }
  211. // FIni.CommentChars:=[';'];
  212. FIni.LoadSections;
  213. finally
  214. IniStream.Destroy;
  215. end;
  216. end;
  217. procedure TMakefileWriter.AddIniSection(const s:string);
  218. var
  219. Sec : TFPCMakeSection;
  220. begin
  221. Sec:=TFPCMakeSection(FIni[s]);
  222. if assigned(Sec) then
  223. FOutput.AddStrings(Sec.List)
  224. else
  225. Raise Exception.Create(Format('Section "%s" doesn''t exists in fpcmake.ini',[s]));
  226. end;
  227. procedure TMakefileWriter.AddCustomSection(const s:string);
  228. var
  229. Sec : TFPCMakeSection;
  230. begin
  231. Sec:=TFPCMakeSection(FInput[s]);
  232. if assigned(Sec) then
  233. begin
  234. Sec.BuildMakefile;
  235. FOutput.AddStrings(Sec.List);
  236. end;
  237. end;
  238. procedure TMakefileWriter.AddTargetVariable(const inivar:string);
  239. var
  240. s : string;
  241. T : TOs;
  242. C : TCpu;
  243. begin
  244. for c:=low(TCpu) to high(TCpu) do
  245. for t:=low(TOS) to high(TOS) do
  246. if FInput.IncludeTargets[c,t] then
  247. begin
  248. s:=FInput.GetTargetVariable(c,t,IniVar,false);
  249. if s<>'' then
  250. begin
  251. FOutput.Add('ifeq ($(FULL_TARGET),'+CPUStr[c]+'-'+OSStr[t]+')');
  252. FOutput.Add('override '+FixVariable(IniVar)+'+='+s);
  253. FOutput.Add('endif');
  254. end;
  255. end;
  256. end;
  257. procedure TMakefileWriter.AddVariable(const inivar:string);
  258. var
  259. s : string;
  260. begin
  261. s:=FInput.GetVariable(IniVar,false);
  262. if s<>'' then
  263. FOutput.Add('override '+FixVariable(IniVar)+'='+s)
  264. end;
  265. function TMakefileWriter.AddTargetDefines(const inivar,prefix:string):string;
  266. procedure addtokens(s:string);
  267. var
  268. name : string;
  269. k1,k2 : integer;
  270. begin
  271. repeat
  272. Name:=GetToken(s,' ');
  273. if Name='' then
  274. break;
  275. { Remove (..) }
  276. k1:=pos('(',name);
  277. if k1>0 then
  278. begin
  279. k2:=PosIdx(')',name,k1);
  280. if k2=0 then
  281. k2:=length(name)+1;
  282. Delete(Name,k1,k2);
  283. end;
  284. FOutput.Add(prefix+VarName(name)+'=1');
  285. { add to the list of dirs without duplicates }
  286. AddTokenNoDup(result,name,' ');
  287. until false;
  288. end;
  289. var
  290. s : string;
  291. T : TOs;
  292. C : TCpu;
  293. begin
  294. result:='';
  295. for c:=low(TCpu) to high(TCpu) do
  296. for t:=low(TOS) to high(TOS) do
  297. if FInput.IncludeTargets[c,t] then
  298. begin
  299. s:=FInput.GetTargetVariable(c,t,IniVar,false);
  300. if s<>'' then
  301. begin
  302. FOutput.Add('ifeq ($(FULL_TARGET),'+CpuStr[c]+'-'+OSStr[t]+')');
  303. AddTokens(s);
  304. FOutput.Add('endif');
  305. end;
  306. end;
  307. end;
  308. procedure TMakefileWriter.AddTool(const varname,exename,altexename:string);
  309. begin
  310. with FOutput do
  311. begin
  312. Add('ifndef '+varname);
  313. Add(varname+':=$(strip $(wildcard $(addsuffix /'+exename+'$(SRCEXEEXT),$(SEARCHPATH))))');
  314. if altexename<>'' then
  315. begin
  316. Add('ifeq ($('+varname+'),)');
  317. Add(varname+':=$(strip $(wildcard $(addsuffix /'+altexename+'$(SRCEXEEXT),$(SEARCHPATH))))');
  318. end;
  319. Add('ifeq ($('+varname+'),)');
  320. Add(varname+'= __missing_command_'+varname); {This is to be shure make stops,
  321. if the command is not found. Otherwise if the command was set to the
  322. empty string, options to the command would be interpreted as command,
  323. and because options is preceeded by a "-", make will ignore the error
  324. that the command is not found.}
  325. Add('else');
  326. Add(varname+':=$(firstword $('+varname+'))');
  327. Add('endif');
  328. if altexename<>'' then
  329. begin
  330. Add('else');
  331. Add(varname+':=$(firstword $('+varname+'))');
  332. Add('endif');
  333. end;
  334. Add('endif');
  335. Add('export '+varname);
  336. end;
  337. end;
  338. procedure TMakefileWriter.AddTools(const inivar:string);
  339. var
  340. hs,tool : string;
  341. begin
  342. hs:=FInput.GetVariable(inivar,false);
  343. repeat
  344. Tool:=GetToken(hs,' ');
  345. if Tool='' then
  346. break;
  347. AddTool(FixVariable(Tool),Tool,'');
  348. until false;
  349. end;
  350. procedure TMakefileWriter.AddRules;
  351. procedure AddRule(rule:trules);
  352. var
  353. i : integer;
  354. hs : string;
  355. Sec : TFPCMakeSection;
  356. Rules : TStringList;
  357. begin
  358. Sec:=TFPCMakeSection(FInput['rules']);
  359. if assigned(Sec) then
  360. begin
  361. Rules:=Sec.List;
  362. for i:=0 to Rules.Count-1 do
  363. begin
  364. if (length(rules[i])>length(rule2str[rule])) and
  365. (rules[i][1]=rule2str[rule][1]) and
  366. ((rules[i][length(rule2str[rule])+1]=':') or
  367. ((length(rules[i])>length(rule2str[rule])+1) and
  368. (rules[i][length(rule2str[rule])+2]=':'))) and
  369. (Copy(rules[i],1,length(rule2str[rule]))=rule2str[rule]) then
  370. exit;
  371. end;
  372. end;
  373. hs:='';
  374. if FHasSection[Rule2Sec[rule]] then
  375. hs:=hs+' fpc_'+rule2str[rule];
  376. { include target dirs, but not for info and targets that
  377. call other targets with a only extra settings, if the
  378. section was not included, then still process the targets }
  379. if FInput.HasTargetVariable('target_dirs') and
  380. (not(rule in [r_info,r_shared,r_smart,r_debug,r_release,r_zipdistinstall,r_distinstall]) or
  381. not FHasSection[Rule2Sec[rule]]) then
  382. begin
  383. if FInput.HasVariable('default_dir') then
  384. hs:=hs+' $(addsuffix _'+rule2str[rule]+',$(DEFAULT_DIR))'
  385. else
  386. if not(rule in [r_sourceinstall,r_zipinstall,r_zipsourceinstall,
  387. r_makefiles]) or
  388. not(FInput.HasVariable('package_name')) then
  389. hs:=hs+' $(addsuffix _'+rule2str[rule]+',$(TARGET_DIRS))';
  390. end;
  391. { include cleaning of example dirs }
  392. if (rule=r_clean) and
  393. FInput.HasTargetVariable('target_exampledirs') then
  394. hs:=hs+' $(addsuffix _'+rule2str[rule]+',$(TARGET_EXAMPLEDIRS))';
  395. { Add the rule }
  396. AddPhony(Rule2Str[Rule]);
  397. FOutput.Add(rule2str[rule]+':'+hs);
  398. end;
  399. var
  400. rule : trules;
  401. begin
  402. for rule:=low(trules) to high(trules) do
  403. AddRule(rule);
  404. WritePhony;
  405. end;
  406. procedure TMakefileWriter.AddPhony(const s:string);
  407. begin
  408. FPhony:=FPhony+' '+s;
  409. end;
  410. procedure TMakefileWriter.WritePhony;
  411. begin
  412. if FPhony<>'' then
  413. begin
  414. FOutput.Add('.PHONY:'+FPhony);
  415. FPhony:='';
  416. end;
  417. end;
  418. procedure TMakefileWriter.AddTargetDirs(const inivar:string);
  419. procedure AddTargetDir(const s,defpref:string);
  420. var
  421. j : trules;
  422. begin
  423. FOutput.Add('ifdef '+defpref+VarName(s));
  424. for j:=low(trules) to high(trules) do
  425. begin
  426. FOutput.Add(s+'_'+rule2str[j]+':');
  427. FOutput.Add(#9+'$(MAKE) -C '+s+' '+rule2str[j]);
  428. AddPhony(s+'_'+rule2str[j]);
  429. end;
  430. FOutput.Add(s+':');
  431. FOutput.Add(#9+'$(MAKE) -C '+s+' all');
  432. AddPhony(s);
  433. WritePhony;
  434. FOutput.Add('endif');
  435. end;
  436. var
  437. hs,dir : string;
  438. prefix : string;
  439. begin
  440. prefix:=FixVariable(inivar)+'_';
  441. hs:=AddTargetDefines(inivar,prefix);
  442. repeat
  443. Dir:=GetToken(hs,' ');
  444. if Dir='' then
  445. break;
  446. AddTargetDir(Dir,prefix);
  447. until false;
  448. end;
  449. procedure TMakefileWriter.AddMainPackage(const pack:string);
  450. var
  451. packdirvar : string;
  452. begin
  453. { create needed variables }
  454. packdirvar:='PACKAGEDIR_MAIN';
  455. { Search packagedir by looking for Makefile.fpc }
  456. FOutput.Add(packdirvar+':=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /'+pack+'/Makefile.fpc,$(PACKAGESDIR))))))');
  457. end;
  458. procedure TMakefileWriter.AddRequiredPackages;
  459. procedure AddPackage(const pack,prefix:string);
  460. var
  461. packdirvar,unitdirvar,unitfpmakedirvar : string;
  462. fpcmadedirvar : string;
  463. begin
  464. FOutput.Add('ifdef '+Prefix+VarName(pack));
  465. { create needed variables }
  466. packdirvar:='PACKAGEDIR_'+VarName(pack);
  467. unitdirvar:='UNITDIR_'+VarName(pack);
  468. unitfpmakedirvar:='UNITDIR_FPMAKE_'+VarName(pack);
  469. { Search packagedir by looking for Makefile.fpc }
  470. FOutput.Add(packdirvar+':=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /'+pack+'/Makefile.fpc,$(PACKAGESDIR))))))');
  471. FOutput.Add('ifneq ($('+packdirvar+'),)');
  472. { Create unit dir, check if os dependent dir exists }
  473. FOutput.Add('ifneq ($(wildcard $('+packdirvar+')/units/$(TARGETSUFFIX)),)');
  474. FOutput.Add(unitdirvar+'=$('+packdirvar+')/units/$(TARGETSUFFIX)');
  475. FOutput.Add('else');
  476. FOutput.Add(unitdirvar+'=$('+packdirvar+')');
  477. FOutput.Add('endif');
  478. FOutput.Add('ifneq ($(wildcard $('+packdirvar+')/units/$(SOURCESUFFIX)),)');
  479. FOutput.Add(unitfpmakedirvar+'=$('+packdirvar+')/units/$(SOURCESUFFIX)');
  480. FOutput.Add('else');
  481. FOutput.Add('ifneq ($(wildcard $('+packdirvar+')/units_bs/$(SOURCESUFFIX)),)');
  482. FOutput.Add(unitfpmakedirvar+'=$('+packdirvar+')/units_bs/$(SOURCESUFFIX)');
  483. FOutput.Add('else');
  484. FOutput.Add(unitfpmakedirvar+'=$('+packdirvar+')');
  485. FOutput.Add('endif');
  486. FOutput.Add('endif');
  487. FOutput.Add('ifdef CHECKDEPEND');
  488. { rtl needs special handling for FPCMADE }
  489. if pack='rtl' then
  490. fpcmadedirvar:='/$(OS_TARGET)'
  491. else
  492. fpcmadedirvar:='';
  493. FOutput.Add('$('+packdirvar+')'+fpcmadedirvar+'/$(FPCMADE):');
  494. FOutput.Add(#9'$(MAKE) -C $('+packdirvar+')'+fpcmadedirvar+' $(FPCMADE)');
  495. FOutput.Add('override ALLDEPENDENCIES+=$('+packdirvar+')'+fpcmadedirvar+'/$(FPCMADE)');
  496. FOutput.Add('endif');
  497. { Package dir doesn't exists, check unit dir }
  498. FOutput.Add('else');
  499. FOutput.Add(packdirvar+'=');
  500. FOutput.Add(unitdirvar+':=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /'+pack+'/Package.fpc,$(UNITSDIR)))))');
  501. FOutput.Add('ifneq ($('+unitdirvar+'),)');
  502. FOutput.Add(unitdirvar+':=$(firstword $('+unitdirvar+'))');
  503. FOutput.Add('else');
  504. FOutput.Add(unitdirvar+'=');
  505. FOutput.Add('endif');
  506. FOutput.Add('endif');
  507. { Add Unit dir to the command line -Fu }
  508. FOutput.Add('ifdef '+unitdirvar);
  509. FOutput.Add('override COMPILER_UNITDIR+=$('+unitdirvar+')');
  510. FOutput.Add('endif');
  511. FOutput.Add('ifdef '+unitfpmakedirvar);
  512. FOutput.Add('override COMPILER_FPMAKE_UNITDIR+=$('+unitfpmakedirvar+')');
  513. FOutput.Add('endif');
  514. { endif for package }
  515. FOutput.Add('endif');
  516. end;
  517. var
  518. i : integer;
  519. reqs,req,prefix : string;
  520. t : TOS;
  521. c : TCpu;
  522. sl : TStringList;
  523. begin
  524. prefix:='REQUIRE_PACKAGES_';
  525. reqs:='';
  526. { Add target defines }
  527. for c:=low(tcpu) to high(tcpu) do
  528. for t:=low(tos) to high(tos) do
  529. if FInput.IncludeTargets[c,t] then
  530. begin
  531. sl:=FInput.GetTargetRequires(c,t);
  532. { show info }
  533. FInput.Verbose(FPCMakeInfo,CpuStr[c]+'-'+OSStr[t]+' requires: '+sl.CommaText);
  534. if sl.count>0 then
  535. begin
  536. FOutput.Add('ifeq ($(FULL_TARGET),'+CPUStr[c]+'-'+OSStr[t]+')');
  537. for i:=0 to sl.count-1 do
  538. begin
  539. FOutput.Add(prefix+VarName(sl[i])+'=1');
  540. AddTokenNoDup(reqs,sl[i],' ');
  541. end;
  542. FOutput.Add('endif');
  543. end;
  544. sl.Free;
  545. end;
  546. { Add all require packages }
  547. repeat
  548. req:=GetToken(reqs,' ');
  549. if Req='' then
  550. break;
  551. AddPackage(req,prefix);
  552. until false;
  553. WritePhony;
  554. end;
  555. procedure TMakefileWriter.AddDefaultTools;
  556. begin
  557. AddTool('ECHO','gecho','echo');
  558. AddTool('DATE','gdate','date');
  559. AddTool('GINSTALL','ginstall','install');
  560. AddTool('CPPROG','cp','');
  561. AddTool('RMPROG','rm','');
  562. AddTool('MVPROG','mv','');
  563. AddTool('MKDIRPROG','gmkdir','mkdir');
  564. AddIniSection('shelltools');
  565. AddTool('PPUMOVE','ppumove','');
  566. AddTool('FPCMAKE','fpcmake','');
  567. AddTool('ZIPPROG','zip','');
  568. AddTool('TARPROG','gtar','tar');
  569. AddIniSection('defaulttools');
  570. end;
  571. procedure TMakefileWriter.AddMakefileTargets;
  572. var
  573. s : string;
  574. c : TCpu;
  575. t : Tos;
  576. begin
  577. s:='';
  578. for c:=low(tcpu) to high(tcpu) do
  579. for t:=low(tos) to high(tos) do
  580. if FInput.IncludeTargets[c,t] then
  581. AddToken(s,CpuStr[c]+'-'+OSStr[t],' ');
  582. FOutput.Add('MAKEFILETARGETS='+s);
  583. end;
  584. procedure TMakefileWriter.OptimizeSections;
  585. var
  586. SkippedSecs :integer;
  587. begin
  588. { Turn some sections off, depending if files are
  589. provided }
  590. if not FInput.IsPackage then
  591. begin
  592. FHasSection[sec_zipinstall]:=false;
  593. FHasSection[sec_distinstall]:=false;
  594. end;
  595. { Remove unused sections for targets }
  596. SkippedSecs:=0;
  597. if (not FInput.HasTargetVariable('target_units')) and (not FInput.HasTargetVariable('target_implicitunits')) then
  598. begin
  599. inc(SkippedSecs);
  600. FHasSection[sec_units]:=false;
  601. end;
  602. if (not FInput.HasTargetVariable('target_programs')) then
  603. begin
  604. inc(SkippedSecs);
  605. FHasSection[sec_exes]:=false;
  606. end;
  607. if (not FInput.HasTargetVariable('target_examples')) then
  608. begin
  609. inc(SkippedSecs);
  610. { example dirs also requires the fpc_examples target, because
  611. it also depends on the all target }
  612. if (not FInput.HasTargetVariable('target_exampledirs')) then
  613. FHasSection[sec_examples]:=false;
  614. end;
  615. if (not FInput.HasTargetVariable('target_loaders')) then
  616. begin
  617. inc(SkippedSecs);
  618. FHasSection[sec_loaders]:=false;
  619. end;
  620. if (not FInput.HasTargetVariable('target_fpmake')) then
  621. begin
  622. inc(SkippedSecs);
  623. FHasSection[sec_fpmake]:=false;
  624. end;
  625. { if all 5 sections are not available we can skip also the
  626. generic compile rules }
  627. if SkippedSecs=5 then
  628. begin
  629. FHasSection[sec_shared]:=false;
  630. FHasSection[sec_compile]:=false;
  631. if (not FInput.HasTargetVariable('package_name')) and
  632. (not FInput.HasTargetVariable('install_units')) and
  633. (not FInput.HasTargetVariable('install_files')) and
  634. (not FInput.HasTargetVariable('install_createpackagefpc')) then
  635. FHasSection[sec_install]:=false;
  636. { Package.fpc also needs to be cleaned }
  637. if (not FInput.HasTargetVariable('clean_units')) and
  638. (not FInput.HasTargetVariable('clean_files')) and
  639. (not FInput.HasTargetVariable('install_createpackagefpc')) then
  640. FHasSection[sec_clean]:=false;
  641. end;
  642. end;
  643. procedure TMakefileWriter.WriteGenericMakefile;
  644. begin
  645. { Remove unused sections }
  646. OptimizeSections;
  647. { Generate Output }
  648. with FOutput do
  649. begin
  650. { Header }
  651. Add('#');
  652. Add('# Don''t edit, this file is generated by '+TitleDate);
  653. Add('#');
  654. if FInput.HasVariable('default_rule') then
  655. Add('default: '+FInput.GetVariable('default_rule',false))
  656. else
  657. Add('default: all');
  658. { Supported targets by this Makefile }
  659. AddMakefileTargets;
  660. { Add misc defines }
  661. AddIniSection('defines');
  662. { Add automatic detect sections }
  663. AddIniSection('osdetect');
  664. { Forced target }
  665. if FInput.HasVariable('require_target') then
  666. Add('override OS_TARGET='+FInput.GetVariable('require_target',false))
  667. else if FInput.HasVariable('default_target') then
  668. Add('override OS_TARGET_DEFAULT='+FInput.GetVariable('default_target',false));
  669. if FInput.HasVariable('require_cpu') then
  670. Add('override CPU_TARGET='+FInput.GetVariable('require_cpu',false))
  671. else if FInput.HasVariable('default_cpu') then
  672. Add('override CPU_TARGET_DEFAULT='+FInput.GetVariable('default_cpu',false));
  673. { FPC Detection }
  674. AddVariable('default_fpcdir');
  675. AddIniSection('fpcdetect');
  676. AddIniSection('fpcdircheckenv');
  677. AddIniSection('fpcdirdetect');
  678. AddIniSection('fpmakefpcdetect');
  679. { Package }
  680. AddVariable('package_name');
  681. AddVariable('package_version');
  682. AddVariable('package_targets');
  683. { Directory of main package }
  684. if FInput.HasVariable('package_main') then
  685. AddMainPackage(FInput.GetVariable('package_main',false));
  686. { LCL rules }
  687. if FInput.UsesLCL then
  688. begin
  689. AddVariable('default_lcldir');
  690. AddVariable('lcl_platform');
  691. AddIniSection('lclrules');
  692. end;
  693. { First add the required packages sections }
  694. // for i:=0 to FInput.RequireList.Count-1 do
  695. // AddCustomSection(FInput.Requirelist[i]);
  696. { prerules section }
  697. if assigned(FInput['prerules']) then
  698. AddStrings(TFPCMakeSection(FInput['prerules']).List);
  699. if FHasSection[sec_fpmake] then
  700. AddIniSection('fpmakeprerules');
  701. { Default }
  702. AddVariable('default_dir');
  703. { Targets }
  704. AddTargetVariable('target_dirs');
  705. AddTargetVariable('target_programs');
  706. AddTargetVariable('target_units');
  707. AddTargetVariable('target_implicitunits');
  708. AddTargetVariable('target_loaders');
  709. AddTargetVariable('target_rsts');
  710. AddTargetVariable('target_examples');
  711. AddTargetVariable('target_exampledirs');
  712. AddTargetVariable('target_fpmake');
  713. { Clean }
  714. AddTargetVariable('clean_units');
  715. AddTargetVariable('clean_files');
  716. AddTargetVariable('clean_programs');
  717. { Install }
  718. AddTargetVariable('install_units');
  719. AddTargetVariable('install_files');
  720. AddVariable('install_buildunit');
  721. AddVariable('install_prefix');
  722. AddVariable('install_basedir');
  723. AddVariable('install_datadir');
  724. AddVariable('install_fpcpackage');
  725. AddVariable('install_fpcsubdir');
  726. AddVariable('install_createpackagefpc');
  727. { Dist }
  728. AddVariable('dist_destdir');
  729. AddVariable('dist_zipname');
  730. AddVariable('dist_ziptarget');
  731. { Compiler }
  732. AddTargetVariable('compiler_options');
  733. AddTargetVariable('compiler_version');
  734. AddTargetVariable('compiler_includedir');
  735. AddTargetVariable('compiler_unitdir');
  736. AddTargetVariable('compiler_sourcedir');
  737. AddTargetVariable('compiler_objectdir');
  738. AddTargetVariable('compiler_librarydir');
  739. AddTargetVariable('compiler_targetdir');
  740. AddTargetVariable('compiler_unittargetdir');
  741. { shared }
  742. AddVariable('shared_build');
  743. AddVariable('shared_libname');
  744. AddVariable('shared_libversion');
  745. AddVariable('shared_libunits');
  746. AddVariable('shared_build');
  747. { default Dirs and extensions }
  748. AddIniSection('defaultdirs');
  749. if FInput.CheckLibcRequire then
  750. AddIniSection('dirlibc');
  751. AddIniSection('extensions');
  752. { Add default tools }
  753. AddDefaultTools;
  754. { Required packages }
  755. AddVariable('require_packages');
  756. AddRequiredPackages;
  757. { commandline }
  758. AddIniSection('command_begin');
  759. if FInput.CheckLibcRequire then
  760. AddIniSection('command_libc');
  761. AddIniSection('command_end');
  762. { compile }
  763. if FHasSection[sec_fpmake] then
  764. AddIniSection('fpmakerules');
  765. if FHasSection[sec_loaders] then
  766. AddIniSection('loaderrules');
  767. if FHasSection[sec_units] then
  768. AddIniSection('unitrules');
  769. if FHasSection[sec_exes] then
  770. AddIniSection('exerules');
  771. if FHasSection[sec_rsts] then
  772. AddIniSection('rstrules');
  773. if FHasSection[sec_examples] then
  774. AddIniSection('examplerules');
  775. if FHasSection[sec_compile] then
  776. AddIniSection('compilerules');
  777. if FHasSection[sec_shared] then
  778. AddIniSection('sharedrules');
  779. { install }
  780. if FHasSection[sec_install] then
  781. AddIniSection('installrules');
  782. if FHasSection[sec_distinstall] then
  783. AddIniSection('distinstallrules');
  784. if FHasSection[sec_zipinstall] then
  785. AddIniSection('zipinstallrules');
  786. { clean }
  787. AddIniSection('cleanrules');
  788. { info }
  789. AddIniSection('baseinforules');
  790. if FInput.UsesLCL then
  791. AddIniSection('lclinforules');
  792. AddIniSection('inforules');
  793. { info }
  794. AddIniSection('makefilerules');
  795. { Subdirs }
  796. AddTargetDirs('target_dirs');
  797. AddTargetDirs('target_exampledirs');
  798. { Tools }
  799. AddTools('require_tools');
  800. { Rules }
  801. AddRules;
  802. { Users own rules }
  803. AddIniSection('localmakefile');
  804. AddIniSection('userrules');
  805. if assigned(FInput['rules']) then
  806. AddStrings(TFPCMakeSection(FInput['rules']).List);
  807. end;
  808. { write to disk }
  809. FInput.Verbose(FPCMakeInfo,'Writing Makefile');
  810. Fixtab(FOutput);
  811. FOutput.SaveToFile(FFileName);
  812. end;
  813. end.