fpcmmain.pp 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520
  1. {
  2. $Id$
  3. Copyright (c) 2001 by Peter Vreman
  4. FPCMake - Main module
  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 fpcmmain;
  14. interface
  15. uses
  16. dos,
  17. {$ifdef Unix}
  18. {$ifdef VER1_0}
  19. {$ifdef linux}
  20. {$ifndef BSD}
  21. linux,
  22. {$endif}
  23. {$endif}
  24. {$ifdef BSD}
  25. Linux,
  26. {$endif}
  27. {$else}
  28. unix,
  29. {$endif}
  30. {$endif}
  31. sysutils,classes,
  32. fpcmdic;
  33. {$ifdef BEOS}
  34. {$define NO_UNIX_UNIT}
  35. {$endif}
  36. {$ifdef SUNOS}
  37. {$define NO_UNIX_UNIT}
  38. {$endif}
  39. {$ifdef QNX}
  40. {$define NO_UNIX_UNIT}
  41. {$endif}
  42. const
  43. Version='1.1';
  44. Title='FPCMake Version '+Version;
  45. TitleDate=Title+' ['+{$ifdef fpc}{$i %DATE}{$else}'n/a'{$endif}+']';
  46. type
  47. TTarget=(
  48. t_linux,t_go32v2,t_win32,t_os2,t_freebsd,t_beos,t_netbsd,
  49. t_amiga,t_atari, t_sunos, t_qnx, t_netware, t_openbsd,t_wdosx
  50. );
  51. TTargetSet=set of TTarget;
  52. const
  53. TargetStr : array[TTarget] of string=(
  54. 'linux','go32v2','win32','os2','freebsd','beos','netbsd',
  55. 'amiga','atari','sunos', 'qnx', 'netware','openbsd','wdosx'
  56. );
  57. TargetSuffix : array[TTarget] of string=(
  58. '_linux','_go32v2','_win32','_os2','_freebsd','_beos','_netbsd',
  59. '_amiga','_atari','_sunos', '_qnx', '_netware','_openbsd','_wdosx'
  60. );
  61. type
  62. TKeyValueItem = class(TDictionaryItem)
  63. private
  64. FValue : string;
  65. public
  66. constructor Create(const k,v:string);
  67. property Value:string read FValue write FValue;
  68. end;
  69. TKeyValue = class(TDictionary)
  70. private
  71. function GetKey(const k:string):string;
  72. public
  73. procedure Add(const k,v:String);
  74. property Key[const s:string]:string read GetKey write Add;default;
  75. end;
  76. TFPCMakeSection = class(TDictionaryItem)
  77. private
  78. FList : TStringList;
  79. FDictionary : TKeyValue;
  80. procedure BuildIniDic(p:TDictionaryItem);
  81. procedure BuildMakefileDic(p:TDictionaryItem);
  82. function GetKey(const k:string):string;
  83. public
  84. constructor Create(const n:string);
  85. constructor CreateKeyValue(const n:string);
  86. destructor Destroy;override;
  87. procedure AddLine(const s:string);
  88. procedure AddKey(const k,v:string);
  89. procedure Clear;
  90. procedure ParseIni;
  91. procedure BuildIni;
  92. procedure BuildMakefile;
  93. property Key[const s:string]:string read GetKey;default;
  94. property List:TStringList read FList;
  95. property Dictionary:TKeyValue read FDictionary;
  96. end;
  97. TTargetRequireList = array[ttarget] of TStringList;
  98. TFPCMakeVerbose = (FPCMakeError, FPCMakeInfo, FPCMakeDebug);
  99. TFPCMake = class
  100. private
  101. FStream : TStream;
  102. FFileName : string;
  103. FCommentChars : TSysCharSet;
  104. FEmptyLines : boolean;
  105. FSections : TDictionary;
  106. FPackageSec,
  107. FExportSec : TFPCMakeSection;
  108. FUsesLCL,
  109. FIsPackage : boolean;
  110. FPackageName,
  111. FPackageVersion,
  112. FPackageTargets : string;
  113. FRequireList : TTargetRequireList;
  114. FVariables : TKeyValue;
  115. FIncludeTargets : TTargetSet;
  116. procedure Init;
  117. procedure ParseSec(p:TDictionaryItem);
  118. procedure PrintSec(p:TDictionaryItem);
  119. procedure PrintDic(p:TDictionaryItem);
  120. function GetSec(const AName:string):TDictionaryItem;
  121. procedure LoadRequiredPackage(t:TTarget;const ReqName,ReqVersion:string);
  122. procedure LoadRequiredDir(t:TTarget;const MainPack,currdir,subdir:string);
  123. procedure LoadRequires(t:Ttarget;FromFPCMake:TFPCMake);
  124. function CopySection(Sec:TFPCMakeSection;Secname:string):TFPCMakeSection;
  125. protected
  126. VerboseIdent : string;
  127. public
  128. constructor Create(const AFileName:string);
  129. constructor CreateFromStream(s:TStream;const AFileName:string);
  130. destructor Destroy;override;
  131. procedure Verbose(lvl:TFPCMakeVerbose;const s:string);virtual;
  132. procedure SetTargets(const s:string);
  133. procedure LoadSections;
  134. procedure LoadMakefileFPC;
  135. procedure LoadPackageSection;
  136. procedure LoadRequireSection;
  137. function GetTargetRequires(t:TTarget):TStringList;
  138. function CheckLibcRequire:boolean;
  139. procedure CreateExportSection;
  140. procedure AddFPCDefaultVariables;
  141. procedure AddLCLDefaultVariables;
  142. function SubstVariables(const s:string):string;
  143. function GetVariable(const inivar:string;dosubst:boolean):string;
  144. function SetVariable(const inivar,value:string;add:boolean):string;
  145. procedure Print;
  146. property Section[const s:string]:TDictionaryItem read GetSec;default;
  147. property RequireList:TTargetRequireList read FRequireList;
  148. property Variables:TKeyValue read FVariables;
  149. property UsesLCL:boolean read FUsesLCL;
  150. property IsPackage:boolean read FIsPackage;
  151. property PackageName:string read FPackageName;
  152. property PackageVersion:string read FPackageVersion;
  153. property PackageSec:TFPCMakeSection read FPackageSec;
  154. property ExportSec:TFPCMakeSection read FExportSec;
  155. property CommentChars:TSysCharSet read FCommentChars write FCommentChars;
  156. property EmptyLines:Boolean read FEmptyLines write FEmptyLines;
  157. property IncludeTargets:TTargetSet read FIncludeTargets write FIncludeTargets;
  158. end;
  159. function posidx(const substr,s : string;idx:integer):integer;
  160. function GetToken(var s:string;sep:char):string;
  161. procedure AddToken(var s:string;const tok:string;sep:char);
  162. procedure AddTokenNoDup(var s:string;const s2:string;sep:char);
  163. implementation
  164. resourcestring
  165. s_not_list_sec='Not a list section "%s"';
  166. s_not_key_value_sec='Not a key-value section "%s"';
  167. s_err_section_start='%s:%d: Wrong section start';
  168. s_err_not_key_value='Parse error key=value excepted: "%s"';
  169. s_err_no_section='%s:%d: Entries without section';
  170. s_no_package_name='No package name set';
  171. s_no_package_version='No package version set';
  172. s_err_require_format='Wrong require format "%s"';
  173. s_wrong_package_name='Package name "%s" expected, but "%s" found';
  174. s_wrong_package_version='Package version "%s" expected, but version "%s" found';
  175. s_directory_not_found='Directory "%s" not found';
  176. s_makefilefpc_not_found='No Makefile.fpc found in directory "%s"';
  177. s_package_not_found='Target "%s", package "%s" not found';
  178. s_fpcmake_version_required='FPCMake version "%s" is required';
  179. s_no_targets_set='No targets set';
  180. s_targets_info='Targets: "%s"';
  181. s_globals='Globals:';
  182. {****************************************************************************
  183. Helpers
  184. ****************************************************************************}
  185. Function PathExists ( F : String) : Boolean;
  186. Var
  187. Info : TSearchRec;
  188. begin
  189. if F[Length(f)] in ['/','\'] then
  190. Delete(f,length(f),1);
  191. PathExists:=(findfirst(F,faAnyFile,info)=0) and
  192. ((info.attr and fadirectory)=fadirectory);
  193. findclose(Info);
  194. end;
  195. Function PathOrFileExists ( F : String) : Boolean;
  196. Var
  197. Info : Dos.SearchRec;
  198. begin
  199. if F[Length(f)] in ['/','\'] then
  200. Delete(f,length(f),1);
  201. dos.findfirst(f,fareadonly+faarchive+fahidden+fadirectory,info);
  202. PathOrFileExists:=(Doserror=0);
  203. dos.findclose(Info);
  204. end;
  205. function posidx(const substr,s : string;idx:integer):integer;
  206. var
  207. i,j : integer;
  208. e : boolean;
  209. begin
  210. i:=idx;
  211. j:=0;
  212. e:=(length(SubStr)>0);
  213. while e and (i<=Length(s)-Length(SubStr)) do
  214. begin
  215. inc(i);
  216. if (SubStr[1]=s[i]) and (Substr=Copy(s,i,Length(SubStr))) then
  217. begin
  218. j:=i;
  219. e:=false;
  220. end;
  221. end;
  222. PosIdx:=j;
  223. end;
  224. function GetToken(var s:string;sep:char):string;
  225. var
  226. i : integer;
  227. begin
  228. s:=Trim(s);
  229. i:=pos(sep,s);
  230. if i=0 then
  231. begin
  232. Result:=s;
  233. s:='';
  234. end
  235. else
  236. begin
  237. Result:=Copy(s,1,i-1);
  238. Delete(s,1,i);
  239. end;
  240. end;
  241. procedure AddToken(var s:string;const tok:string;sep:char);
  242. begin
  243. if tok='' then
  244. exit;
  245. if s<>'' then
  246. s:=s+sep+tok
  247. else
  248. s:=tok;
  249. end;
  250. procedure AddTokenNoDup(var s:string;const s2:string;sep:char);
  251. var
  252. i,idx : integer;
  253. again,add : boolean;
  254. begin
  255. add:=false;
  256. idx:=0;
  257. repeat
  258. again:=false;
  259. i:=posidx(s2,s,idx);
  260. if (i=0) then
  261. add:=true
  262. else
  263. if (i=1) then
  264. begin
  265. if (length(s)>length(s2)) and
  266. (s[length(s2)+1]<>sep) then
  267. add:=true;
  268. end
  269. else
  270. if (i>1) and
  271. ((s[i-1]<>sep) or
  272. ((length(s)>=i+length(s2)) and (s[i+length(s2)]<>sep))) then
  273. begin
  274. idx:=i+length(s2);
  275. again:=true;
  276. end;
  277. until not again;
  278. if add then
  279. begin
  280. if s='' then
  281. s:=s2
  282. else
  283. s:=s+sep+s2;
  284. end;
  285. end;
  286. {****************************************************************************
  287. TKeyValueItem
  288. ****************************************************************************}
  289. constructor TKeyValueItem.Create(const k,v:string);
  290. begin
  291. inherited Create(k);
  292. value:=v;
  293. end;
  294. {****************************************************************************
  295. TKeyValue
  296. ****************************************************************************}
  297. function TKeyValue.GetKey(const k:string):string;
  298. var
  299. p : TKeyValueItem;
  300. begin
  301. p:=TKeyValueItem(Search(k));
  302. if p=nil then
  303. GetKey:=''
  304. else
  305. GetKey:=p.Value;
  306. end;
  307. procedure TKeyValue.Add(const k,v:string);
  308. var
  309. p : TKeyValueItem;
  310. begin
  311. p:=TKeyValueItem(Search(k));
  312. if p=nil then
  313. begin
  314. p:=TKeyValueItem.Create(k,v);
  315. Insert(p);
  316. end
  317. else
  318. p.Value:=v;
  319. end;
  320. {****************************************************************************
  321. TFPCMakeSection
  322. ****************************************************************************}
  323. constructor TFPCMakeSection.Create(const n:string);
  324. begin
  325. inherited Create(n);
  326. FList:=TStringList.Create;
  327. FDictionary:=nil;
  328. end;
  329. constructor TFPCMakeSection.CreateKeyValue(const n:string);
  330. begin
  331. inherited Create(n);
  332. FList:=nil;
  333. FDictionary:=TKeyValue.Create;
  334. end;
  335. destructor TFPCMakeSection.Destroy;
  336. begin
  337. inherited Destroy;
  338. FList.Free;
  339. FDictionary.Free;
  340. end;
  341. procedure TFPCMakeSection.Clear;
  342. begin
  343. FList.Free;
  344. FList:=TStringList.Create;
  345. FDictionary.Free;
  346. FDictionary:=nil;
  347. end;
  348. procedure TFPCMakeSection.AddLine(const s:string);
  349. begin
  350. if FList=nil then
  351. raise Exception.Create(Format(s_not_list_sec,[Name]));
  352. FList.Add(s);
  353. end;
  354. procedure TFPCMakeSection.AddKey(const k,v:string);
  355. begin
  356. if FDictionary=nil then
  357. raise Exception.Create(Format(s_not_key_value_sec,[Name]));
  358. { Don't add empty values }
  359. if v<>'' then
  360. FDictionary.Add(k,v);
  361. end;
  362. function TFPCMakeSection.GetKey(const k:string):string;
  363. begin
  364. if FDictionary=nil then
  365. raise Exception.Create(Format(s_not_key_value_sec,[Name]));
  366. GetKey:=FDictionary[k];
  367. end;
  368. procedure TFPCMakeSection.ParseIni;
  369. var
  370. p : TKeyValueItem;
  371. i,j,len,maxi : integer;
  372. s,newkey,value : string;
  373. begin
  374. { If already processed skip }
  375. if assigned(FDictionary) then
  376. exit;
  377. { Don't process rules section }
  378. if (Name='prerules') or (Name='rules') then
  379. exit;
  380. { Parse the section }
  381. FDictionary:=TKeyValue.Create;
  382. { Parse the list }
  383. maxi:=FList.Count;
  384. i:=0;
  385. while (i<maxi) do
  386. begin
  387. s:=Trim(FList[i]);
  388. len:=Length(s);
  389. { Concat lines ending with \ }
  390. while s[len]='\' do
  391. begin
  392. Delete(s,len,1);
  393. if i+1<maxi then
  394. begin
  395. inc(i);
  396. s:=s+Trim(FList[i]);
  397. len:=Length(s);
  398. end;
  399. end;
  400. { Parse key=value line }
  401. j:=0;
  402. while (j<len) and (s[j+1] in ['A'..'Z','a'..'z','0'..'9','_']) do
  403. inc(j);
  404. NewKey:=Copy(s,1,j);
  405. While (j<len) and (s[j+1] in [' ',#9]) do
  406. inc(j);
  407. inc(j);
  408. if s[j]<>'=' then
  409. Raise Exception.Create(Format(s_err_not_key_value,[s]));
  410. While (j<len) and (s[j+1] in [' ',#9]) do
  411. inc(j);
  412. Value:=Copy(s,j+1,len-j);
  413. p:=TKeyValueItem(FDictionary.Search(NewKey));
  414. { Concat values if key already exists }
  415. if assigned(p) then
  416. AddToken(p.FValue,Value,' ')
  417. else
  418. FDictionary.Add(NewKey,Value);
  419. inc(i);
  420. end;
  421. { List is not used anymore }
  422. FList.Free;
  423. FList:=nil;
  424. end;
  425. procedure TFPCMakeSection.BuildIniDic(p:TDictionaryItem);
  426. begin
  427. with TKeyValueItem(p) do
  428. begin
  429. FList.Add(Name+'='+Value);
  430. end;
  431. end;
  432. procedure TFPCMakeSection.BuildIni;
  433. begin
  434. if assigned(FList) then
  435. exit;
  436. FList:=TStringList.Create;
  437. FDictionary.Foreach(@BuildIniDic);
  438. FDictionary.Free;
  439. FDictionary:=nil;
  440. end;
  441. procedure TFPCMakeSection.BuildMakefileDic(p:TDictionaryItem);
  442. begin
  443. FList.Add(Uppercase(Name+'_'+TKeyValueItem(p).Name)+'='+TKeyValueItem(p).Value);
  444. end;
  445. procedure TFPCMakeSection.BuildMakefile;
  446. begin
  447. if assigned(FList) then
  448. exit;
  449. FList:=TStringList.Create;
  450. FDictionary.Foreach(@BuildMakefileDic);
  451. FDictionary.Free;
  452. FDictionary:=nil;
  453. end;
  454. {****************************************************************************
  455. TFPCMake
  456. ****************************************************************************}
  457. constructor TFPCMake.Create(const AFileName:string);
  458. begin
  459. FFileName:=AFileName;
  460. FStream:=nil;
  461. Init;
  462. end;
  463. constructor TFPCMake.CreateFromStream(s:TStream;const AFileName:string);
  464. begin
  465. FFileName:=AFileName;
  466. FStream:=s;
  467. Init;
  468. end;
  469. procedure TFPCMake.Init;
  470. var
  471. t : ttarget;
  472. begin
  473. FSections:=TDictionary.Create;
  474. for t:=low(ttarget) to high(ttarget) do
  475. FRequireList[t]:=TStringList.Create;
  476. FVariables:=TKeyValue.Create;
  477. FCommentChars:=[';','#'];
  478. FEmptyLines:=false;
  479. FIsPackage:=false;
  480. FPackageName:='';
  481. FPackageVersion:='';
  482. FPackageSec:=nil;
  483. FExportSec:=nil;
  484. FIncludeTargets:=[low(TTarget)..high(TTarget)];
  485. VerboseIdent:='';
  486. FUsesLCL:=false;
  487. end;
  488. destructor TFPCMake.Destroy;
  489. var
  490. t : ttarget;
  491. begin
  492. FSections.Free;
  493. for t:=low(ttarget) to high(ttarget) do
  494. FRequireList[t].Free;
  495. FVariables.Free;
  496. end;
  497. procedure TFPCMake.LoadSections;
  498. var
  499. SLInput : TStringList;
  500. i,j,n : integer;
  501. s,
  502. SecName : string;
  503. CurrSec : TFPCMakeSection;
  504. begin
  505. try
  506. CurrSec:=nil;
  507. SLInput:=TStringList.Create;
  508. if assigned(FStream) then
  509. SLInput.LoadFromStream(FStream)
  510. else
  511. SLInput.LoadFromFile(FFileName);
  512. { Load Input into sections list }
  513. n:=SLInput.Count;
  514. i:=0;
  515. while (i<n) do
  516. begin
  517. s:=Trim(SLInput[i]);
  518. if (EmptyLines and (s='')) or
  519. ((s<>'') and not(s[1] in FCommentChars)) then
  520. begin
  521. { section start? }
  522. if (s<>'') and (s[1]='[') then
  523. begin
  524. j:=pos(']',s);
  525. if j=0 then
  526. raise Exception.Create(Format(s_err_section_start,[FFileName,i+1]));
  527. SecName:=Copy(s,2,j-2);
  528. CurrSec:=TFPCMakeSection(FSections[SecName]);
  529. if CurrSec=nil then
  530. CurrSec:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.Create(SecName)));
  531. end
  532. else
  533. begin
  534. if CurrSec=nil then
  535. raise Exception.Create(Format(s_err_no_section,[FFileName,i+1]));
  536. { Insert string without spaces stripped }
  537. CurrSec.AddLine(SLInput[i]);
  538. end;
  539. end;
  540. inc(i);
  541. end;
  542. finally
  543. SLInput.Free;
  544. end;
  545. end;
  546. function TFPCMake.CopySection(Sec:TFPCMakeSection;Secname:string):TFPCMakeSection;
  547. begin
  548. Result:=TFPCMakeSection(FSections[SecName]);
  549. if Sec=Nil then
  550. exit;
  551. { Clear old section or if not existing create new }
  552. if assigned(Result) then
  553. Result.Clear
  554. else
  555. Result:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.Create(SecName)));
  556. Sec.BuildIni;
  557. Result.List.AddStrings(Sec.List);
  558. Result.ParseIni;
  559. Sec.ParseIni;
  560. end;
  561. procedure TFPCMake.LoadMakefileFPC;
  562. var
  563. s : string;
  564. begin
  565. LoadSections;
  566. { Parse all sections }
  567. FSections.Foreach(@ParseSec);
  568. { Load package section }
  569. LoadPackageSection;
  570. { Add some default variables like FPCDIR, UNITSDIR }
  571. AddFPCDefaultVariables;
  572. { Load LCL code ? }
  573. s:=GetVariable('require_packages',true);
  574. if (pos('lcl',s)>0) or (PackageName='lcl') then
  575. begin
  576. FUsesLCL:=true;
  577. AddLCLDefaultVariables;
  578. end;
  579. { Show globals }
  580. Verbose(FPCMakeDebug,s_globals);
  581. Variables.Foreach(@PrintDic);
  582. { Load required packages }
  583. LoadRequireSection;
  584. end;
  585. procedure TFPCMake.Verbose(lvl:TFPCMakeVerbose;const s:string);
  586. begin
  587. writeln(VerboseIdent,s);
  588. end;
  589. procedure TFPCMake.SetTargets(const s:string);
  590. var
  591. hslst : string;
  592. hs : string;
  593. t : TTarget;
  594. begin
  595. FIncludeTargets:=[];
  596. hslst:=s;
  597. repeat
  598. hs:=LowerCase(GetToken(hslst,','));
  599. if hs='' then
  600. break;
  601. { target 'all' includes all targets }
  602. if hs='all' then
  603. begin
  604. for t:=low(TTarget) to high(TTarget) do
  605. include(FIncludeTargets,t);
  606. break;
  607. end;
  608. for t:=low(TTarget) to high(TTarget) do
  609. if hs=TargetStr[t] then
  610. include(FIncludeTargets,t);
  611. until false;
  612. if FIncludeTargets=[] then
  613. raise Exception.Create(s_no_targets_set)
  614. else
  615. begin
  616. hs:='';
  617. for t:=low(TTarget) to high(TTarget) do
  618. if t in FIncludeTargets then
  619. AddToken(hs,TargetStr[t],' ');
  620. Verbose(FPCMakeDebug,Format(s_targets_info,[hs]));
  621. end;
  622. end;
  623. procedure TFPCMake.LoadPackageSection;
  624. var
  625. hs,s : string;
  626. t : TTarget;
  627. begin
  628. { Get package info from package section }
  629. FPackageSec:=TFPCMakeSection(FSections['package']);
  630. if FPackageSec=nil then
  631. exit;
  632. { Parse the section to key=value pairs }
  633. FPackageSec.ParseIni;
  634. { Are we a subpart of a package, then load that package }
  635. s:=FPackageSec['main'];
  636. if s<>'' then
  637. begin
  638. SetVariable('package_name',s,false);
  639. FPackageName:=s;
  640. end
  641. else
  642. begin
  643. { mandatory name }
  644. FPackageName:=FPackageSec['name'];
  645. if FPackageName='' then
  646. Raise Exception.Create(s_no_package_name);
  647. { mandatory version }
  648. FPackageVersion:=FPackageSec['version'];
  649. if FPackageVersion='' then
  650. Raise Exception.Create(s_no_package_version);
  651. FIsPackage:=true;
  652. { optional targets }
  653. FPackageTargets:='';
  654. s:=LowerCase(FPackageSec['targets']);
  655. repeat
  656. hs:=GetToken(s,' ');
  657. if hs='' then
  658. break;
  659. for t:=low(TTarget) to high(TTarget) do
  660. if hs=TargetStr[t] then
  661. begin
  662. AddToken(FPackageTargets,hs,' ');
  663. break;
  664. end;
  665. until false;
  666. { Set the ExportSec }
  667. FExportSec:=TFPCMakeSection(FSections[Lowercase(FPackageName)]);
  668. end;
  669. end;
  670. procedure TFPCMake.CreateExportSection;
  671. var
  672. t : TTarget;
  673. begin
  674. { Don't create a section twice }
  675. if FExportSec<>nil then
  676. exit;
  677. { Look if we've already an own section, else create a new
  678. key-value section }
  679. FExportSec:=TFPCMakeSection(FSections[LowerCase(FPackageName)]);
  680. if FExportSec=nil then
  681. FExportSec:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.CreateKeyValue(LowerCase(FPackageName))));
  682. { Add default the values to the export section }
  683. FExportSec.AddKey('name',FPackageName);
  684. FExportSec.AddKey('version',FPackageVersion);
  685. { Add required packages }
  686. for t:=low(TTarget) to high(TTarget) do
  687. FExportSec.AddKey('require'+TargetSuffix[t],FPackageSec['require'+TargetSuffix[t]]);
  688. { Unit dir }
  689. {FExportSec.AddKey('unitdir','$(UNITSDIR)/'+Lowercase(PackageName));}
  690. end;
  691. procedure TFPCMake.LoadRequiredPackage(t:TTarget;const ReqName,ReqVersion:string);
  692. function TryFile(const fn:string):boolean;
  693. var
  694. ReqFPCMake : TFPCMake;
  695. begin
  696. TryFile:=false;
  697. if FileExists(fn) then
  698. begin
  699. VerboseIdent:=VerboseIdent+' ';
  700. Verbose(FPCMakeDebug,'Package '+ReqName+': '+fn);
  701. ReqFPCMake:=TFPCMake.Create(fn);
  702. ReqFPCMake.LoadSections;
  703. ReqFPCMake.LoadPackageSection;
  704. { Check package name and version }
  705. if LowerCase(ReqFPCMake.PackageName)<>ExtractFileName(ReqName) then
  706. raise Exception.Create(Format(s_wrong_package_name,[ReqName,LowerCase(ReqFPCMake.PackageName)]));
  707. if (ReqVersion<>'') and (ReqFPCMake.PackageVersion<ReqVersion) then
  708. raise Exception.Create(Format(s_wrong_package_version,[ReqVersion,ReqFPCMake.PackageVersion]));
  709. { First load the requirements of this package }
  710. LoadRequires(t,ReqFPCMake);
  711. { Get a copy of the package section }
  712. CopySection(ReqFPCMake.PackageSec,ReqName+'_package');
  713. { Get a copy of the export section }
  714. CopySection(ReqFPCMake.ExportSec,ReqName);
  715. { Get a copy of the require section }
  716. CopySection(TFPCMakeSection(ReqFPCMake['require']),ReqName+'_require');
  717. { Free }
  718. ReqFPCMake.Free;
  719. Delete(VerboseIdent,1,2);
  720. TryFile:=true;
  721. end;
  722. end;
  723. var
  724. s : string;
  725. begin
  726. { Force the current target }
  727. SetVariable('TARGET',TargetStr[t],false);
  728. { Check for Makefile.fpc }
  729. s:=SubstVariables('$(addsuffix /'+ReqName+'/Makefile.fpc,$(FPCDIR)) $(addsuffix /'+ReqName+'/Makefile.fpc,$(PACKAGESDIR)) $(addsuffix /'+ReqName+'/Makefile.fpc,$(REQUIRE_PACKAGESDIR))');
  730. Verbose(FPCMakeDebug,'Package "'+ReqName+'": Looking for Makefile.fpc: "'+s+'"');
  731. s:=SubstVariables('$(firstword $(wildcard '+s+'))');
  732. if TryFile(s) then
  733. exit;
  734. { Check for Package.fpc }
  735. s:=SubstVariables('$(addsuffix /'+ReqName+'/Package.fpc,$(FPCDIR)) $(addsuffix /'+ReqName+'/Package.fpc,$(UNITSDIR)) $(addsuffix /'+ReqName+'/Package.fpc,$(REQUIRE_UNITSDIR))');
  736. Verbose(FPCMakeDebug,'Package "'+ReqName+'": Looking for Package.fpc: "'+s+'"');
  737. s:=SubstVariables('$(firstword $(wildcard '+s+'))');
  738. if TryFile(s) then
  739. exit;
  740. Raise Exception.Create(Format(s_package_not_found,[TargetStr[t],Reqname]));
  741. end;
  742. procedure TFPCMake.LoadRequiredDir(t:TTarget;const MainPack,currdir,subdir:string);
  743. var
  744. ReqFPCMake : TFPCMake;
  745. s : string;
  746. begin
  747. VerboseIdent:=VerboseIdent+' ';
  748. s:=currdir+subdir;
  749. Verbose(FPCMakeDebug,'Subdir: '+s+'/Makefile.fpc');
  750. if not FileExists(s+'/Makefile.fpc') then
  751. begin
  752. { give better error what is wrong }
  753. if not PathExists(s) then
  754. Raise Exception.Create(Format(s_directory_not_found,[s]))
  755. else
  756. Raise Exception.Create(Format(s_makefilefpc_not_found,[s]));
  757. end;
  758. { Process Makefile.fpc }
  759. ReqFPCMake:=TFPCMake.Create(currdir+subdir+'/Makefile.fpc');
  760. ReqFPCMake.LoadSections;
  761. ReqFPCMake.LoadPackageSection;
  762. { Are we a subpackage? }
  763. if (ReqFPCMake.GetVariable('package_name',false)<>MainPack) then
  764. begin
  765. ReqFPCMake.Free;
  766. Delete(VerboseIdent,1,2);
  767. exit;
  768. end;
  769. { Load the requirements of this package }
  770. LoadRequires(t,ReqFPCMake);
  771. { Add the current requirements to our parents requirements }
  772. s:=Trim(ReqFPCMake.GetVariable('require_packages',true)+' '+ReqFPCMake.GetVariable('require_packages'+targetsuffix[t],true));
  773. SetVariable('require_packages'+targetsuffix[t],s,true);
  774. if ReqFPCMake.GetVariable('require_libc',false)<>'' then
  775. SetVariable('require_libc','y',false);
  776. { Free }
  777. ReqFPCMake.Free;
  778. Delete(VerboseIdent,1,2);
  779. end;
  780. procedure TFPCMake.LoadRequires(t:Ttarget;FromFPCMake:TFPCMake);
  781. var
  782. s,
  783. ReqDir,
  784. ReqName,
  785. ReqVersion : string;
  786. i,j : integer;
  787. begin
  788. { packages }
  789. s:=Trim(FromFPCMake.GetVariable('require_packages',true)+' '+FromFPCMake.GetVariable('require_packages'+TargetSuffix[t],true));
  790. Verbose(FPCMakeDebug,'Required packages for '+TargetStr[t]+': '+s);
  791. repeat
  792. reqname:=GetToken(s,' ');
  793. if reqname='' then
  794. break;
  795. i:=Pos('(',ReqName);
  796. if i>0 then
  797. begin
  798. j:=Pos(')',ReqName);
  799. if (i=1) or (j=0) then
  800. Raise Exception.Create(Format(s_err_require_format,[ReqName]));
  801. ReqVersion:=Copy(ReqName,i+1,j-i-1);
  802. ReqName:=Copy(ReqName,1,i-1);
  803. end
  804. else
  805. ReqVersion:='';
  806. { We only use lowercase names }
  807. ReqName:=Lowercase(ReqName);
  808. { Already loaded ? }
  809. if (RequireList[t].IndexOf(ReqName)=-1) then
  810. begin
  811. LoadRequiredPackage(t,ReqName,ReqVersion);
  812. RequireList[t].Add(ReqName);
  813. end;
  814. until false;
  815. { sub dirs }
  816. s:=FromFPCMake.GetVariable('target_dirs',true)+' '+FromFPCMake.GetVariable('target_dirs'+TargetSuffix[t],true);
  817. Verbose(FPCMakeDebug,'Required dirs for '+TargetStr[t]+': '+s);
  818. repeat
  819. reqdir:=GetToken(s,' ');
  820. if reqdir='' then
  821. break;
  822. LoadRequiredDir(t,FromFPCMake.FPackageName,ExtractFilePath(FromFPCMake.FFileName),ReqDir)
  823. until false;
  824. end;
  825. procedure TFPCMake.LoadRequireSection;
  826. function CheckVar(const s:string):boolean;
  827. var
  828. t : ttarget;
  829. begin
  830. result:=false;
  831. if GetVariable(s,false)<>'' then
  832. begin
  833. result:=true;
  834. exit;
  835. end;
  836. for t:=low(ttarget) to high(ttarget) do
  837. if t in FIncludeTargets then
  838. begin
  839. if GetVariable(s+targetsuffix[t],false)<>'' then
  840. begin
  841. result:=true;
  842. exit;
  843. end;
  844. end;
  845. end;
  846. var
  847. s : string;
  848. t : ttarget;
  849. begin
  850. { Check FPCMake version }
  851. s:=GetVariable('require_fpcmake',false);
  852. if (s>version) then
  853. raise Exception.Create(Format(s_fpcmake_version_required,[s]));
  854. { Maybe add an implicit rtl dependency if there is something
  855. to compile }
  856. s:=GetVariable('require_packages',false);
  857. if (GetVariable('require_nortl',false)='') and
  858. (CheckVar('target_programs') or
  859. CheckVar('target_units') or
  860. CheckVar('target_examples')) and
  861. (Pos('rtl(',s)=0) then
  862. begin
  863. s:='rtl '+s;
  864. SetVariable('require_packages',s,false);
  865. end;
  866. { Load recursively all required packages starting with this Makefile.fpc }
  867. for t:=low(TTarget) to high(TTarget) do
  868. if t in FIncludeTargets then
  869. LoadRequires(t,self);
  870. end;
  871. function TFPCMake.GetTargetRequires(t:TTarget):TStringList;
  872. var
  873. ReqSec : TFPCMakeSection;
  874. ReqList : TStringList;
  875. procedure AddReqSec(t:TTarget;Sec:TFPCMakeSection);
  876. var
  877. s,
  878. ReqName : string;
  879. RSec : TFPCMakeSection;
  880. i : integer;
  881. begin
  882. s:=Sec['packages']+' '+Sec['packages'+TargetSuffix[t]];
  883. repeat
  884. ReqName:=GetToken(s,' ');
  885. if ReqName='' then
  886. break;
  887. i:=Pos('(',ReqName);
  888. if i>0 then
  889. ReqName:=Copy(ReqName,1,i-1);
  890. { We only use lowercase names }
  891. ReqName:=Lowercase(ReqName);
  892. { Already loaded ? }
  893. if (ReqList.IndexOf(ReqName)=-1) then
  894. begin
  895. RSec:=TFPCMakeSection(FSections[ReqName+'_require']);
  896. if assigned(RSec) then
  897. AddReqSec(t,RSec);
  898. ReqList.Add(ReqName);
  899. end;
  900. until false;
  901. end;
  902. begin
  903. ReqList:=TStringList.Create;
  904. ReqSec:=TFPCMakeSection(FSections['require']);
  905. if assigned(ReqSec) then
  906. AddReqSec(t,ReqSec);
  907. GetTargetRequires:=ReqList;
  908. end;
  909. function TFPCMake.CheckLibcRequire:boolean;
  910. var
  911. i : integer;
  912. RSec : TFPCMakeSection;
  913. t : ttarget;
  914. begin
  915. Result:=false;
  916. if GetVariable('require_libc',false)<>'' then
  917. begin
  918. Result:=true;
  919. exit;
  920. end;
  921. for t:=low(ttarget) to high(ttarget) do
  922. if t in FIncludeTargets then
  923. begin
  924. for i:=0 to RequireList[t].Count-1 do
  925. begin
  926. RSec:=TFPCMakeSection(FSections[RequireList[t][i]+'_require']);
  927. if assigned(RSec) then
  928. begin
  929. if RSec['libc']<>'' then
  930. begin
  931. Result:=true;
  932. exit;
  933. end;
  934. end;
  935. end;
  936. end;
  937. end;
  938. procedure TFPCMake.AddFPCDefaultVariables;
  939. var
  940. hs,s : string;
  941. begin
  942. { Already set FPCDIR }
  943. hs:='';
  944. s:=GetVariable('FPCDIR',false);
  945. if s<>'' then
  946. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  947. { Load from environment }
  948. if hs='' then
  949. begin
  950. s:=GetEnv('FPCDIR');
  951. if s<>'' then
  952. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  953. end;
  954. { default_fpcdir }
  955. if hs='' then
  956. begin
  957. s:=GetVariable('default_fpcdir',true);
  958. { add the current subdir to relative paths }
  959. if s<>'' then
  960. begin
  961. {$ifdef UNIX}
  962. if (s[1]<>'/') then
  963. {$else}
  964. if (length(s)>2) and (s[2]<>':') then
  965. {$endif}
  966. s:=ExtractFilePath(FFileName)+s;
  967. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  968. end
  969. end;
  970. { OS defaults }
  971. if hs='' then
  972. begin
  973. {$ifdef UNIX}
  974. {$ifndef NO_UNIX_UNIT}
  975. if FileExists('/usr/local/bin/ppc386') then
  976. begin
  977. s:=ExtractFilePath(ReadLink('/usr/local/bin/ppc386'));
  978. if s<>'' then
  979. begin
  980. if s[length(s)]='/' then
  981. delete(s,length(s),1);
  982. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  983. end;
  984. end;
  985. if hs='' then
  986. begin
  987. if FileExists('/usr/bin/ppc386') then
  988. begin
  989. s:=ExtractFilePath(ReadLink('/usr/bin/ppc386'));
  990. if s<>'' then
  991. begin
  992. if s[length(s)]='/' then
  993. delete(s,length(s),1);
  994. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  995. end;
  996. end;
  997. end;
  998. {$endif}
  999. {$else UNIX}
  1000. hs:=ExtractFilePath(FSearch('ppc386.exe',getenv('PATH')));
  1001. if hs<>'' then
  1002. begin
  1003. s:=hs+'/..';
  1004. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  1005. if hs='' then
  1006. begin
  1007. s:=s+'/..';
  1008. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  1009. end;
  1010. end;
  1011. if hs='' then
  1012. s:='c:/pp';
  1013. {$endif UNIX}
  1014. end;
  1015. SetVariable('FPCDIR',s,false);
  1016. { PACKAGESDIR }
  1017. if GetVariable('PACKAGESDIR',false)='' then
  1018. SetVariable('PACKAGESDIR','$(FPCDIR)/packages/base $(FPCDIR)/packages/extra',false);
  1019. { UNITSDIR }
  1020. if GetVariable('UNITSDIR',false)='' then
  1021. SetVariable('UNITSDIR','$(FPCDIR)/units/$(TARGET)',false);
  1022. { BASEDIR }
  1023. SetVariable('BASEDIR',GetCurrentDir,false);
  1024. end;
  1025. procedure TFPCMake.AddLCLDefaultVariables;
  1026. var
  1027. hs,s : string;
  1028. begin
  1029. { Already set LCLDIR }
  1030. hs:=SubstVariables('$(wildcard $(LCLDIR)/units)');
  1031. { Load from environment }
  1032. if hs='' then
  1033. begin
  1034. SetVariable('LCLDIR',GetEnv('LCLDIR'),false);
  1035. hs:=SubstVariables('$(wildcard $(LCLDIR)/units)');
  1036. end;
  1037. { default_lcldir }
  1038. if hs='' then
  1039. begin
  1040. s:=GetVariable('default_lcldir',true);
  1041. { add the current subdir to relative paths }
  1042. if s<>'' then
  1043. begin
  1044. {$ifdef UNIX}
  1045. if (s[1]<>'/') then
  1046. {$else}
  1047. if (length(s)>2) and (s[2]<>':') then
  1048. {$endif}
  1049. s:=ExtractFilePath(FFileName)+s;
  1050. SetVariable('LCLDIR',s,false);
  1051. hs:=SubstVariables('$(wildcard $(LCLDIR)/units)');
  1052. end
  1053. end;
  1054. { OS defaults }
  1055. if hs='' then
  1056. begin
  1057. hs:=SubstVariables('$(subst /units,,$(firstword $(wildcard $(addsuffix /units,$(BASEDIR)/lcl $(BASEDIR)))))');
  1058. if hs<>'' then
  1059. SetVariable('LCLDIR',hs,false);
  1060. end;
  1061. {$ifdef UNIX}
  1062. if hs='' then
  1063. begin
  1064. hs:=SubstVariables('$(subst /units,,$(firstword $(wildcard $(addsuffix /lib/lazarus/units,/usr/local /usr))))');
  1065. if hs<>'' then
  1066. SetVariable('LCLDIR',hs,false);
  1067. end;
  1068. {$endif UNIX}
  1069. { Add components to PACKAGESDIR }
  1070. SetVariable('PACKAGESDIR',SubstVariables('$(wildcard $(LCLDIR)/.. $(LCLDIR)/../components $(LCLDIR)/components)'),true);
  1071. end;
  1072. function TFPCMake.SubstVariables(const s:string):string;
  1073. function Expect(var s:string;c:char):boolean;
  1074. begin
  1075. if (s<>'') and (s[1]=c) then
  1076. begin
  1077. Delete(s,1,1);
  1078. Result:=true;
  1079. end
  1080. else
  1081. begin
  1082. Verbose(FPCMakeError,'Error "'+c+'" expected');
  1083. Result:=false;
  1084. end;
  1085. end;
  1086. function GetVar(var s:string;untilc:char):string;
  1087. var
  1088. i,j,k : integer;
  1089. first : boolean;
  1090. func,
  1091. tok,s1,s2,s3 : string;
  1092. Sec : TFPCMakeSection;
  1093. begin
  1094. Result:='';
  1095. repeat
  1096. j:=Pos(untilc,s);
  1097. if j=0 then
  1098. j:=Length(s)+1;
  1099. i:=Pos('$(',s);
  1100. if (j<i) or (i=0) then
  1101. break;
  1102. Result:=Result+Copy(s,1,i-1);
  1103. Delete(s,1,i+1);
  1104. { Maybe Function ? }
  1105. j:=Pos(')',s);
  1106. if j=0 then
  1107. j:=Length(s)+1;
  1108. i:=Pos(' ',s);
  1109. if i=0 then
  1110. i:=Length(s)+1;
  1111. if i<j then
  1112. begin
  1113. { It's a function }
  1114. Func:=Copy(s,1,i-1);
  1115. //writeln('func: ',func);
  1116. { $(wildcard <list>) }
  1117. if Func='wildcard' then
  1118. begin
  1119. Delete(s,1,9);
  1120. s1:=GetVar(s,')');
  1121. Expect(s,')');
  1122. first:=true;
  1123. repeat
  1124. tok:=GetToken(s1,' ');
  1125. if tok='' then
  1126. break;
  1127. if PathOrFileExists(tok) then
  1128. begin
  1129. if not first then
  1130. Result:=Result+' '
  1131. else
  1132. first:=false;
  1133. Result:=Result+tok;
  1134. end;
  1135. until false;
  1136. end
  1137. { $(addprefix <suffix>,<list>) }
  1138. else if Func='addprefix' then
  1139. begin
  1140. Delete(s,1,10);
  1141. s1:=GetVar(s,',');
  1142. if Expect(s,',') then
  1143. begin
  1144. s2:=GetVar(s,')');
  1145. Expect(s,')');
  1146. end;
  1147. first:=true;
  1148. repeat
  1149. tok:=GetToken(s2,' ');
  1150. if tok='' then
  1151. break;
  1152. if not first then
  1153. Result:=Result+' '
  1154. else
  1155. first:=false;
  1156. Result:=Result+s1+tok;
  1157. until false;
  1158. end
  1159. { $(addsuffix <suffix>,<list>) }
  1160. else if Func='addsuffix' then
  1161. begin
  1162. Delete(s,1,10);
  1163. s1:=GetVar(s,',');
  1164. if Expect(s,',') then
  1165. begin
  1166. s2:=GetVar(s,')');
  1167. Expect(s,')');
  1168. end;
  1169. first:=true;
  1170. repeat
  1171. tok:=GetToken(s2,' ');
  1172. if tok='' then
  1173. break;
  1174. if not first then
  1175. Result:=Result+' '
  1176. else
  1177. first:=false;
  1178. Result:=Result+tok+s1;
  1179. until false;
  1180. end
  1181. { $(firstword <list>) }
  1182. else if Func='firstword' then
  1183. begin
  1184. Delete(s,1,10);
  1185. s1:=GetVar(s,')');
  1186. Expect(s,')');
  1187. Result:=GetToken(s1,' ');
  1188. end
  1189. { $(subst <oldpat>,<newpat>,<string>) }
  1190. else if Func='subst' then
  1191. begin
  1192. Delete(s,1,6);
  1193. s1:=GetVar(s,',');
  1194. if Expect(s,',') then
  1195. begin
  1196. s2:=GetVar(s,',');
  1197. if Expect(s,',') then
  1198. begin
  1199. s3:=GetVar(s,')');
  1200. Expect(s,')');
  1201. end;
  1202. end;
  1203. Result:=StringReplace(s3,s1,s2,[rfReplaceAll]);
  1204. end;
  1205. end
  1206. else
  1207. begin
  1208. s2:=Copy(s,1,j-1);
  1209. Delete(s,1,j);
  1210. k:=pos('_',s2);
  1211. if k>0 then
  1212. begin
  1213. s3:=LowerCase(Copy(s2,k+1,Length(s2)-k));
  1214. s2:=LowerCase(Copy(s2,1,k-1));
  1215. Sec:=TFPCMakeSection(Section[s2]);
  1216. if assigned(Sec) then
  1217. s2:=Sec[s3]
  1218. else
  1219. s2:='';
  1220. end
  1221. else
  1222. s2:=Variables[s2];
  1223. Insert(s2,s,1);
  1224. end;
  1225. until false;
  1226. Result:=Result+Copy(s,1,j-1);
  1227. Delete(s,1,j-1);
  1228. end;
  1229. var
  1230. s1 : string;
  1231. begin
  1232. //writeln('S: ',s);
  1233. s1:=s;
  1234. Result:=GetVar(s1,#0);
  1235. //writeln('R: ',result);
  1236. end;
  1237. function TFPCMake.GetVariable(const inivar:string;dosubst:boolean):string;
  1238. var
  1239. Sec : TFPCMakeSection;
  1240. Dic : TKeyValue;
  1241. i : integer;
  1242. begin
  1243. Result:='';
  1244. i:=Pos('_',inivar);
  1245. if i<>0 then
  1246. begin
  1247. Sec:=TFPCMakeSection(FSections[Copy(Inivar,1,i-1)]);
  1248. if assigned(Sec) then
  1249. begin
  1250. if not assigned(Sec.Dictionary) then
  1251. Sec.ParseIni;
  1252. Dic:=TKeyValue(Sec.Dictionary);
  1253. Result:=Dic[Copy(IniVar,i+1,Length(IniVar)-i)];
  1254. end
  1255. else
  1256. exit;
  1257. end
  1258. else
  1259. Result:=Variables[IniVar];
  1260. { Substition asked ? }
  1261. if dosubst then
  1262. Result:=SubstVariables(Result);
  1263. end;
  1264. function TFPCMake.SetVariable(const inivar,value:string;add:boolean):string;
  1265. var
  1266. Sec : TFPCMakeSection;
  1267. P : TKeyValueItem;
  1268. i : integer;
  1269. tempval,key : string;
  1270. begin
  1271. Result:='';
  1272. i:=Pos('_',inivar);
  1273. if i<>0 then
  1274. begin
  1275. Sec:=TFPCMakeSection(FSections[Copy(Inivar,1,i-1)]);
  1276. if Sec=nil then
  1277. Sec:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.CreateKeyValue(Copy(Inivar,1,i-1))));
  1278. key:=Copy(IniVar,i+1,Length(IniVar)-i);
  1279. p:=TKeyValueItem(Sec.Dictionary.Search(Key));
  1280. if assigned(p) then
  1281. begin
  1282. if Add then
  1283. AddToken(p.FValue,Value,' ')
  1284. else
  1285. p.Value:=Value;
  1286. end
  1287. else
  1288. TKeyValue(Sec.Dictionary).Add(key,value);
  1289. end
  1290. else
  1291. begin
  1292. if Add then
  1293. begin
  1294. tempval:=Variables[IniVar];
  1295. AddToken(tempval,Value,' ');
  1296. Variables[IniVar]:=tempval;
  1297. end
  1298. else
  1299. Variables[IniVar]:=Value;
  1300. end;
  1301. end;
  1302. procedure TFPCMake.ParseSec(p:TDictionaryItem);
  1303. begin
  1304. TFPCMakeSection(p).ParseIni;
  1305. end;
  1306. procedure TFPCMake.PrintSec(p:TDictionaryItem);
  1307. var
  1308. i : integer;
  1309. begin
  1310. with TFPCMakeSection(p) do
  1311. begin
  1312. Verbose(FPCMakeDebug,'['+Name+']');
  1313. if assigned(FList) then
  1314. begin
  1315. Verbose(FPCMakeDebug,' List:');
  1316. for i:=0 to FList.Count-1 do
  1317. Verbose(FPCMakeDebug,' "'+FList[i]+'"');
  1318. if assigned(FDictionary) then
  1319. Verbose(FPCMakeDebug,'');
  1320. end;
  1321. if assigned(FDictionary) then
  1322. begin
  1323. Verbose(FPCMakeDebug,' Dictionary:');
  1324. FDictionary.Foreach(@PrintDic);
  1325. end;
  1326. end;
  1327. end;
  1328. procedure TFPCMake.PrintDic(p:TDictionaryItem);
  1329. begin
  1330. with TKeyValueItem(p) do
  1331. begin
  1332. Verbose(FPCMakeDebug,' '+name+' = "'+value+'"');
  1333. end;
  1334. end;
  1335. procedure TFPCMake.Print;
  1336. begin
  1337. { global variables }
  1338. Verbose(FPCMakeDebug,'[global variables]');
  1339. Verbose(FPCMakeDebug,' Dictionary:');
  1340. Variables.Foreach(@PrintDic);
  1341. { sections }
  1342. FSections.Foreach(@PrintSec);
  1343. end;
  1344. function TFPCMake.GetSec(const AName:string):TDictionaryItem;
  1345. begin
  1346. GetSec:=FSections.Search(AName);
  1347. end;
  1348. end.
  1349. {
  1350. $Log$
  1351. Revision 1.27 2002-10-07 18:41:02 peter
  1352. * support mainpackage/subpackage. This allows to use things like
  1353. gnome1/gconf as required package
  1354. Revision 1.26 2002/09/07 15:40:31 peter
  1355. * old logs removed and tabs fixed
  1356. Revision 1.25 2002/07/30 13:18:42 marco
  1357. * OpenBSD fixes
  1358. Revision 1.24 2002/06/01 18:39:15 marco
  1359. * Renamefest
  1360. Revision 1.23 2002/03/15 11:37:46 armin
  1361. + Added netware target
  1362. Revision 1.22 2002/01/29 22:00:22 peter
  1363. * load package section first before setting globals
  1364. * fixed buildunit
  1365. Revision 1.21 2002/01/29 17:48:53 peter
  1366. * packages splitted to base and extra
  1367. Revision 1.20 2002/01/27 21:42:35 peter
  1368. * -r option to process target dirs also
  1369. * default changed to build only for current target
  1370. * removed auto building of required packages
  1371. * removed makefile target because it causes problems with
  1372. an internal rule of make
  1373. Revision 1.19 2002/01/06 21:50:04 peter
  1374. * lcl updates
  1375. * small optimizes for package check
  1376. }