fpcmmain.pp 48 KB

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