fpcmwr.pp 33 KB

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