fpcmmain.pp 46 KB

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