fpcmmain.pp 46 KB

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