fpcmwr.pp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038
  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,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_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 AddMainPackage(const pack:string);
  69. procedure AddRequiredPackages;
  70. procedure AddTool(const varname,exename,altexename:string);
  71. procedure AddTools(const inivar:string);
  72. procedure AddRules;
  73. procedure AddPhony(const s:string);
  74. procedure WritePhony;
  75. procedure AddTargetDirs(const inivar:string);
  76. function CheckTargetVariable(const inivar:string):boolean;
  77. function CheckVariable(const inivar:string):boolean;
  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. end;
  86. implementation
  87. {$i fpcmake.inc}
  88. type
  89. TMyMemoryStream=class(TMemoryStream)
  90. public
  91. constructor Create(p:pointer;mysize:integer);
  92. end;
  93. {*****************************************************************************
  94. Helpers
  95. *****************************************************************************}
  96. function FixVariable(s:string):string;
  97. var
  98. i : integer;
  99. begin
  100. Result:=UpperCase(s);
  101. i:=pos('.',Result);
  102. if i>0 then
  103. Result[i]:='_';
  104. end;
  105. function VarName(const s:string):string;
  106. var
  107. i,j : longint;
  108. begin
  109. i:=0;
  110. result:=s;
  111. while i<length(result) do
  112. begin
  113. inc(i);
  114. case result[i] of
  115. '{' :
  116. begin
  117. { this are pkgs which are hold the dirs between the accolades }
  118. j:=PosIdx('}',result,i);
  119. if j>0 then
  120. Delete(result,i,j-i+1)
  121. else
  122. Delete(result,i,1);
  123. dec(i);
  124. end;
  125. '$','(',')' :
  126. begin
  127. Delete(result,i,1);
  128. dec(i);
  129. end;
  130. 'a'..'z' :
  131. result[i]:=chr(ord(result[i])-32);
  132. end;
  133. end;
  134. end;
  135. procedure FixTab(sl:TStringList);
  136. var
  137. i,j,k : integer;
  138. s,s2 : string;
  139. begin
  140. i:=0;
  141. while (i<sl.Count) do
  142. begin
  143. if (sl[i]<>'') and (sl[i][1] in [' ',#9]) then
  144. begin
  145. s:=sl[i];
  146. k:=0;
  147. j:=0;
  148. repeat
  149. inc(j);
  150. case s[j] of
  151. ' ' :
  152. inc(k);
  153. #9 :
  154. k:=(k+7) and not(7);
  155. else
  156. break;
  157. end;
  158. until (j=length(s));
  159. if k>7 then
  160. begin
  161. s2:='';
  162. Delete(s,1,j-1);
  163. while (k>7) do
  164. begin
  165. s2:=s2+#9;
  166. dec(k,8);
  167. end;
  168. while (k>0) do
  169. begin
  170. s2:=s2+' ';
  171. dec(k);
  172. end;
  173. sl[i]:=s2+s;
  174. end;
  175. end;
  176. inc(i);
  177. end;
  178. end;
  179. {*****************************************************************************
  180. TMyMemoryStream
  181. *****************************************************************************}
  182. constructor TMyMemoryStream.Create(p:pointer;mysize:integer);
  183. begin
  184. inherited Create;
  185. SetPointer(p,mysize);
  186. end;
  187. {*****************************************************************************
  188. TMakefileWriter
  189. *****************************************************************************}
  190. constructor TMakefileWriter.Create(AFPCMake:TFPCMake;const AFileName:string);
  191. begin
  192. FInput:=AFPCMake;
  193. FFileName:=AFileName;
  194. FOutput:=TStringList.Create;
  195. FPhony:='';
  196. FillChar(FHasSection,sizeof(FHasSection),1);
  197. LoadFPCMakeIni;
  198. end;
  199. destructor TMakefileWriter.Destroy;
  200. begin
  201. FOutput.Free;
  202. FIni.Free;
  203. end;
  204. procedure TMakefileWriter.LoadFPCMakeIni;
  205. var
  206. IniStream : TStream;
  207. begin
  208. try
  209. IniStream:=TMyMemoryStream.Create(@fpcmakeini,sizeof(fpcmakeini));
  210. FIni:=TFPCMake.CreateFromStream(IniStream,'fpcmake.ini');
  211. { Leave the '#' comments in the output }
  212. // FIni.CommentChars:=[';'];
  213. FIni.LoadSections;
  214. finally
  215. IniStream.Destroy;
  216. end;
  217. end;
  218. procedure TMakefileWriter.AddIniSection(const s:string);
  219. var
  220. Sec : TFPCMakeSection;
  221. begin
  222. Sec:=TFPCMakeSection(FIni[s]);
  223. if assigned(Sec) then
  224. FOutput.AddStrings(Sec.List)
  225. else
  226. Raise Exception.Create(Format('Section "%s" doesn''t exists in fpcmake.ini',[s]));
  227. end;
  228. procedure TMakefileWriter.AddCustomSection(const s:string);
  229. var
  230. Sec : TFPCMakeSection;
  231. begin
  232. Sec:=TFPCMakeSection(FInput[s]);
  233. if assigned(Sec) then
  234. begin
  235. Sec.BuildMakefile;
  236. FOutput.AddStrings(Sec.List);
  237. end;
  238. end;
  239. function TMakefileWriter.CheckTargetVariable(const inivar:string):boolean;
  240. var
  241. t : TTarget;
  242. c : TCpu;
  243. begin
  244. result:=false;
  245. if FInput.GetVariable(IniVar,false)<>'' then
  246. begin
  247. result:=true;
  248. exit;
  249. end;
  250. for t:=low(TTarget) to high(TTarget) do
  251. if (t in FInput.IncludeTargets) and
  252. (FInput.GetVariable(IniVar+TargetSuffix[t],false)<>'') then
  253. begin
  254. result:=true;
  255. exit;
  256. end;
  257. for c:=low(TCpu) to high(TCpu) do
  258. if (c in FInput.IncludeCpus) and
  259. (FInput.GetVariable(IniVar+CpuSuffix[c],false)<>'') then
  260. begin
  261. result:=true;
  262. exit;
  263. end;
  264. end;
  265. function TMakefileWriter.CheckVariable(const inivar:string):boolean;
  266. begin
  267. Result:=(FInput.GetVariable(IniVar,false)<>'');
  268. end;
  269. procedure TMakefileWriter.AddTargetVariable(const inivar:string);
  270. var
  271. s : string;
  272. T : TTarget;
  273. C : TCpu;
  274. firsttarget,
  275. firstcpu : boolean;
  276. begin
  277. s:=FInput.GetVariable(IniVar,false);
  278. if s<>'' then
  279. FOutput.Add('override '+FixVariable(IniVar)+'+='+s);
  280. for t:=low(TTarget) to high(TTarget) do
  281. if t in FInput.IncludeTargets then
  282. begin
  283. firsttarget:=true;
  284. firstcpu:=true;
  285. s:=FInput.GetVariable(IniVar+TargetSuffix[t],false);
  286. if s<>'' then
  287. begin
  288. if firsttarget then
  289. begin
  290. firsttarget:=false;
  291. FOutput.Add('ifeq ($(OS_TARGET),'+TargetStr[t]+')');
  292. end;
  293. FOutput.Add('override '+FixVariable(IniVar)+'+='+s);
  294. end;
  295. for c:=low(TCpu) to high(TCpu) do
  296. if (TargetCpuPossible[t,c]) and (c in FInput.IncludeCpus) then
  297. begin
  298. s:=FInput.GetVariable(IniVar+TargetSuffix[t]+CpuSuffix[c],false);
  299. if s<>'' then
  300. begin
  301. if firsttarget then
  302. begin
  303. firsttarget:=false;
  304. FOutput.Add('ifeq ($(OS_TARGET),'+TargetStr[t]+')');
  305. end;
  306. if firstcpu then
  307. begin
  308. firstcpu:=false;
  309. FOutput.Add('ifeq ($(CPU_TARGET),'+CpuStr[c]+')');
  310. end;
  311. FOutput.Add('override '+FixVariable(IniVar)+'+='+s);
  312. end;
  313. end;
  314. if not firstcpu then
  315. FOutput.Add('endif');
  316. if not firsttarget then
  317. FOutput.Add('endif');
  318. end;
  319. for c:=low(TCpu) to high(TCpu) do
  320. if (c in FInput.IncludeCpus) then
  321. begin
  322. s:=FInput.GetVariable(IniVar+CpuSuffix[c],false);
  323. if s<>'' then
  324. begin
  325. FOutput.Add('ifeq ($(CPU_TARGET),'+CpuStr[c]+')');
  326. FOutput.Add('override '+FixVariable(IniVar)+'+='+s);
  327. FOutput.Add('endif');
  328. end;
  329. end;
  330. end;
  331. procedure TMakefileWriter.AddVariable(const inivar:string);
  332. var
  333. s : string;
  334. begin
  335. s:=FInput.GetVariable(IniVar,false);
  336. if s<>'' then
  337. FOutput.Add('override '+FixVariable(IniVar)+'='+s)
  338. end;
  339. function TMakefileWriter.AddTargetDefines(const inivar,prefix:string):string;
  340. procedure addtokens(s:string);
  341. var
  342. name : string;
  343. k1,k2 : integer;
  344. begin
  345. repeat
  346. Name:=GetToken(s,' ');
  347. if Name='' then
  348. break;
  349. { Remove (..) }
  350. k1:=pos('(',name);
  351. if k1>0 then
  352. begin
  353. k2:=PosIdx(')',name,k1);
  354. if k2=0 then
  355. k2:=length(name)+1;
  356. Delete(Name,k1,k2);
  357. end;
  358. FOutput.Add(prefix+VarName(name)+'=1');
  359. { add to the list of dirs without duplicates }
  360. AddTokenNoDup(result,name,' ');
  361. until false;
  362. end;
  363. var
  364. s : string;
  365. T : TTarget;
  366. c : TCpu;
  367. firsttarget,
  368. firstcpu : boolean;
  369. begin
  370. result:='';
  371. s:=FInput.GetVariable(IniVar,false);
  372. addtokens(s);
  373. for t:=low(TTarget) to high(TTarget) do
  374. if t in FInput.IncludeTargets then
  375. begin
  376. firsttarget:=true;
  377. firstcpu:=true;
  378. s:=FInput.GetVariable(IniVar+TargetSuffix[t],false);
  379. if s<>'' then
  380. begin
  381. if firsttarget then
  382. begin
  383. firsttarget:=false;
  384. FOutput.Add('ifeq ($(OS_TARGET),'+TargetStr[t]+')');
  385. end;
  386. addtokens(s);
  387. end;
  388. for c:=low(TCpu) to high(TCpu) do
  389. if (TargetCpuPossible[t,c]) and (c in FInput.IncludeCpus) then
  390. begin
  391. s:=FInput.GetVariable(IniVar+TargetSuffix[t]+CpuSuffix[c],false);
  392. if s<>'' then
  393. begin
  394. if firsttarget then
  395. begin
  396. firsttarget:=false;
  397. FOutput.Add('ifeq ($(OS_TARGET),'+TargetStr[t]+')');
  398. end;
  399. if firstcpu then
  400. begin
  401. firstcpu:=false;
  402. FOutput.Add('ifeq ($(CPU_TARGET),'+CpuStr[c]+')');
  403. end;
  404. addtokens(s);
  405. end;
  406. end;
  407. if not firstcpu then
  408. FOutput.Add('endif');
  409. if not firsttarget then
  410. FOutput.Add('endif');
  411. end;
  412. for c:=low(TCpu) to high(TCpu) do
  413. if (c in FInput.IncludeCpus) then
  414. begin
  415. s:=FInput.GetVariable(IniVar+CpuSuffix[c],false);
  416. if s<>'' then
  417. begin
  418. FOutput.Add('ifeq ($(CPU_TARGET),'+CpuStr[c]+')');
  419. addtokens(s);
  420. FOutput.Add('endif');
  421. end;
  422. end;
  423. end;
  424. procedure TMakefileWriter.AddTool(const varname,exename,altexename:string);
  425. begin
  426. with FOutput do
  427. begin
  428. Add('ifndef '+varname);
  429. Add(varname+':=$(strip $(wildcard $(addsuffix /'+exename+'$(SRCEXEEXT),$(SEARCHPATH))))');
  430. if altexename<>'' then
  431. begin
  432. Add('ifeq ($('+varname+'),)');
  433. Add(varname+':=$(strip $(wildcard $(addsuffix /'+altexename+'$(SRCEXEEXT),$(SEARCHPATH))))');
  434. end;
  435. Add('ifeq ($('+varname+'),)');
  436. Add(varname+'= __missing_command_'+varname); {This is to be shure make stops,
  437. if the command is not found. Otherwise if the command was set to the
  438. empty string, options to the command would be interpreted as command,
  439. and because options is preceeded by a "-", make will ignore the error
  440. that the command is not found.}
  441. Add('else');
  442. Add(varname+':=$(firstword $('+varname+'))');
  443. Add('endif');
  444. if altexename<>'' then
  445. begin
  446. Add('else');
  447. Add(varname+':=$(firstword $('+varname+'))');
  448. Add('endif');
  449. end;
  450. Add('endif');
  451. Add('export '+varname);
  452. end;
  453. end;
  454. procedure TMakefileWriter.AddTools(const inivar:string);
  455. var
  456. hs,tool : string;
  457. begin
  458. hs:=FInput.GetVariable(inivar,false);
  459. repeat
  460. Tool:=GetToken(hs,' ');
  461. if Tool='' then
  462. break;
  463. AddTool(FixVariable(Tool),Tool,'');
  464. until false;
  465. end;
  466. procedure TMakefileWriter.AddRules;
  467. procedure AddRule(rule:trules);
  468. var
  469. i : integer;
  470. hs : string;
  471. Sec : TFPCMakeSection;
  472. Rules : TStringList;
  473. begin
  474. Sec:=TFPCMakeSection(FInput['rules']);
  475. if assigned(Sec) then
  476. begin
  477. Rules:=Sec.List;
  478. for i:=0 to Rules.Count-1 do
  479. begin
  480. if (length(rules[i])>length(rule2str[rule])) and
  481. (rules[i][1]=rule2str[rule][1]) and
  482. ((rules[i][length(rule2str[rule])+1]=':') or
  483. ((length(rules[i])>length(rule2str[rule])+1) and
  484. (rules[i][length(rule2str[rule])+2]=':'))) and
  485. (Copy(rules[i],1,length(rule2str[rule]))=rule2str[rule]) then
  486. exit;
  487. end;
  488. end;
  489. hs:='';
  490. if FHasSection[Rule2Sec[rule]] then
  491. hs:=hs+' fpc_'+rule2str[rule];
  492. { include target dirs, but not for info and targets that
  493. call other targets with a only extra settings, if the
  494. section was not included, then still process the targets }
  495. if CheckTargetVariable('target_dirs') and
  496. (not(rule in [r_info,r_shared,r_smart,r_debug,r_release,r_zipdistinstall,r_distinstall]) or
  497. not FHasSection[Rule2Sec[rule]]) then
  498. begin
  499. if CheckVariable('default_dir') then
  500. hs:=hs+' $(addsuffix _'+rule2str[rule]+',$(DEFAULT_DIR))'
  501. else
  502. if not(rule in [r_sourceinstall,r_zipinstall,r_zipsourceinstall,
  503. r_makefiles]) or
  504. not(CheckVariable('package_name')) then
  505. hs:=hs+' $(addsuffix _'+rule2str[rule]+',$(TARGET_DIRS))';
  506. end;
  507. { include cleaning of example dirs }
  508. if (rule=r_clean) and
  509. CheckTargetVariable('target_exampledirs') then
  510. hs:=hs+' $(addsuffix _'+rule2str[rule]+',$(TARGET_EXAMPLEDIRS))';
  511. { Add the rule }
  512. AddPhony(Rule2Str[Rule]);
  513. FOutput.Add(rule2str[rule]+':'+hs);
  514. end;
  515. var
  516. rule : trules;
  517. begin
  518. for rule:=low(trules) to high(trules) do
  519. AddRule(rule);
  520. WritePhony;
  521. end;
  522. procedure TMakefileWriter.AddPhony(const s:string);
  523. begin
  524. FPhony:=FPhony+' '+s;
  525. end;
  526. procedure TMakefileWriter.WritePhony;
  527. begin
  528. if FPhony<>'' then
  529. begin
  530. FOutput.Add('.PHONY:'+FPhony);
  531. FPhony:='';
  532. end;
  533. end;
  534. procedure TMakefileWriter.AddTargetDirs(const inivar:string);
  535. procedure AddTargetDir(const s,defpref:string);
  536. var
  537. j : trules;
  538. begin
  539. FOutput.Add('ifdef '+defpref+VarName(s));
  540. for j:=low(trules) to high(trules) do
  541. begin
  542. FOutput.Add(s+'_'+rule2str[j]+':');
  543. FOutput.Add(#9+'$(MAKE) -C '+s+' '+rule2str[j]);
  544. AddPhony(s+'_'+rule2str[j]);
  545. end;
  546. FOutput.Add(s+':');
  547. FOutput.Add(#9+'$(MAKE) -C '+s+' all');
  548. AddPhony(s);
  549. WritePhony;
  550. FOutput.Add('endif');
  551. end;
  552. var
  553. hs,dir : string;
  554. prefix : string;
  555. begin
  556. prefix:=FixVariable(inivar)+'_';
  557. hs:=AddTargetDefines(inivar,prefix);
  558. repeat
  559. Dir:=GetToken(hs,' ');
  560. if Dir='' then
  561. break;
  562. AddTargetDir(Dir,prefix);
  563. until false;
  564. end;
  565. procedure TMakefileWriter.AddMainPackage(const pack:string);
  566. var
  567. packdirvar : string;
  568. begin
  569. { create needed variables }
  570. packdirvar:='PACKAGEDIR_MAIN';
  571. { Search packagedir by looking for Makefile.fpc }
  572. FOutput.Add(packdirvar+':=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /'+pack+'/Makefile.fpc,$(PACKAGESDIR))))))');
  573. end;
  574. procedure TMakefileWriter.AddRequiredPackages;
  575. procedure AddPackage(const pack,prefix:string);
  576. var
  577. packdirvar,unitdirvar : string;
  578. begin
  579. FOutput.Add('ifdef '+Prefix+VarName(pack));
  580. { create needed variables }
  581. packdirvar:='PACKAGEDIR_'+VarName(pack);
  582. unitdirvar:='UNITDIR_'+VarName(pack);
  583. { Search packagedir by looking for Makefile.fpc }
  584. FOutput.Add(packdirvar+':=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /'+pack+'/Makefile.fpc,$(PACKAGESDIR))))))');
  585. FOutput.Add('ifneq ($('+packdirvar+'),)');
  586. { Create unit dir, check if os dependent dir exists }
  587. FOutput.Add('ifneq ($(wildcard $('+packdirvar+')/units/$(FULL_TARGET)),)');
  588. FOutput.Add(unitdirvar+'=$('+packdirvar+')/units/$(FULL_TARGET)');
  589. FOutput.Add('else');
  590. FOutput.Add(unitdirvar+'=$('+packdirvar+')');
  591. FOutput.Add('endif');
  592. FOutput.Add('ifdef CHECKDEPEND');
  593. FOutput.Add('$('+packdirvar+')/$(FPCMADE):');
  594. FOutput.Add(#9'$(MAKE) -C $('+packdirvar+') $(FPCMADE)');
  595. FOutput.Add('override ALLDEPENDENCIES+=$('+packdirvar+')/$(FPCMADE)');
  596. FOutput.Add('endif');
  597. { Package dir doesn't exists, check unit dir }
  598. FOutput.Add('else');
  599. FOutput.Add(packdirvar+'=');
  600. FOutput.Add(unitdirvar+':=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /'+pack+'/Package.fpc,$(UNITSDIR)))))');
  601. FOutput.Add('ifneq ($('+unitdirvar+'),)');
  602. FOutput.Add(unitdirvar+':=$(firstword $('+unitdirvar+'))');
  603. FOutput.Add('else');
  604. FOutput.Add(unitdirvar+'=');
  605. FOutput.Add('endif');
  606. FOutput.Add('endif');
  607. { Add Unit dir to the command line -Fu }
  608. FOutput.Add('ifdef '+unitdirvar);
  609. FOutput.Add('override COMPILER_UNITDIR+=$('+unitdirvar+')');
  610. FOutput.Add('endif');
  611. { endif for package }
  612. FOutput.Add('endif');
  613. end;
  614. var
  615. i : integer;
  616. reqs,req,prefix : string;
  617. t : Ttarget;
  618. c : TCpu;
  619. sl : TStringList;
  620. begin
  621. prefix:='REQUIRE_PACKAGES_';
  622. reqs:='';
  623. { Add target defines }
  624. for t:=low(ttarget) to high(ttarget) do
  625. if t in FInput.IncludeTargets then
  626. begin
  627. for c:=low(tcpu) to high(tcpu) do
  628. if (TargetCpuPossible[t,c]) and (c in FInput.IncludeCpus) then
  629. begin
  630. sl:=FInput.GetTargetRequires(t,c);
  631. { show info }
  632. FInput.Verbose(FPCMakeInfo,TargetStr[t]+'-'+CpuStr[c]+' requires: '+sl.CommaText);
  633. if sl.count>0 then
  634. begin
  635. FOutput.Add('ifeq ($(OS_TARGET),'+TargetStr[t]+')');
  636. FOutput.Add('ifeq ($(CPU_TARGET),'+CpuStr[c]+')');
  637. for i:=0 to sl.count-1 do
  638. begin
  639. FOutput.Add(prefix+VarName(sl[i])+'=1');
  640. AddTokenNoDup(reqs,sl[i],' ');
  641. end;
  642. FOutput.Add('endif');
  643. FOutput.Add('endif');
  644. end;
  645. sl.Free;
  646. end;
  647. end;
  648. { Add all require packages }
  649. repeat
  650. req:=GetToken(reqs,' ');
  651. if Req='' then
  652. break;
  653. AddPackage(req,prefix);
  654. until false;
  655. WritePhony;
  656. end;
  657. procedure TMakefileWriter.AddDefaultTools;
  658. begin
  659. AddTool('ECHO','gecho','echo');
  660. AddTool('DATE','gdate','date');
  661. AddTool('GINSTALL','ginstall','install');
  662. AddTool('CPPROG','cp','');
  663. AddTool('RMPROG','rm','');
  664. AddTool('MVPROG','mv','');
  665. AddTool('MKDIRPROG','gmkdir','mkdir');
  666. AddIniSection('shelltools');
  667. AddTool('PPUMOVE','ppumove','');
  668. AddTool('FPCMAKE','fpcmake','');
  669. AddTool('ZIPPROG','zip','');
  670. AddTool('TARPROG','tar','');
  671. AddIniSection('defaulttools');
  672. end;
  673. procedure TMakefileWriter.AddMakefileTargets;
  674. var
  675. s : string;
  676. t : Ttarget;
  677. begin
  678. s:='';
  679. for t:=low(ttarget) to high(ttarget) do
  680. if t in FInput.IncludeTargets then
  681. begin
  682. AddToken(s,TargetStr[t],' ');
  683. end;
  684. FOutput.Add('MAKEFILETARGETS='+s);
  685. end;
  686. procedure TMakefileWriter.OptimizeSections;
  687. var
  688. SkippedSecs :integer;
  689. begin
  690. { Turn some sections off, depending if files are
  691. provided }
  692. if not FInput.IsPackage then
  693. begin
  694. FHasSection[sec_zipinstall]:=false;
  695. FHasSection[sec_distinstall]:=false;
  696. end;
  697. FHasSection[sec_libs]:=CheckVariable('lib_name');
  698. { Remove unused sections for targets }
  699. SkippedSecs:=0;
  700. if (not CheckTargetVariable('target_units')) then
  701. begin
  702. inc(SkippedSecs);
  703. FHasSection[sec_units]:=false;
  704. end;
  705. if (not CheckTargetVariable('target_programs')) then
  706. begin
  707. inc(SkippedSecs);
  708. FHasSection[sec_exes]:=false;
  709. end;
  710. if (not CheckTargetVariable('target_examples')) then
  711. begin
  712. inc(SkippedSecs);
  713. { example dirs also requires the fpc_examples target, because
  714. it also depends on the all target }
  715. if (not CheckTargetVariable('target_exampledirs')) then
  716. FHasSection[sec_examples]:=false;
  717. end;
  718. if (not CheckTargetVariable('target_loaders')) then
  719. begin
  720. inc(SkippedSecs);
  721. FHasSection[sec_loaders]:=false;
  722. end;
  723. { if all 4 sections are not available we can skip also the
  724. generic compile rules }
  725. if SkippedSecs=4 then
  726. begin
  727. FHasSection[sec_compile]:=false;
  728. if (not CheckTargetVariable('package_name')) and
  729. (not CheckTargetVariable('install_units')) and
  730. (not CheckTargetVariable('install_files')) and
  731. (not CheckTargetVariable('install_createpackagefpc')) then
  732. FHasSection[sec_install]:=false;
  733. { Package.fpc also needs to be cleaned }
  734. if (not CheckTargetVariable('clean_units')) and
  735. (not CheckTargetVariable('clean_files')) and
  736. (not CheckTargetVariable('install_createpackagefpc')) then
  737. FHasSection[sec_clean]:=false;
  738. end;
  739. end;
  740. procedure TMakefileWriter.WriteGenericMakefile;
  741. begin
  742. { Remove unused sections }
  743. OptimizeSections;
  744. { Generate Output }
  745. with FOutput do
  746. begin
  747. { Header }
  748. Add('#');
  749. Add('# Don''t edit, this file is generated by '+TitleDate);
  750. Add('#');
  751. if CheckVariable('default_rule') then
  752. Add('default: '+FInput.GetVariable('default_rule',false))
  753. else
  754. Add('default: all');
  755. { Supported targets by this Makefile }
  756. AddMakefileTargets;
  757. { Add misc defines }
  758. AddIniSection('defines');
  759. { Add automatic detect sections }
  760. AddIniSection('osdetect');
  761. { Forced target }
  762. if CheckVariable('require_target') then
  763. Add('override OS_TARGET='+FInput.GetVariable('require_target',false))
  764. else if CheckVariable('default_target') then
  765. Add('override OS_TARGET_DEFAULT='+FInput.GetVariable('default_target',false));
  766. if CheckVariable('require_cpu') then
  767. Add('override CPU_TARGET='+FInput.GetVariable('require_cpu',false))
  768. else if CheckVariable('default_cpu') then
  769. Add('override CPU_TARGET_DEFAULT='+FInput.GetVariable('default_cpu',false));
  770. { FPC Detection }
  771. AddVariable('default_fpcdir');
  772. AddIniSection('fpcdetect');
  773. AddIniSection('fpcdircheckenv');
  774. AddIniSection('fpcdirdetect');
  775. { Package }
  776. AddVariable('package_name');
  777. AddVariable('package_version');
  778. AddVariable('package_targets');
  779. { Directory of main package }
  780. if CheckVariable('package_main') then
  781. AddMainPackage(FInput.GetVariable('package_main',false));
  782. { LCL rules }
  783. if FInput.UsesLCL then
  784. begin
  785. AddVariable('default_lcldir');
  786. AddVariable('lcl_platform');
  787. AddIniSection('lclrules');
  788. end;
  789. { First add the required packages sections }
  790. // for i:=0 to FInput.RequireList.Count-1 do
  791. // AddCustomSection(FInput.Requirelist[i]);
  792. { prerules section }
  793. if assigned(FInput['prerules']) then
  794. AddStrings(TFPCMakeSection(FInput['prerules']).List);
  795. { Default }
  796. AddVariable('default_dir');
  797. { Targets }
  798. AddTargetVariable('target_dirs');
  799. AddTargetVariable('target_programs');
  800. AddTargetVariable('target_units');
  801. AddTargetVariable('target_implicitunits');
  802. AddTargetVariable('target_loaders');
  803. AddTargetVariable('target_rsts');
  804. AddTargetVariable('target_examples');
  805. AddTargetVariable('target_exampledirs');
  806. { Clean }
  807. AddTargetVariable('clean_units');
  808. AddTargetVariable('clean_files');
  809. { Install }
  810. AddTargetVariable('install_units');
  811. AddTargetVariable('install_files');
  812. AddVariable('install_buildunit');
  813. AddVariable('install_prefix');
  814. AddVariable('install_basedir');
  815. AddVariable('install_datadir');
  816. AddVariable('install_fpcpackage');
  817. AddVariable('install_fpcsubdir');
  818. AddVariable('install_createpackagefpc');
  819. { Dist }
  820. AddVariable('dist_destdir');
  821. AddVariable('dist_zipname');
  822. AddVariable('dist_ziptarget');
  823. { Compiler }
  824. AddTargetVariable('compiler_options');
  825. AddTargetVariable('compiler_version');
  826. AddTargetVariable('compiler_includedir');
  827. AddTargetVariable('compiler_unitdir');
  828. AddTargetVariable('compiler_sourcedir');
  829. AddTargetVariable('compiler_objectdir');
  830. AddTargetVariable('compiler_librarydir');
  831. AddTargetVariable('compiler_targetdir');
  832. AddTargetVariable('compiler_unittargetdir');
  833. { default Dirs and extensions }
  834. AddIniSection('defaultdirs');
  835. if FInput.CheckLibcRequire then
  836. AddIniSection('dirlibc');
  837. AddIniSection('extensions');
  838. { Add default tools }
  839. AddDefaultTools;
  840. { Required packages }
  841. AddVariable('require_packages');
  842. AddRequiredPackages;
  843. { commandline }
  844. AddIniSection('command_begin');
  845. if FInput.CheckLibcRequire then
  846. AddIniSection('command_libc');
  847. AddIniSection('command_end');
  848. { compile }
  849. if FHasSection[sec_loaders] then
  850. AddIniSection('loaderrules');
  851. if FHasSection[sec_units] then
  852. AddIniSection('unitrules');
  853. if FHasSection[sec_exes] then
  854. AddIniSection('exerules');
  855. if FHasSection[sec_rsts] then
  856. AddIniSection('rstrules');
  857. if FHasSection[sec_examples] then
  858. AddIniSection('examplerules');
  859. if FHasSection[sec_compile] then
  860. AddIniSection('compilerules');
  861. if FHasSection[sec_libs] then
  862. AddIniSection('libraryrules');
  863. { install }
  864. if FHasSection[sec_install] then
  865. AddIniSection('installrules');
  866. if FHasSection[sec_distinstall] then
  867. AddIniSection('distinstallrules');
  868. if FHasSection[sec_zipinstall] then
  869. AddIniSection('zipinstallrules');
  870. { clean }
  871. AddIniSection('cleanrules');
  872. { info }
  873. AddIniSection('baseinforules');
  874. if FInput.UsesLCL then
  875. AddIniSection('lclinforules');
  876. AddIniSection('inforules');
  877. { info }
  878. AddIniSection('makefilerules');
  879. { Subdirs }
  880. AddTargetDirs('target_dirs');
  881. AddTargetDirs('target_exampledirs');
  882. { Tools }
  883. AddTools('require_tools');
  884. { Rules }
  885. AddRules;
  886. { Users own rules }
  887. AddIniSection('localmakefile');
  888. AddIniSection('userrules');
  889. if assigned(FInput['rules']) then
  890. AddStrings(TFPCMakeSection(FInput['rules']).List);
  891. end;
  892. { write to disk }
  893. FInput.Verbose(FPCMakeInfo,'Writing Makefile');
  894. Fixtab(FOutput);
  895. FOutput.SaveToFile(FFileName);
  896. end;
  897. end.
  898. {
  899. $Log$
  900. Revision 1.35 2004-11-01 17:17:33 olle
  901. * __missing_command will now have the name of the missing command appended.
  902. Revision 1.34 2004/10/30 12:36:48 peter
  903. * units are now created in separate directory units/cpu-os/
  904. * distclean uses cleanall rule and removes units dir
  905. * cross compile support fixed, it is now possible to cycle a ppcsparc
  906. without deleting ppc386
  907. * bintutilsperfix defaults to cpu-os-
  908. Revision 1.33 2004/08/01 08:12:07 michael
  909. + Patch from Vincent Snijders to fix CPU-specific installs
  910. Revision 1.32 2004/07/12 06:42:52 michael
  911. * Patch from peter to fix writing of target dir rules for cpu specific dirs
  912. Revision 1.31 2004/07/11 18:58:19 peter
  913. * support varaiable_cpu
  914. Revision 1.30 2004/04/20 22:59:31 olle
  915. * support for new fpcini section [defines]
  916. Revision 1.29 2004/04/01 12:26:56 olle
  917. + a tool not found is replaced by the fake command __missing_command__, so that make stops, if it tries to run the command.
  918. Revision 1.28 2003/04/25 20:53:33 peter
  919. * target_dir variable generation was not cpu dependent yet
  920. Revision 1.27 2003/04/24 23:21:01 peter
  921. * support different cpu target
  922. Revision 1.26 2003/03/24 10:56:02 marco
  923. * fix recursive zip making that corrupted utilsxxx.zip
  924. Revision 1.25 2002/09/27 06:54:54 pierre
  925. * translate default_cpu/os into CPU/OS_TARGET_DEFAULT
  926. Revision 1.24 2002/09/07 15:40:32 peter
  927. * old logs removed and tabs fixed
  928. Revision 1.23 2002/03/19 19:37:09 peter
  929. * fix source location in zips for packages and demos
  930. Revision 1.22 2002/03/11 19:10:36 peter
  931. * Regenerated with updated fpcmake
  932. Revision 1.21 2002/02/28 17:03:47 pierre
  933. + CHECKDEPEND var to check if packages are up to date
  934. Revision 1.20 2002/01/27 21:42:35 peter
  935. * -r option to process target dirs also
  936. * default changed to build only for current target
  937. * removed auto building of required packages
  938. * removed makefile target because it causes problems with
  939. an internal rule of make
  940. Revision 1.19 2002/01/06 21:50:05 peter
  941. * lcl updates
  942. * small optimizes for package check
  943. }