2
0

fpcmmain.pp 45 KB

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