fpcmmain.pp 41 KB

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