fpcmmain.pp 49 KB

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