fpcmmain.pp 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558
  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. { Add some default variables like FPCDIR, UNITSDIR }
  564. AddFPCDefaultVariables;
  565. { Load LCL code ? }
  566. s:=GetVariable('require_packages',true);
  567. if pos('lcl',s)>0 then
  568. begin
  569. FUsesLCL:=true;
  570. AddLCLDefaultVariables;
  571. end;
  572. { Show globals }
  573. Verbose(FPCMakeDebug,s_globals);
  574. Variables.Foreach(@PrintDic);
  575. { Load package section }
  576. LoadPackageSection;
  577. LoadRequireSection;
  578. end;
  579. procedure TFPCMake.Verbose(lvl:TFPCMakeVerbose;const s:string);
  580. begin
  581. writeln(VerboseIdent,s);
  582. end;
  583. procedure TFPCMake.SetTargets(const s:string);
  584. var
  585. hslst : string;
  586. hs : string;
  587. t : TTarget;
  588. begin
  589. FIncludeTargets:=[];
  590. hslst:=s;
  591. repeat
  592. hs:=LowerCase(GetToken(hslst,','));
  593. if hs='' then
  594. break;
  595. { target 'all' includes all targets }
  596. if hs='all' then
  597. begin
  598. for t:=low(TTarget) to high(TTarget) do
  599. include(FIncludeTargets,t);
  600. break;
  601. end;
  602. for t:=low(TTarget) to high(TTarget) do
  603. if hs=TargetStr[t] then
  604. include(FIncludeTargets,t);
  605. until false;
  606. if FIncludeTargets=[] then
  607. raise Exception.Create(s_no_targets_set)
  608. else
  609. begin
  610. hs:='';
  611. for t:=low(TTarget) to high(TTarget) do
  612. if t in FIncludeTargets then
  613. AddToken(hs,TargetStr[t],' ');
  614. Verbose(FPCMakeDebug,Format(s_targets_info,[hs]));
  615. end;
  616. end;
  617. procedure TFPCMake.LoadPackageSection;
  618. var
  619. hs,s : string;
  620. t : TTarget;
  621. begin
  622. { Get package info from package section }
  623. FPackageSec:=TFPCMakeSection(FSections['package']);
  624. if FPackageSec=nil then
  625. exit;
  626. { Parse the section to key=value pairs }
  627. FPackageSec.ParseIni;
  628. { Are we a subpart of a package, then load that package }
  629. s:=FPackageSec['main'];
  630. if s<>'' then
  631. begin
  632. SetVariable('package_name',s,false);
  633. FPackageName:=s;
  634. end
  635. else
  636. begin
  637. { mandatory name }
  638. FPackageName:=FPackageSec['name'];
  639. if FPackageName='' then
  640. Raise Exception.Create(s_no_package_name);
  641. { mandatory version }
  642. FPackageVersion:=FPackageSec['version'];
  643. if FPackageVersion='' then
  644. Raise Exception.Create(s_no_package_version);
  645. FIsPackage:=true;
  646. { optional targets }
  647. FPackageTargets:='';
  648. s:=LowerCase(FPackageSec['targets']);
  649. repeat
  650. hs:=GetToken(s,' ');
  651. if hs='' then
  652. break;
  653. for t:=low(TTarget) to high(TTarget) do
  654. if hs=TargetStr[t] then
  655. begin
  656. AddToken(FPackageTargets,hs,' ');
  657. break;
  658. end;
  659. until false;
  660. { Set the ExportSec }
  661. FExportSec:=TFPCMakeSection(FSections[Lowercase(FPackageName)]);
  662. end;
  663. end;
  664. procedure TFPCMake.CreateExportSection;
  665. var
  666. t : TTarget;
  667. begin
  668. { Don't create a section twice }
  669. if FExportSec<>nil then
  670. exit;
  671. { Look if we've already an own section, else create a new
  672. key-value section }
  673. FExportSec:=TFPCMakeSection(FSections[LowerCase(FPackageName)]);
  674. if FExportSec=nil then
  675. FExportSec:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.CreateKeyValue(LowerCase(FPackageName))));
  676. { Add default the values to the export section }
  677. FExportSec.AddKey('name',FPackageName);
  678. FExportSec.AddKey('version',FPackageVersion);
  679. { Add required packages }
  680. for t:=low(TTarget) to high(TTarget) do
  681. FExportSec.AddKey('require'+TargetSuffix[t],FPackageSec['require'+TargetSuffix[t]]);
  682. { Unit dir }
  683. {FExportSec.AddKey('unitdir','$(UNITSDIR)/'+Lowercase(PackageName));}
  684. end;
  685. procedure TFPCMake.LoadRequiredPackage(t:TTarget;const ReqName,ReqVersion:string);
  686. function TryFile(const fn:string):boolean;
  687. var
  688. ReqFPCMake : TFPCMake;
  689. begin
  690. TryFile:=false;
  691. if FileExists(fn) then
  692. begin
  693. VerboseIdent:=VerboseIdent+' ';
  694. Verbose(FPCMakeDebug,'Package '+ReqName+': '+fn);
  695. ReqFPCMake:=TFPCMake.Create(fn);
  696. ReqFPCMake.LoadSections;
  697. ReqFPCMake.LoadPackageSection;
  698. { Check package name and version }
  699. if LowerCase(ReqFPCMake.PackageName)<>ReqName then
  700. raise Exception.Create(Format(s_wrong_package_name,[ReqName,LowerCase(ReqFPCMake.PackageName)]));
  701. if (ReqVersion<>'') and (ReqFPCMake.PackageVersion<ReqVersion) then
  702. raise Exception.Create(Format(s_wrong_package_version,[ReqVersion,ReqFPCMake.PackageVersion]));
  703. { First load the requirements of this package }
  704. LoadRequires(t,ReqFPCMake);
  705. { Get a copy of the package section }
  706. CopySection(ReqFPCMake.PackageSec,ReqName+'_package');
  707. { Get a copy of the export section }
  708. CopySection(ReqFPCMake.ExportSec,ReqName);
  709. { Get a copy of the require section }
  710. CopySection(TFPCMakeSection(ReqFPCMake['require']),ReqName+'_require');
  711. { Free }
  712. ReqFPCMake.Free;
  713. Delete(VerboseIdent,1,2);
  714. TryFile:=true;
  715. end;
  716. end;
  717. var
  718. s : string;
  719. begin
  720. { Force the current target }
  721. SetVariable('TARGET',TargetStr[t],false);
  722. { Check for Makefile.fpc }
  723. s:=SubstVariables('$(addsuffix /'+ReqName+'/Makefile.fpc,$(FPCDIR)) $(addsuffix /'+ReqName+'/Makefile.fpc,$(PACKAGESDIR)) $(addsuffix /'+ReqName+'/Makefile.fpc,$(REQUIRE_PACKAGESDIR))');
  724. Verbose(FPCMakeDebug,'Package "'+ReqName+'": Looking for Makefile.fpc: "'+s+'"');
  725. s:=SubstVariables('$(firstword $(wildcard '+s+'))');
  726. if TryFile(s) then
  727. exit;
  728. { Check for Package.fpc }
  729. s:=SubstVariables('$(addsuffix /'+ReqName+'/Package.fpc,$(FPCDIR)) $(addsuffix /'+ReqName+'/Package.fpc,$(UNITSDIR)) $(addsuffix /'+ReqName+'/Package.fpc,$(REQUIRE_UNITSDIR))');
  730. Verbose(FPCMakeDebug,'Package "'+ReqName+'": Looking for Package.fpc: "'+s+'"');
  731. s:=SubstVariables('$(firstword $(wildcard '+s+'))');
  732. if TryFile(s) then
  733. exit;
  734. Raise Exception.Create(Format(s_package_not_found,[TargetStr[t],Reqname]));
  735. end;
  736. procedure TFPCMake.LoadRequiredDir(t:TTarget;const MainPack,currdir,subdir:string);
  737. var
  738. ReqFPCMake : TFPCMake;
  739. s : string;
  740. begin
  741. VerboseIdent:=VerboseIdent+' ';
  742. s:=currdir+subdir;
  743. Verbose(FPCMakeDebug,'Subdir: '+s+'/Makefile.fpc');
  744. if not FileExists(s+'/Makefile.fpc') then
  745. begin
  746. { give better error what is wrong }
  747. if not PathExists(s) then
  748. Raise Exception.Create(Format(s_directory_not_found,[s]))
  749. else
  750. Raise Exception.Create(Format(s_makefilefpc_not_found,[s]));
  751. end;
  752. { Process Makefile.fpc }
  753. ReqFPCMake:=TFPCMake.Create(currdir+subdir+'/Makefile.fpc');
  754. ReqFPCMake.LoadSections;
  755. ReqFPCMake.LoadPackageSection;
  756. { Are we a subpackage? }
  757. if (ReqFPCMake.GetVariable('package_name',false)<>MainPack) then
  758. begin
  759. ReqFPCMake.Free;
  760. Delete(VerboseIdent,1,2);
  761. exit;
  762. end;
  763. { Load the requirements of this package }
  764. LoadRequires(t,ReqFPCMake);
  765. { Add the current requirements to our parents requirements }
  766. s:=Trim(ReqFPCMake.GetVariable('require_packages',true)+' '+ReqFPCMake.GetVariable('require_packages'+targetsuffix[t],true));
  767. SetVariable('require_packages'+targetsuffix[t],s,true);
  768. if ReqFPCMake.GetVariable('require_libc',false)<>'' then
  769. SetVariable('require_libc','y',false);
  770. { Free }
  771. ReqFPCMake.Free;
  772. Delete(VerboseIdent,1,2);
  773. end;
  774. procedure TFPCMake.LoadRequires(t:Ttarget;FromFPCMake:TFPCMake);
  775. var
  776. s,
  777. ReqDir,
  778. ReqName,
  779. ReqVersion : string;
  780. i,j : integer;
  781. begin
  782. { packages }
  783. s:=Trim(FromFPCMake.GetVariable('require_packages',true)+' '+FromFPCMake.GetVariable('require_packages'+TargetSuffix[t],true));
  784. Verbose(FPCMakeDebug,'Required packages for '+TargetStr[t]+': '+s);
  785. repeat
  786. reqname:=GetToken(s,' ');
  787. if reqname='' then
  788. break;
  789. i:=Pos('(',ReqName);
  790. if i>0 then
  791. begin
  792. j:=Pos(')',ReqName);
  793. if (i=1) or (j=0) then
  794. Raise Exception.Create(Format(s_err_require_format,[ReqName]));
  795. ReqVersion:=Copy(ReqName,i+1,j-i-1);
  796. ReqName:=Copy(ReqName,1,i-1);
  797. end
  798. else
  799. ReqVersion:='';
  800. { We only use lowercase names }
  801. ReqName:=Lowercase(ReqName);
  802. { Already loaded ? }
  803. if (RequireList[t].IndexOf(ReqName)=-1) then
  804. begin
  805. LoadRequiredPackage(t,ReqName,ReqVersion);
  806. RequireList[t].Add(ReqName);
  807. end;
  808. until false;
  809. { sub dirs }
  810. s:=FromFPCMake.GetVariable('target_dirs',true)+' '+FromFPCMake.GetVariable('target_dirs'+TargetSuffix[t],true);
  811. Verbose(FPCMakeDebug,'Required dirs for '+TargetStr[t]+': '+s);
  812. repeat
  813. reqdir:=GetToken(s,' ');
  814. if reqdir='' then
  815. break;
  816. LoadRequiredDir(t,FromFPCMake.FPackageName,ExtractFilePath(FromFPCMake.FFileName),ReqDir)
  817. until false;
  818. end;
  819. procedure TFPCMake.LoadRequireSection;
  820. function CheckVar(const s:string):boolean;
  821. var
  822. t : ttarget;
  823. begin
  824. result:=false;
  825. if GetVariable(s,false)<>'' then
  826. begin
  827. result:=true;
  828. exit;
  829. end;
  830. for t:=low(ttarget) to high(ttarget) do
  831. if t in FIncludeTargets then
  832. begin
  833. if GetVariable(s+targetsuffix[t],false)<>'' then
  834. begin
  835. result:=true;
  836. exit;
  837. end;
  838. end;
  839. end;
  840. var
  841. s : string;
  842. t : ttarget;
  843. begin
  844. { Check FPCMake version }
  845. s:=GetVariable('require_fpcmake',false);
  846. if (s>version) then
  847. raise Exception.Create(Format(s_fpcmake_version_required,[s]));
  848. { Maybe add an implicit rtl dependency if there is something
  849. to compile }
  850. s:=GetVariable('require_packages',false);
  851. if (GetVariable('require_nortl',false)='') and
  852. (CheckVar('target_programs') or
  853. CheckVar('target_units') or
  854. CheckVar('target_examples')) and
  855. (Pos('rtl(',s)=0) then
  856. begin
  857. s:='rtl '+s;
  858. SetVariable('require_packages',s,false);
  859. end;
  860. { Load recursively all required packages starting with this Makefile.fpc }
  861. for t:=low(TTarget) to high(TTarget) do
  862. if t in FIncludeTargets then
  863. LoadRequires(t,self);
  864. end;
  865. function TFPCMake.GetTargetRequires(t:TTarget):TStringList;
  866. var
  867. ReqSec : TFPCMakeSection;
  868. ReqList : TStringList;
  869. procedure AddReqSec(t:TTarget;Sec:TFPCMakeSection);
  870. var
  871. s,
  872. ReqName : string;
  873. RSec : TFPCMakeSection;
  874. i : integer;
  875. begin
  876. s:=Sec['packages']+' '+Sec['packages'+TargetSuffix[t]];
  877. repeat
  878. ReqName:=GetToken(s,' ');
  879. if ReqName='' then
  880. break;
  881. i:=Pos('(',ReqName);
  882. if i>0 then
  883. ReqName:=Copy(ReqName,1,i-1);
  884. { We only use lowercase names }
  885. ReqName:=Lowercase(ReqName);
  886. { Already loaded ? }
  887. if (ReqList.IndexOf(ReqName)=-1) then
  888. begin
  889. RSec:=TFPCMakeSection(FSections[ReqName+'_require']);
  890. if assigned(RSec) then
  891. AddReqSec(t,RSec);
  892. ReqList.Add(ReqName);
  893. end;
  894. until false;
  895. end;
  896. begin
  897. ReqList:=TStringList.Create;
  898. ReqSec:=TFPCMakeSection(FSections['require']);
  899. if assigned(ReqSec) then
  900. AddReqSec(t,ReqSec);
  901. GetTargetRequires:=ReqList;
  902. end;
  903. function TFPCMake.CheckLibcRequire:boolean;
  904. var
  905. i : integer;
  906. RSec : TFPCMakeSection;
  907. t : ttarget;
  908. begin
  909. Result:=false;
  910. if GetVariable('require_libc',false)<>'' then
  911. begin
  912. Result:=true;
  913. exit;
  914. end;
  915. for t:=low(ttarget) to high(ttarget) do
  916. if t in FIncludeTargets then
  917. begin
  918. for i:=0 to RequireList[t].Count-1 do
  919. begin
  920. RSec:=TFPCMakeSection(FSections[RequireList[t][i]+'_require']);
  921. if assigned(RSec) then
  922. begin
  923. if RSec['libc']<>'' then
  924. begin
  925. Result:=true;
  926. exit;
  927. end;
  928. end;
  929. end;
  930. end;
  931. end;
  932. procedure TFPCMake.AddFPCDefaultVariables;
  933. var
  934. hs,s : string;
  935. begin
  936. { Already set FPCDIR }
  937. hs:='';
  938. s:=GetVariable('FPCDIR',false);
  939. if s<>'' then
  940. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  941. { Load from environment }
  942. if hs='' then
  943. begin
  944. s:=GetEnv('FPCDIR');
  945. if s<>'' then
  946. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  947. end;
  948. { default_fpcdir }
  949. if hs='' then
  950. begin
  951. s:=GetVariable('default_fpcdir',true);
  952. { add the current subdir to relative paths }
  953. if s<>'' then
  954. begin
  955. {$ifdef UNIX}
  956. if (s[1]<>'/') then
  957. {$else}
  958. if (length(s)>2) and (s[2]<>':') then
  959. {$endif}
  960. s:=ExtractFilePath(FFileName)+s;
  961. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  962. end
  963. end;
  964. { OS defaults }
  965. if hs='' then
  966. begin
  967. {$ifdef UNIX}
  968. {$ifndef NO_UNIX_UNIT}
  969. if FileExists('/usr/local/bin/ppc386') then
  970. begin
  971. s:=ExtractFilePath(ReadLink('/usr/local/bin/ppc386'));
  972. if s<>'' then
  973. begin
  974. if s[length(s)]='/' then
  975. delete(s,length(s),1);
  976. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  977. end;
  978. end;
  979. if hs='' then
  980. begin
  981. if FileExists('/usr/bin/ppc386') then
  982. begin
  983. s:=ExtractFilePath(ReadLink('/usr/bin/ppc386'));
  984. if s<>'' then
  985. begin
  986. if s[length(s)]='/' then
  987. delete(s,length(s),1);
  988. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  989. end;
  990. end;
  991. end;
  992. {$endif}
  993. {$else UNIX}
  994. hs:=ExtractFilePath(FSearch('ppc386.exe',getenv('PATH')));
  995. if hs<>'' then
  996. begin
  997. s:=hs+'/..';
  998. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  999. if hs='' then
  1000. begin
  1001. s:=s+'/..';
  1002. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  1003. end;
  1004. end;
  1005. if hs='' then
  1006. s:='c:/pp';
  1007. {$endif UNIX}
  1008. end;
  1009. SetVariable('FPCDIR',s,false);
  1010. { PACKAGESDIR }
  1011. if GetVariable('PACKAGESDIR',false)='' then
  1012. SetVariable('PACKAGESDIR','$(FPCDIR)/packages/base $(FPCDIR)/packages/extra',false);
  1013. { UNITSDIR }
  1014. if GetVariable('UNITSDIR',false)='' then
  1015. SetVariable('UNITSDIR','$(FPCDIR)/units/$(TARGET)',false);
  1016. { BASEDIR }
  1017. SetVariable('BASEDIR',GetCurrentDir,false);
  1018. end;
  1019. procedure TFPCMake.AddLCLDefaultVariables;
  1020. var
  1021. hs,s : string;
  1022. begin
  1023. { Already set LCLDIR }
  1024. hs:=SubstVariables('$(wildcard $(LCLDIR)/units)');
  1025. { Load from environment }
  1026. if hs='' then
  1027. begin
  1028. SetVariable('LCLDIR',GetEnv('LCLDIR'),false);
  1029. hs:=SubstVariables('$(wildcard $(LCLDIR)/units)');
  1030. end;
  1031. { default_lcldir }
  1032. if hs='' then
  1033. begin
  1034. s:=GetVariable('default_lcldir',true);
  1035. { add the current subdir to relative paths }
  1036. if s<>'' then
  1037. begin
  1038. {$ifdef UNIX}
  1039. if (s[1]<>'/') then
  1040. {$else}
  1041. if (length(s)>2) and (s[2]<>':') then
  1042. {$endif}
  1043. s:=ExtractFilePath(FFileName)+s;
  1044. SetVariable('LCLDIR',s,false);
  1045. hs:=SubstVariables('$(wildcard $(LCLDIR)/units)');
  1046. end
  1047. end;
  1048. { OS defaults }
  1049. if hs='' then
  1050. begin
  1051. hs:=SubstVariables('$(subst /units,,$(firstword $(wildcard $(addsuffix /units,$(BASEDIR)/lcl $(BASEDIR)))))');
  1052. if hs<>'' then
  1053. SetVariable('LCLDIR',hs,false);
  1054. end;
  1055. {$ifdef UNIX}
  1056. if hs='' then
  1057. begin
  1058. hs:=SubstVariables('$(subst /units,,$(firstword $(wildcard $(addsuffix /lib/lazarus/units,/usr/local /usr))))');
  1059. if hs<>'' then
  1060. SetVariable('LCLDIR',hs,false);
  1061. end;
  1062. {$endif UNIX}
  1063. { Add components to PACKAGESDIR }
  1064. SetVariable('PACKAGESDIR',SubstVariables('$(wildcard $(LCLDIR)/.. $(LCLDIR)/../components $(LCLDIR)/components)'),true);
  1065. end;
  1066. function TFPCMake.SubstVariables(const s:string):string;
  1067. function Expect(var s:string;c:char):boolean;
  1068. begin
  1069. if (s<>'') and (s[1]=c) then
  1070. begin
  1071. Delete(s,1,1);
  1072. Result:=true;
  1073. end
  1074. else
  1075. begin
  1076. Verbose(FPCMakeError,'Error "'+c+'" expected');
  1077. Result:=false;
  1078. end;
  1079. end;
  1080. function GetVar(var s:string;untilc:char):string;
  1081. var
  1082. i,j,k : integer;
  1083. first : boolean;
  1084. func,
  1085. tok,s1,s2,s3 : string;
  1086. Sec : TFPCMakeSection;
  1087. begin
  1088. Result:='';
  1089. repeat
  1090. j:=Pos(untilc,s);
  1091. if j=0 then
  1092. j:=Length(s)+1;
  1093. i:=Pos('$(',s);
  1094. if (j<i) or (i=0) then
  1095. break;
  1096. Result:=Result+Copy(s,1,i-1);
  1097. Delete(s,1,i+1);
  1098. { Maybe Function ? }
  1099. j:=Pos(')',s);
  1100. if j=0 then
  1101. j:=Length(s)+1;
  1102. i:=Pos(' ',s);
  1103. if i=0 then
  1104. i:=Length(s)+1;
  1105. if i<j then
  1106. begin
  1107. { It's a function }
  1108. Func:=Copy(s,1,i-1);
  1109. //writeln('func: ',func);
  1110. { $(wildcard <list>) }
  1111. if Func='wildcard' then
  1112. begin
  1113. Delete(s,1,9);
  1114. s1:=GetVar(s,')');
  1115. Expect(s,')');
  1116. first:=true;
  1117. repeat
  1118. tok:=GetToken(s1,' ');
  1119. if tok='' then
  1120. break;
  1121. if PathOrFileExists(tok) then
  1122. begin
  1123. if not first then
  1124. Result:=Result+' '
  1125. else
  1126. first:=false;
  1127. Result:=Result+tok;
  1128. end;
  1129. until false;
  1130. end
  1131. { $(addprefix <suffix>,<list>) }
  1132. else if Func='addprefix' then
  1133. begin
  1134. Delete(s,1,10);
  1135. s1:=GetVar(s,',');
  1136. if Expect(s,',') then
  1137. begin
  1138. s2:=GetVar(s,')');
  1139. Expect(s,')');
  1140. end;
  1141. first:=true;
  1142. repeat
  1143. tok:=GetToken(s2,' ');
  1144. if tok='' then
  1145. break;
  1146. if not first then
  1147. Result:=Result+' '
  1148. else
  1149. first:=false;
  1150. Result:=Result+s1+tok;
  1151. until false;
  1152. end
  1153. { $(addsuffix <suffix>,<list>) }
  1154. else if Func='addsuffix' then
  1155. begin
  1156. Delete(s,1,10);
  1157. s1:=GetVar(s,',');
  1158. if Expect(s,',') then
  1159. begin
  1160. s2:=GetVar(s,')');
  1161. Expect(s,')');
  1162. end;
  1163. first:=true;
  1164. repeat
  1165. tok:=GetToken(s2,' ');
  1166. if tok='' then
  1167. break;
  1168. if not first then
  1169. Result:=Result+' '
  1170. else
  1171. first:=false;
  1172. Result:=Result+tok+s1;
  1173. until false;
  1174. end
  1175. { $(firstword <list>) }
  1176. else if Func='firstword' then
  1177. begin
  1178. Delete(s,1,10);
  1179. s1:=GetVar(s,')');
  1180. Expect(s,')');
  1181. Result:=GetToken(s1,' ');
  1182. end
  1183. { $(subst <oldpat>,<newpat>,<string>) }
  1184. else if Func='subst' then
  1185. begin
  1186. Delete(s,1,6);
  1187. s1:=GetVar(s,',');
  1188. if Expect(s,',') then
  1189. begin
  1190. s2:=GetVar(s,',');
  1191. if Expect(s,',') then
  1192. begin
  1193. s3:=GetVar(s,')');
  1194. Expect(s,')');
  1195. end;
  1196. end;
  1197. Result:=StringReplace(s3,s1,s2,[rfReplaceAll]);
  1198. end;
  1199. end
  1200. else
  1201. begin
  1202. s2:=Copy(s,1,j-1);
  1203. Delete(s,1,j);
  1204. k:=pos('_',s2);
  1205. if k>0 then
  1206. begin
  1207. s3:=LowerCase(Copy(s2,k+1,Length(s2)-k));
  1208. s2:=LowerCase(Copy(s2,1,k-1));
  1209. Sec:=TFPCMakeSection(Section[s2]);
  1210. if assigned(Sec) then
  1211. s2:=Sec[s3]
  1212. else
  1213. s2:='';
  1214. end
  1215. else
  1216. s2:=Variables[s2];
  1217. Insert(s2,s,1);
  1218. end;
  1219. until false;
  1220. Result:=Result+Copy(s,1,j-1);
  1221. Delete(s,1,j-1);
  1222. end;
  1223. var
  1224. s1 : string;
  1225. begin
  1226. //writeln('S: ',s);
  1227. s1:=s;
  1228. Result:=GetVar(s1,#0);
  1229. //writeln('R: ',result);
  1230. end;
  1231. function TFPCMake.GetVariable(const inivar:string;dosubst:boolean):string;
  1232. var
  1233. Sec : TFPCMakeSection;
  1234. Dic : TKeyValue;
  1235. i : integer;
  1236. begin
  1237. Result:='';
  1238. i:=Pos('_',inivar);
  1239. if i<>0 then
  1240. begin
  1241. Sec:=TFPCMakeSection(FSections[Copy(Inivar,1,i-1)]);
  1242. if assigned(Sec) then
  1243. begin
  1244. if not assigned(Sec.Dictionary) then
  1245. Sec.ParseIni;
  1246. Dic:=TKeyValue(Sec.Dictionary);
  1247. Result:=Dic[Copy(IniVar,i+1,Length(IniVar)-i)];
  1248. end
  1249. else
  1250. exit;
  1251. end
  1252. else
  1253. Result:=Variables[IniVar];
  1254. { Substition asked ? }
  1255. if dosubst then
  1256. Result:=SubstVariables(Result);
  1257. end;
  1258. function TFPCMake.SetVariable(const inivar,value:string;add:boolean):string;
  1259. var
  1260. Sec : TFPCMakeSection;
  1261. P : TKeyValueItem;
  1262. i : integer;
  1263. tempval,key : string;
  1264. begin
  1265. Result:='';
  1266. i:=Pos('_',inivar);
  1267. if i<>0 then
  1268. begin
  1269. Sec:=TFPCMakeSection(FSections[Copy(Inivar,1,i-1)]);
  1270. if Sec=nil then
  1271. Sec:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.CreateKeyValue(Copy(Inivar,1,i-1))));
  1272. key:=Copy(IniVar,i+1,Length(IniVar)-i);
  1273. p:=TKeyValueItem(Sec.Dictionary.Search(Key));
  1274. if assigned(p) then
  1275. begin
  1276. if Add then
  1277. AddToken(p.FValue,Value,' ')
  1278. else
  1279. p.Value:=Value;
  1280. end
  1281. else
  1282. TKeyValue(Sec.Dictionary).Add(key,value);
  1283. end
  1284. else
  1285. begin
  1286. if Add then
  1287. begin
  1288. tempval:=Variables[IniVar];
  1289. AddToken(tempval,Value,' ');
  1290. Variables[IniVar]:=tempval;
  1291. end
  1292. else
  1293. Variables[IniVar]:=Value;
  1294. end;
  1295. end;
  1296. procedure TFPCMake.ParseSec(p:TDictionaryItem);
  1297. begin
  1298. TFPCMakeSection(p).ParseIni;
  1299. end;
  1300. procedure TFPCMake.PrintSec(p:TDictionaryItem);
  1301. var
  1302. i : integer;
  1303. begin
  1304. with TFPCMakeSection(p) do
  1305. begin
  1306. Verbose(FPCMakeDebug,'['+Name+']');
  1307. if assigned(FList) then
  1308. begin
  1309. Verbose(FPCMakeDebug,' List:');
  1310. for i:=0 to FList.Count-1 do
  1311. Verbose(FPCMakeDebug,' "'+FList[i]+'"');
  1312. if assigned(FDictionary) then
  1313. Verbose(FPCMakeDebug,'');
  1314. end;
  1315. if assigned(FDictionary) then
  1316. begin
  1317. Verbose(FPCMakeDebug,' Dictionary:');
  1318. FDictionary.Foreach(@PrintDic);
  1319. end;
  1320. end;
  1321. end;
  1322. procedure TFPCMake.PrintDic(p:TDictionaryItem);
  1323. begin
  1324. with TKeyValueItem(p) do
  1325. begin
  1326. Verbose(FPCMakeDebug,' '+name+' = "'+value+'"');
  1327. end;
  1328. end;
  1329. procedure TFPCMake.Print;
  1330. begin
  1331. { global variables }
  1332. Verbose(FPCMakeDebug,'[global variables]');
  1333. Verbose(FPCMakeDebug,' Dictionary:');
  1334. Variables.Foreach(@PrintDic);
  1335. { sections }
  1336. FSections.Foreach(@PrintSec);
  1337. end;
  1338. function TFPCMake.GetSec(const AName:string):TDictionaryItem;
  1339. begin
  1340. GetSec:=FSections.Search(AName);
  1341. end;
  1342. end.
  1343. {
  1344. $Log$
  1345. Revision 1.21 2002-01-29 17:48:53 peter
  1346. * packages splitted to base and extra
  1347. Revision 1.20 2002/01/27 21:42:35 peter
  1348. * -r option to process target dirs also
  1349. * default changed to build only for current target
  1350. * removed auto building of required packages
  1351. * removed makefile target because it causes problems with
  1352. an internal rule of make
  1353. Revision 1.19 2002/01/06 21:50:04 peter
  1354. * lcl updates
  1355. * small optimizes for package check
  1356. Revision 1.18 2001/12/26 21:02:00 peter
  1357. * little support for lcl and lazarus, but not yet working
  1358. Revision 1.17 2001/12/15 04:16:57 carl
  1359. + clean support for QNX / BeOS and SunOS targets
  1360. Revision 1.16 2001/12/11 23:01:56 carl
  1361. + Added SunOS and QNX targets
  1362. Revision 1.15 2001/10/14 21:38:32 peter
  1363. * cross compiling support
  1364. Revision 1.14 2001/09/29 19:47:50 carl
  1365. * make it work for BeOS
  1366. Revision 1.13 2001/08/22 20:45:19 peter
  1367. * firstword added
  1368. * pathexist fix to include sysfile
  1369. Revision 1.12 2001/08/10 10:28:55 pierre
  1370. + netbsd target added
  1371. Revision 1.11 2001/08/02 20:50:29 peter
  1372. * -T<target> support
  1373. * better error reporting for not found dirs
  1374. * some cleanups and nicer strings
  1375. Revision 1.10 2001/07/31 22:02:32 peter
  1376. * install Package.fpc
  1377. Revision 1.9 2001/07/24 09:06:40 pierre
  1378. + added amiga and atari targets
  1379. Revision 1.8 2001/07/13 21:01:59 peter
  1380. * cygdrive support
  1381. * fixed cygwin detection
  1382. * fixed some duplicate and extraeous spaces
  1383. Revision 1.7 2001/06/04 21:42:57 peter
  1384. * Arguments added
  1385. * Start of Package.fpc creation
  1386. Revision 1.6 2001/06/02 19:20:24 peter
  1387. * beos target added
  1388. Revision 1.5 2001/02/22 21:11:24 peter
  1389. * fpcdir detection added
  1390. * fixed loading of variables in fpcmake itself
  1391. Revision 1.4 2001/02/05 20:44:56 peter
  1392. * variable substition like GNU Make. wildcard,addprefix,addsuffix
  1393. already implemented
  1394. Revision 1.3 2001/02/01 22:00:10 peter
  1395. * default.fpcdir is back
  1396. * subdir requirement checking works, but not very optimal yet as
  1397. it can load the same Makefile.fpc multiple times
  1398. Revision 1.2 2001/01/29 21:49:10 peter
  1399. * lot of updates
  1400. Revision 1.1 2001/01/24 21:59:36 peter
  1401. * first commit of new fpcmake
  1402. }