fpcmmain.pp 46 KB

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