fpcmmain.pp 49 KB

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