fpcmmain.pp 44 KB

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