fpcmwr.pp 30 KB

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