fpcmwr.pp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977
  1. {
  2. $Id$
  3. Copyright (c) 2001 by Peter Vreman
  4. FPCMake - Makefile writer
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$ifdef fpc}{$mode objfpc}{$endif}
  12. {$H+}
  13. unit fpcmwr;
  14. interface
  15. uses
  16. sysutils,classes,
  17. fpcmmain;
  18. type
  19. tsections=(sec_none,
  20. sec_units,sec_exes,sec_loaders,sec_examples,sec_rsts,
  21. sec_compile,sec_install,
  22. sec_distinstall,sec_zipinstall,sec_clean,sec_libs,
  23. sec_command,sec_exts,sec_dirs,sec_tools,sec_info,sec_makefile
  24. );
  25. trules=(
  26. r_all,r_debug,r_smart,r_release,
  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',
  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,
  46. sec_examples,
  47. sec_libs,
  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=class
  55. private
  56. FFileName : string;
  57. FIni : TFPCMake;
  58. FInput : TFPCMake;
  59. FOutput : TStringList;
  60. FPhony : string;
  61. FHasSection : array[tsections] of boolean;
  62. procedure LoadFPCMakeIni;
  63. procedure AddIniSection(const s:string);
  64. procedure AddCustomSection(const s:string);
  65. procedure AddTargetVariable(const inivar:string);
  66. procedure AddVariable(const inivar:string);
  67. function AddTargetDefines(const inivar,prefix:string):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. function CheckTargetVariable(const inivar:string):boolean;
  76. function CheckVariable(const inivar:string):boolean;
  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. function TMakefileWriter.CheckTargetVariable(const inivar:string):boolean;
  239. var
  240. t : TTarget;
  241. begin
  242. result:=false;
  243. if FInput.GetVariable(IniVar,false)<>'' then
  244. begin
  245. result:=true;
  246. exit;
  247. end;
  248. for t:=low(TTarget) to high(TTarget) do
  249. if (t in FInput.IncludeTargets) and
  250. (FInput.GetVariable(IniVar+TargetSuffix[t],false)<>'') then
  251. begin
  252. result:=true;
  253. exit;
  254. end;
  255. end;
  256. function TMakefileWriter.CheckVariable(const inivar:string):boolean;
  257. begin
  258. Result:=(FInput.GetVariable(IniVar,false)<>'');
  259. end;
  260. procedure TMakefileWriter.AddTargetVariable(const inivar:string);
  261. var
  262. s : string;
  263. T : TTarget;
  264. C : TCpu;
  265. firsttarget,
  266. firstcpu : boolean;
  267. begin
  268. s:=FInput.GetVariable(IniVar,false);
  269. if s<>'' then
  270. FOutput.Add('override '+FixVariable(IniVar)+'+='+s);
  271. for t:=low(TTarget) to high(TTarget) do
  272. if t in FInput.IncludeTargets then
  273. begin
  274. firsttarget:=true;
  275. firstcpu:=true;
  276. s:=FInput.GetVariable(IniVar+TargetSuffix[t],false);
  277. if s<>'' then
  278. begin
  279. if firsttarget then
  280. begin
  281. firsttarget:=false;
  282. FOutput.Add('ifeq ($(OS_TARGET),'+TargetStr[t]+')');
  283. end;
  284. FOutput.Add('override '+FixVariable(IniVar)+'+='+s);
  285. end;
  286. for c:=low(TCpu) to high(TCpu) do
  287. if (TargetCpuPossible[t,c]) and (c in FInput.IncludeCpus) then
  288. begin
  289. s:=FInput.GetVariable(IniVar+TargetSuffix[t]+CpuSuffix[c],false);
  290. if s<>'' then
  291. begin
  292. if firsttarget then
  293. begin
  294. firsttarget:=false;
  295. FOutput.Add('ifeq ($(OS_TARGET),'+TargetStr[t]+')');
  296. end;
  297. if firstcpu then
  298. begin
  299. firstcpu:=false;
  300. FOutput.Add('ifeq ($(CPU_TARGET),'+CpuStr[c]+')');
  301. end;
  302. FOutput.Add('override '+FixVariable(IniVar)+'+='+s);
  303. end;
  304. end;
  305. if not firstcpu then
  306. FOutput.Add('endif');
  307. if not firsttarget then
  308. FOutput.Add('endif');
  309. end;
  310. end;
  311. procedure TMakefileWriter.AddVariable(const inivar:string);
  312. var
  313. s : string;
  314. begin
  315. s:=FInput.GetVariable(IniVar,false);
  316. if s<>'' then
  317. FOutput.Add('override '+FixVariable(IniVar)+'='+s)
  318. end;
  319. function TMakefileWriter.AddTargetDefines(const inivar,prefix:string):string;
  320. procedure addtokens(s:string);
  321. var
  322. name : string;
  323. k1,k2 : integer;
  324. begin
  325. repeat
  326. Name:=GetToken(s,' ');
  327. if Name='' then
  328. break;
  329. { Remove (..) }
  330. k1:=pos('(',name);
  331. if k1>0 then
  332. begin
  333. k2:=PosIdx(')',name,k1);
  334. if k2=0 then
  335. k2:=length(name)+1;
  336. Delete(Name,k1,k2);
  337. end;
  338. FOutput.Add(prefix+VarName(name)+'=1');
  339. { add to the list of dirs without duplicates }
  340. AddTokenNoDup(result,name,' ');
  341. until false;
  342. end;
  343. var
  344. s : string;
  345. T : TTarget;
  346. c : TCpu;
  347. firsttarget,
  348. firstcpu : boolean;
  349. begin
  350. result:='';
  351. s:=FInput.GetVariable(IniVar,false);
  352. addtokens(s);
  353. for t:=low(TTarget) to high(TTarget) do
  354. if t in FInput.IncludeTargets then
  355. begin
  356. firsttarget:=true;
  357. firstcpu:=true;
  358. s:=FInput.GetVariable(IniVar+TargetSuffix[t],false);
  359. if s<>'' then
  360. begin
  361. if firsttarget then
  362. begin
  363. firsttarget:=false;
  364. FOutput.Add('ifeq ($(OS_TARGET),'+TargetStr[t]+')');
  365. end;
  366. addtokens(s);
  367. end;
  368. for c:=low(TCpu) to high(TCpu) do
  369. if (TargetCpuPossible[t,c]) and (c in FInput.IncludeCpus) then
  370. begin
  371. s:=FInput.GetVariable(IniVar+TargetSuffix[t]+CpuSuffix[c],false);
  372. if s<>'' then
  373. begin
  374. if firsttarget then
  375. begin
  376. firsttarget:=false;
  377. FOutput.Add('ifeq ($(OS_TARGET),'+TargetStr[t]+')');
  378. end;
  379. if firstcpu then
  380. begin
  381. firstcpu:=false;
  382. FOutput.Add('ifeq ($(CPU_TARGET),'+CpuStr[c]+')');
  383. end;
  384. addtokens(s);
  385. end;
  386. end;
  387. if not firstcpu then
  388. FOutput.Add('endif');
  389. if not firsttarget then
  390. FOutput.Add('endif');
  391. end;
  392. end;
  393. procedure TMakefileWriter.AddTool(const varname,exename,altexename:string);
  394. begin
  395. with FOutput do
  396. begin
  397. Add('ifndef '+varname);
  398. Add(varname+':=$(strip $(wildcard $(addsuffix /'+exename+'$(SRCEXEEXT),$(SEARCHPATH))))');
  399. if altexename<>'' then
  400. begin
  401. Add('ifeq ($('+varname+'),)');
  402. Add(varname+':=$(strip $(wildcard $(addsuffix /'+altexename+'$(SRCEXEEXT),$(SEARCHPATH))))');
  403. end;
  404. Add('ifeq ($('+varname+'),)');
  405. Add(varname+'= __missing_command__'); {This is to be shure make stops,
  406. if the command is not found. Otherwise if the command was set to the
  407. empty string, options to the command would be interpreted as command,
  408. and because options is preceeded by a "-", make will ignore the error
  409. that the command is not found.}
  410. Add('else');
  411. Add(varname+':=$(firstword $('+varname+'))');
  412. Add('endif');
  413. if altexename<>'' then
  414. begin
  415. Add('else');
  416. Add(varname+':=$(firstword $('+varname+'))');
  417. Add('endif');
  418. end;
  419. Add('endif');
  420. Add('export '+varname);
  421. end;
  422. end;
  423. procedure TMakefileWriter.AddTools(const inivar:string);
  424. var
  425. hs,tool : string;
  426. begin
  427. hs:=FInput.GetVariable(inivar,false);
  428. repeat
  429. Tool:=GetToken(hs,' ');
  430. if Tool='' then
  431. break;
  432. AddTool(FixVariable(Tool),Tool,'');
  433. until false;
  434. end;
  435. procedure TMakefileWriter.AddRules;
  436. procedure AddRule(rule:trules);
  437. var
  438. i : integer;
  439. hs : string;
  440. Sec : TFPCMakeSection;
  441. Rules : TStringList;
  442. begin
  443. Sec:=TFPCMakeSection(FInput['rules']);
  444. if assigned(Sec) then
  445. begin
  446. Rules:=Sec.List;
  447. for i:=0 to Rules.Count-1 do
  448. begin
  449. if (length(rules[i])>length(rule2str[rule])) and
  450. (rules[i][1]=rule2str[rule][1]) and
  451. ((rules[i][length(rule2str[rule])+1]=':') or
  452. ((length(rules[i])>length(rule2str[rule])+1) and
  453. (rules[i][length(rule2str[rule])+2]=':'))) and
  454. (Copy(rules[i],1,length(rule2str[rule]))=rule2str[rule]) then
  455. exit;
  456. end;
  457. end;
  458. hs:='';
  459. if FHasSection[Rule2Sec[rule]] then
  460. hs:=hs+' fpc_'+rule2str[rule];
  461. { include target dirs, but not for info and targets that
  462. call other targets with a only extra settings, if the
  463. section was not included, then still process the targets }
  464. if CheckTargetVariable('target_dirs') and
  465. (not(rule in [r_info,r_shared,r_smart,r_debug,r_release,r_zipdistinstall,r_distinstall]) or
  466. not FHasSection[Rule2Sec[rule]]) then
  467. begin
  468. if CheckVariable('default_dir') then
  469. hs:=hs+' $(addsuffix _'+rule2str[rule]+',$(DEFAULT_DIR))'
  470. else
  471. if not(rule in [r_sourceinstall,r_zipinstall,r_zipsourceinstall,
  472. r_makefiles]) or
  473. not(CheckVariable('package_name')) then
  474. hs:=hs+' $(addsuffix _'+rule2str[rule]+',$(TARGET_DIRS))';
  475. end;
  476. { include cleaning of example dirs }
  477. if (rule=r_clean) and
  478. CheckTargetVariable('target_exampledirs') then
  479. hs:=hs+' $(addsuffix _'+rule2str[rule]+',$(TARGET_EXAMPLEDIRS))';
  480. { Add the rule }
  481. AddPhony(Rule2Str[Rule]);
  482. FOutput.Add(rule2str[rule]+':'+hs);
  483. end;
  484. var
  485. rule : trules;
  486. begin
  487. for rule:=low(trules) to high(trules) do
  488. AddRule(rule);
  489. WritePhony;
  490. end;
  491. procedure TMakefileWriter.AddPhony(const s:string);
  492. begin
  493. FPhony:=FPhony+' '+s;
  494. end;
  495. procedure TMakefileWriter.WritePhony;
  496. begin
  497. if FPhony<>'' then
  498. begin
  499. FOutput.Add('.PHONY:'+FPhony);
  500. FPhony:='';
  501. end;
  502. end;
  503. procedure TMakefileWriter.AddTargetDirs(const inivar:string);
  504. procedure AddTargetDir(const s,defpref:string);
  505. var
  506. j : trules;
  507. begin
  508. FOutput.Add('ifdef '+defpref+VarName(s));
  509. for j:=low(trules) to high(trules) do
  510. begin
  511. FOutput.Add(s+'_'+rule2str[j]+':');
  512. FOutput.Add(#9+'$(MAKE) -C '+s+' '+rule2str[j]);
  513. AddPhony(s+'_'+rule2str[j]);
  514. end;
  515. FOutput.Add(s+':');
  516. FOutput.Add(#9+'$(MAKE) -C '+s+' all');
  517. AddPhony(s);
  518. WritePhony;
  519. FOutput.Add('endif');
  520. end;
  521. var
  522. hs,dir : string;
  523. prefix : string;
  524. begin
  525. prefix:=FixVariable(inivar)+'_';
  526. hs:=AddTargetDefines(inivar,prefix);
  527. repeat
  528. Dir:=GetToken(hs,' ');
  529. if Dir='' then
  530. break;
  531. AddTargetDir(Dir,prefix);
  532. until false;
  533. end;
  534. procedure TMakefileWriter.AddRequiredPackages;
  535. procedure AddPackage(const pack,prefix:string);
  536. var
  537. packdirvar,unitdirvar : string;
  538. begin
  539. FOutput.Add('ifdef '+Prefix+VarName(pack));
  540. { create needed variables }
  541. packdirvar:='PACKAGEDIR_'+VarName(pack);
  542. unitdirvar:='UNITDIR_'+VarName(pack);
  543. { Search packagedir by looking for Makefile.fpc, for the RTL look
  544. direct in the corresponding target directory }
  545. if pack='rtl' then
  546. FOutput.Add(packdirvar+':=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /'+pack+'/$(OS_TARGET)/Makefile.fpc,$(PACKAGESDIR))))))')
  547. else
  548. FOutput.Add(packdirvar+':=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /'+pack+'/Makefile.fpc,$(PACKAGESDIR))))))');
  549. FOutput.Add('ifneq ($('+packdirvar+'),)');
  550. { Create unit dir, check if os dependent dir exists }
  551. FOutput.Add('ifneq ($(wildcard $('+packdirvar+')/$(OS_TARGET)),)');
  552. FOutput.Add(unitdirvar+'=$('+packdirvar+')/$(OS_TARGET)');
  553. FOutput.Add('else');
  554. FOutput.Add(unitdirvar+'=$('+packdirvar+')');
  555. FOutput.Add('endif');
  556. FOutput.Add('ifdef CHECKDEPEND');
  557. FOutput.Add('$('+packdirvar+')/$(FPCMADE):');
  558. FOutput.Add(#9'$(MAKE) -C $('+packdirvar+') $(FPCMADE)');
  559. FOutput.Add('override ALLDEPENDENCIES+=$('+packdirvar+')/$(FPCMADE)');
  560. FOutput.Add('endif');
  561. { Package dir doesn't exists, check unit dir }
  562. FOutput.Add('else');
  563. FOutput.Add(packdirvar+'=');
  564. FOutput.Add(unitdirvar+':=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /'+pack+'/Package.fpc,$(UNITSDIR)))))');
  565. FOutput.Add('ifneq ($('+unitdirvar+'),)');
  566. FOutput.Add(unitdirvar+':=$(firstword $('+unitdirvar+'))');
  567. FOutput.Add('else');
  568. FOutput.Add(unitdirvar+'=');
  569. FOutput.Add('endif');
  570. FOutput.Add('endif');
  571. { Add Unit dir to the command line -Fu }
  572. FOutput.Add('ifdef '+unitdirvar);
  573. FOutput.Add('override COMPILER_UNITDIR+=$('+unitdirvar+')');
  574. FOutput.Add('endif');
  575. { endif for package }
  576. FOutput.Add('endif');
  577. end;
  578. var
  579. i : integer;
  580. reqs,req,prefix : string;
  581. t : Ttarget;
  582. c : TCpu;
  583. sl : TStringList;
  584. begin
  585. prefix:='REQUIRE_PACKAGES_';
  586. reqs:='';
  587. { Add target defines }
  588. for t:=low(ttarget) to high(ttarget) do
  589. if t in FInput.IncludeTargets then
  590. begin
  591. for c:=low(tcpu) to high(tcpu) do
  592. if (TargetCpuPossible[t,c]) and (c in FInput.IncludeCpus) then
  593. begin
  594. sl:=FInput.GetTargetRequires(t,c);
  595. { show info }
  596. FInput.Verbose(FPCMakeInfo,TargetStr[t]+'-'+CpuStr[c]+' requires: '+sl.CommaText);
  597. if sl.count>0 then
  598. begin
  599. FOutput.Add('ifeq ($(OS_TARGET),'+TargetStr[t]+')');
  600. FOutput.Add('ifeq ($(CPU_TARGET),'+CpuStr[c]+')');
  601. for i:=0 to sl.count-1 do
  602. begin
  603. FOutput.Add(prefix+VarName(sl[i])+'=1');
  604. AddTokenNoDup(reqs,sl[i],' ');
  605. end;
  606. FOutput.Add('endif');
  607. FOutput.Add('endif');
  608. end;
  609. sl.Free;
  610. end;
  611. end;
  612. { Add all require packages }
  613. repeat
  614. req:=GetToken(reqs,' ');
  615. if Req='' then
  616. break;
  617. AddPackage(req,prefix);
  618. until false;
  619. WritePhony;
  620. end;
  621. procedure TMakefileWriter.AddDefaultTools;
  622. begin
  623. AddTool('ECHO','gecho','echo');
  624. AddTool('DATE','gdate','date');
  625. AddTool('GINSTALL','ginstall','install');
  626. AddTool('CPPROG','cp','');
  627. AddTool('RMPROG','rm','');
  628. AddTool('MVPROG','mv','');
  629. AddIniSection('shelltools');
  630. AddTool('PPUMOVE','ppumove','');
  631. AddTool('FPCMAKE','fpcmake','');
  632. AddTool('ZIPPROG','zip','');
  633. AddTool('TARPROG','tar','');
  634. AddIniSection('defaulttools');
  635. end;
  636. procedure TMakefileWriter.AddMakefileTargets;
  637. var
  638. s : string;
  639. t : Ttarget;
  640. begin
  641. s:='';
  642. for t:=low(ttarget) to high(ttarget) do
  643. if t in FInput.IncludeTargets then
  644. begin
  645. AddToken(s,TargetStr[t],' ');
  646. end;
  647. FOutput.Add('MAKEFILETARGETS='+s);
  648. end;
  649. procedure TMakefileWriter.OptimizeSections;
  650. var
  651. SkippedSecs :integer;
  652. begin
  653. { Turn some sections off, depending if files are
  654. provided }
  655. if not FInput.IsPackage then
  656. begin
  657. FHasSection[sec_zipinstall]:=false;
  658. FHasSection[sec_distinstall]:=false;
  659. end;
  660. FHasSection[sec_libs]:=CheckVariable('lib_name');
  661. { Remove unused sections for targets }
  662. SkippedSecs:=0;
  663. if (not CheckTargetVariable('target_units')) then
  664. begin
  665. inc(SkippedSecs);
  666. FHasSection[sec_units]:=false;
  667. end;
  668. if (not CheckTargetVariable('target_programs')) then
  669. begin
  670. inc(SkippedSecs);
  671. FHasSection[sec_exes]:=false;
  672. end;
  673. if (not CheckTargetVariable('target_examples')) then
  674. begin
  675. inc(SkippedSecs);
  676. { example dirs also requires the fpc_examples target, because
  677. it also depends on the all target }
  678. if (not CheckTargetVariable('target_exampledirs')) then
  679. FHasSection[sec_examples]:=false;
  680. end;
  681. if (not CheckTargetVariable('target_loaders')) then
  682. begin
  683. inc(SkippedSecs);
  684. FHasSection[sec_loaders]:=false;
  685. end;
  686. { if all 4 sections are not available we can skip also the
  687. generic compile rules }
  688. if SkippedSecs=4 then
  689. begin
  690. FHasSection[sec_compile]:=false;
  691. if (not CheckTargetVariable('package_name')) and
  692. (not CheckTargetVariable('install_units')) and
  693. (not CheckTargetVariable('install_files')) and
  694. (not CheckTargetVariable('install_createpackagefpc')) then
  695. FHasSection[sec_install]:=false;
  696. { Package.fpc also needs to be cleaned }
  697. if (not CheckTargetVariable('clean_units')) and
  698. (not CheckTargetVariable('clean_files')) and
  699. (not CheckTargetVariable('install_createpackagefpc')) then
  700. FHasSection[sec_clean]:=false;
  701. end;
  702. end;
  703. procedure TMakefileWriter.WriteGenericMakefile;
  704. begin
  705. { Remove unused sections }
  706. OptimizeSections;
  707. { Generate Output }
  708. with FOutput do
  709. begin
  710. { Header }
  711. Add('#');
  712. Add('# Don''t edit, this file is generated by '+TitleDate);
  713. Add('#');
  714. if CheckVariable('default_rule') then
  715. Add('default: '+FInput.GetVariable('default_rule',false))
  716. else
  717. Add('default: all');
  718. { Supported targets by this Makefile }
  719. AddMakefileTargets;
  720. { Add misc defines }
  721. AddIniSection('defines');
  722. { Add automatic detect sections }
  723. AddIniSection('osdetect');
  724. { Forced target }
  725. if CheckVariable('require_target') then
  726. Add('override OS_TARGET='+FInput.GetVariable('require_target',false))
  727. else if CheckVariable('default_target') then
  728. Add('override OS_TARGET_DEFAULT='+FInput.GetVariable('default_target',false));
  729. if CheckVariable('require_cpu') then
  730. Add('override CPU_TARGET='+FInput.GetVariable('require_cpu',false))
  731. else if CheckVariable('default_cpu') then
  732. Add('override CPU_TARGET_DEFAULT='+FInput.GetVariable('default_cpu',false));
  733. { FPC Detection }
  734. AddVariable('default_fpcdir');
  735. AddIniSection('fpcdetect');
  736. AddIniSection('fpcdircheckenv');
  737. AddIniSection('fpcdirdetect');
  738. { Package }
  739. AddVariable('package_name');
  740. AddVariable('package_version');
  741. AddVariable('package_targets');
  742. { LCL rules }
  743. if FInput.UsesLCL then
  744. begin
  745. AddVariable('default_lcldir');
  746. AddVariable('lcl_platform');
  747. AddIniSection('lclrules');
  748. end;
  749. { First add the required packages sections }
  750. // for i:=0 to FInput.RequireList.Count-1 do
  751. // AddCustomSection(FInput.Requirelist[i]);
  752. { prerules section }
  753. if assigned(FInput['prerules']) then
  754. AddStrings(TFPCMakeSection(FInput['prerules']).List);
  755. { Default }
  756. AddVariable('default_dir');
  757. { Targets }
  758. AddTargetVariable('target_dirs');
  759. AddTargetVariable('target_programs');
  760. AddTargetVariable('target_units');
  761. AddTargetVariable('target_implicitunits');
  762. AddTargetVariable('target_loaders');
  763. AddTargetVariable('target_rsts');
  764. AddTargetVariable('target_examples');
  765. AddTargetVariable('target_exampledirs');
  766. { Clean }
  767. AddTargetVariable('clean_units');
  768. AddTargetVariable('clean_files');
  769. { Install }
  770. AddTargetVariable('install_units');
  771. AddTargetVariable('install_files');
  772. AddVariable('install_buildunit');
  773. AddVariable('install_prefix');
  774. AddVariable('install_basedir');
  775. AddVariable('install_datadir');
  776. AddVariable('install_fpcpackage');
  777. AddVariable('install_fpcsubdir');
  778. AddVariable('install_createpackagefpc');
  779. { Dist }
  780. AddVariable('dist_destdir');
  781. AddVariable('dist_zipname');
  782. AddVariable('dist_ziptarget');
  783. { Compiler }
  784. AddTargetVariable('compiler_options');
  785. AddTargetVariable('compiler_version');
  786. AddTargetVariable('compiler_includedir');
  787. AddTargetVariable('compiler_unitdir');
  788. AddTargetVariable('compiler_sourcedir');
  789. AddTargetVariable('compiler_objectdir');
  790. AddTargetVariable('compiler_librarydir');
  791. AddTargetVariable('compiler_targetdir');
  792. AddTargetVariable('compiler_unittargetdir');
  793. { default Dirs and extensions }
  794. AddIniSection('defaultdirs');
  795. if FInput.CheckLibcRequire then
  796. AddIniSection('dirlibc');
  797. AddIniSection('extensions');
  798. { Add default tools }
  799. AddDefaultTools;
  800. { Required packages }
  801. AddVariable('require_packages');
  802. AddRequiredPackages;
  803. { commandline }
  804. AddIniSection('command_begin');
  805. if FInput.CheckLibcRequire then
  806. AddIniSection('command_libc');
  807. AddIniSection('command_end');
  808. { compile }
  809. if FHasSection[sec_loaders] then
  810. AddIniSection('loaderrules');
  811. if FHasSection[sec_units] then
  812. AddIniSection('unitrules');
  813. if FHasSection[sec_exes] then
  814. AddIniSection('exerules');
  815. if FHasSection[sec_rsts] then
  816. AddIniSection('rstrules');
  817. if FHasSection[sec_examples] then
  818. AddIniSection('examplerules');
  819. if FHasSection[sec_compile] then
  820. AddIniSection('compilerules');
  821. if FHasSection[sec_libs] then
  822. AddIniSection('libraryrules');
  823. { install }
  824. if FHasSection[sec_install] then
  825. AddIniSection('installrules');
  826. if FHasSection[sec_distinstall] then
  827. AddIniSection('distinstallrules');
  828. if FHasSection[sec_zipinstall] then
  829. AddIniSection('zipinstallrules');
  830. { clean }
  831. AddIniSection('cleanrules');
  832. { info }
  833. AddIniSection('baseinforules');
  834. if FInput.UsesLCL then
  835. AddIniSection('lclinforules');
  836. AddIniSection('inforules');
  837. { info }
  838. AddIniSection('makefilerules');
  839. { Subdirs }
  840. AddTargetDirs('target_dirs');
  841. AddTargetDirs('target_exampledirs');
  842. { Tools }
  843. AddTools('require_tools');
  844. { Rules }
  845. AddRules;
  846. { Users own rules }
  847. AddIniSection('localmakefile');
  848. AddIniSection('userrules');
  849. if assigned(FInput['rules']) then
  850. AddStrings(TFPCMakeSection(FInput['rules']).List);
  851. end;
  852. { write to disk }
  853. FInput.Verbose(FPCMakeInfo,'Writing Makefile');
  854. Fixtab(FOutput);
  855. FOutput.SaveToFile(FFileName);
  856. end;
  857. end.
  858. {
  859. $Log$
  860. Revision 1.30 2004-04-20 22:59:31 olle
  861. * support for new fpcini section [defines]
  862. Revision 1.29 2004/04/01 12:26:56 olle
  863. + a tool not found is replaced by the fake command __missing_command__, so that make stops, if it tries to run the command.
  864. Revision 1.28 2003/04/25 20:53:33 peter
  865. * target_dir variable generation was not cpu dependent yet
  866. Revision 1.27 2003/04/24 23:21:01 peter
  867. * support different cpu target
  868. Revision 1.26 2003/03/24 10:56:02 marco
  869. * fix recursive zip making that corrupted utilsxxx.zip
  870. Revision 1.25 2002/09/27 06:54:54 pierre
  871. * translate default_cpu/os into CPU/OS_TARGET_DEFAULT
  872. Revision 1.24 2002/09/07 15:40:32 peter
  873. * old logs removed and tabs fixed
  874. Revision 1.23 2002/03/19 19:37:09 peter
  875. * fix source location in zips for packages and demos
  876. Revision 1.22 2002/03/11 19:10:36 peter
  877. * Regenerated with updated fpcmake
  878. Revision 1.21 2002/02/28 17:03:47 pierre
  879. + CHECKDEPEND var to check if packages are up to date
  880. Revision 1.20 2002/01/27 21:42:35 peter
  881. * -r option to process target dirs also
  882. * default changed to build only for current target
  883. * removed auto building of required packages
  884. * removed makefile target because it causes problems with
  885. an internal rule of make
  886. Revision 1.19 2002/01/06 21:50:05 peter
  887. * lcl updates
  888. * small optimizes for package check
  889. }