fpcmwr.pp 29 KB

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