fpcmmain.pp 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385
  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. SLInput:=TStringList.Create;
  452. if assigned(FStream) then
  453. SLInput.LoadFromStream(FStream)
  454. else
  455. SLInput.LoadFromFile(FFileName);
  456. { Load Input into sections list }
  457. n:=SLInput.Count;
  458. i:=0;
  459. while (i<n) do
  460. begin
  461. s:=Trim(SLInput[i]);
  462. if (EmptyLines and (s='')) or
  463. ((s<>'') and not(s[1] in FCommentChars)) then
  464. begin
  465. { section start? }
  466. if (s<>'') and (s[1]='[') then
  467. begin
  468. j:=pos(']',s);
  469. if j=0 then
  470. raise Exception.Create(Format(s_err_section_start,[FFileName,i]));
  471. SecName:=Copy(s,2,j-2);
  472. CurrSec:=TFPCMakeSection(FSections[SecName]);
  473. if CurrSec=nil then
  474. CurrSec:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.Create(SecName)));
  475. end
  476. else
  477. begin
  478. if CurrSec=nil then
  479. raise Exception.Create(Format(s_err_no_section,[FFileName,i]));
  480. { Insert string without spaces stripped }
  481. CurrSec.AddLine(SLInput[i]);
  482. end;
  483. end;
  484. inc(i);
  485. end;
  486. finally
  487. SLInput.Free;
  488. end;
  489. end;
  490. function TFPCMake.CopySection(Sec:TFPCMakeSection;Secname:string):TFPCMakeSection;
  491. begin
  492. Result:=TFPCMakeSection(FSections[SecName]);
  493. if Sec=Nil then
  494. exit;
  495. { Clear old section or if not existing create new }
  496. if assigned(Result) then
  497. Result.Clear
  498. else
  499. Result:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.Create(SecName)));
  500. Sec.BuildIni;
  501. Result.List.AddStrings(Sec.List);
  502. Result.ParseIni;
  503. Sec.ParseIni;
  504. end;
  505. procedure TFPCMake.LoadMakefileFPC;
  506. begin
  507. LoadSections;
  508. { Parse all sections }
  509. FSections.Foreach(@ParseSec);
  510. { Add some default variables like FPCDIR, UNITSDIR }
  511. AddDefaultVariables;
  512. { Load package section }
  513. LoadPackageSection;
  514. LoadRequireSection;
  515. end;
  516. procedure TFPCMake.Verbose(lvl:TFPCMakeVerbose;const s:string);
  517. begin
  518. writeln(VerboseIdent,s);
  519. end;
  520. procedure TFPCMake.SetTargets(const s:string);
  521. var
  522. hslst : string;
  523. hs : string;
  524. t : TTarget;
  525. begin
  526. FIncludeTargets:=[];
  527. hslst:=s;
  528. repeat
  529. hs:=LowerCase(GetToken(hslst,','));
  530. if hs='' then
  531. break;
  532. for t:=low(TTarget) to high(TTarget) do
  533. if hs=TargetStr[t] then
  534. include(FIncludeTargets,t);
  535. until false;
  536. if FIncludeTargets=[] then
  537. raise Exception.Create(s_no_targets_set)
  538. else
  539. begin
  540. hs:='';
  541. for t:=low(TTarget) to high(TTarget) do
  542. if t in FIncludeTargets then
  543. AddToken(hs,TargetStr[t],' ');
  544. Verbose(FPCMakeDebug,Format(s_targets_info,[hs]));
  545. end;
  546. end;
  547. procedure TFPCMake.LoadPackageSection;
  548. var
  549. hs,s : string;
  550. t : TTarget;
  551. begin
  552. { Get package info from package section }
  553. FPackageSec:=TFPCMakeSection(FSections['package']);
  554. if FPackageSec=nil then
  555. exit;
  556. { Parse the section to key=value pairs }
  557. FPackageSec.ParseIni;
  558. { Are we a subpart of a package, then load that package }
  559. s:=FPackageSec['main'];
  560. if s<>'' then
  561. begin
  562. SetVariable('package_name',s,false);
  563. FPackageName:=s;
  564. end
  565. else
  566. begin
  567. { mandatory name }
  568. FPackageName:=FPackageSec['name'];
  569. if FPackageName='' then
  570. Raise Exception.Create(s_no_package_name);
  571. { mandatory version }
  572. FPackageVersion:=FPackageSec['version'];
  573. if FPackageVersion='' then
  574. Raise Exception.Create(s_no_package_version);
  575. FIsPackage:=true;
  576. { optional targets }
  577. FPackageTargets:='';
  578. s:=LowerCase(FPackageSec['targets']);
  579. repeat
  580. hs:=GetToken(s,' ');
  581. if hs='' then
  582. break;
  583. for t:=low(TTarget) to high(TTarget) do
  584. if hs=TargetStr[t] then
  585. begin
  586. AddToken(FPackageTargets,hs,' ');
  587. break;
  588. end;
  589. until false;
  590. { Set the ExportSec }
  591. FExportSec:=TFPCMakeSection(FSections[Lowercase(FPackageName)]);
  592. end;
  593. end;
  594. procedure TFPCMake.CreateExportSection;
  595. var
  596. t : TTarget;
  597. begin
  598. { Don't create a section twice }
  599. if FExportSec<>nil then
  600. exit;
  601. { Look if we've already an own section, else create a new
  602. key-value section }
  603. FExportSec:=TFPCMakeSection(FSections[LowerCase(FPackageName)]);
  604. if FExportSec=nil then
  605. FExportSec:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.CreateKeyValue(LowerCase(FPackageName))));
  606. { Add default the values to the export section }
  607. FExportSec.AddKey('name',FPackageName);
  608. FExportSec.AddKey('version',FPackageVersion);
  609. { Add required packages }
  610. for t:=low(TTarget) to high(TTarget) do
  611. FExportSec.AddKey('require'+TargetSuffix[t],FPackageSec['require'+TargetSuffix[t]]);
  612. { Unit dir }
  613. {FExportSec.AddKey('unitdir','$(UNITSDIR)/'+Lowercase(PackageName));}
  614. end;
  615. procedure TFPCMake.LoadRequiredPackage(t:TTarget;const ReqName,ReqVersion:string);
  616. function TryFile(const fn:string):boolean;
  617. var
  618. ReqFPCMake : TFPCMake;
  619. begin
  620. TryFile:=false;
  621. if FileExists(fn) then
  622. begin
  623. VerboseIdent:=VerboseIdent+' ';
  624. Verbose(FPCMakeDebug,'Package '+ReqName+': '+fn);
  625. ReqFPCMake:=TFPCMake.Create(fn);
  626. ReqFPCMake.LoadSections;
  627. ReqFPCMake.LoadPackageSection;
  628. { Check package name and version }
  629. if LowerCase(ReqFPCMake.PackageName)<>ReqName then
  630. raise Exception.Create(Format(s_wrong_package_name,[ReqName,LowerCase(ReqFPCMake.PackageName)]));
  631. if (ReqVersion<>'') and (ReqFPCMake.PackageVersion<ReqVersion) then
  632. raise Exception.Create(Format(s_wrong_package_version,[ReqVersion,ReqFPCMake.PackageVersion]));
  633. { First load the requirements of this package }
  634. LoadRequires(t,ReqFPCMake);
  635. { Get a copy of the package section }
  636. CopySection(ReqFPCMake.PackageSec,ReqName+'_package');
  637. { Get a copy of the export section }
  638. CopySection(ReqFPCMake.ExportSec,ReqName);
  639. { Get a copy of the require section }
  640. CopySection(TFPCMakeSection(ReqFPCMake['require']),ReqName+'_require');
  641. { Free }
  642. ReqFPCMake.Free;
  643. Delete(VerboseIdent,1,2);
  644. TryFile:=true;
  645. end;
  646. end;
  647. var
  648. s : string;
  649. begin
  650. { Force the current target }
  651. SetVariable('TARGET',TargetStr[t],false);
  652. { Check for Makefile.fpc }
  653. s:=SubstVariables('$(addsuffix /'+ReqName+'/Makefile.fpc,$(FPCDIR)) $(addsuffix /'+ReqName+'/Makefile.fpc,$(PACKAGESDIR)) $(addsuffix /'+ReqName+'/Makefile.fpc,$(REQUIRE_PACKAGESDIR))');
  654. Verbose(FPCMakeDebug,'Looking for Makefile.fpc: "'+s+'"');
  655. s:=SubstVariables('$(firstword $(wildcard '+s+'))');
  656. if TryFile(s) then
  657. exit;
  658. { Check for Package.fpc }
  659. s:=SubstVariables('$(addsuffix /'+ReqName+'/Package.fpc,$(FPCDIR)) $(addsuffix /'+ReqName+'/Package.fpc,$(UNITSDIR)) $(addsuffix /'+ReqName+'/Package.fpc,$(REQUIRE_UNITSDIR))');
  660. Verbose(FPCMakeDebug,'Looking for Package.fpc: "'+s+'"');
  661. s:=SubstVariables('$(firstword $(wildcard '+s+'))');
  662. if TryFile(s) then
  663. exit;
  664. Raise Exception.Create(Format(s_package_not_found,[TargetStr[t],Reqname]));
  665. end;
  666. procedure TFPCMake.LoadRequiredDir(t:TTarget;const MainPack,currdir,subdir:string);
  667. var
  668. ReqFPCMake : TFPCMake;
  669. s : string;
  670. begin
  671. VerboseIdent:=VerboseIdent+' ';
  672. s:=currdir+subdir;
  673. Verbose(FPCMakeDebug,'Subdir: '+s+'/Makefile.fpc');
  674. if not FileExists(s+'/Makefile.fpc') then
  675. begin
  676. { give better error what is wrong }
  677. if not PathExists(s) then
  678. Raise Exception.Create(Format(s_directory_not_found,[s]))
  679. else
  680. Raise Exception.Create(Format(s_makefilefpc_not_found,[s]));
  681. end;
  682. { Process Makefile.fpc }
  683. ReqFPCMake:=TFPCMake.Create(currdir+subdir+'/Makefile.fpc');
  684. ReqFPCMake.LoadSections;
  685. ReqFPCMake.LoadPackageSection;
  686. { Are we a subpackage? }
  687. if (ReqFPCMake.GetVariable('package_name',false)<>MainPack) then
  688. begin
  689. ReqFPCMake.Free;
  690. Delete(VerboseIdent,1,2);
  691. exit;
  692. end;
  693. { Load the requirements of this package }
  694. LoadRequires(t,ReqFPCMake);
  695. { Add the current requirements to our parents requirements }
  696. s:=Trim(ReqFPCMake.GetVariable('require_packages',true)+' '+ReqFPCMake.GetVariable('require_packages'+targetsuffix[t],true));
  697. SetVariable('require_packages'+targetsuffix[t],s,true);
  698. if ReqFPCMake.GetVariable('require_libc',false)<>'' then
  699. SetVariable('require_libc','y',false);
  700. { Free }
  701. ReqFPCMake.Free;
  702. Delete(VerboseIdent,1,2);
  703. end;
  704. procedure TFPCMake.LoadRequires(t:Ttarget;FromFPCMake:TFPCMake);
  705. var
  706. s,
  707. ReqDir,
  708. ReqName,
  709. ReqVersion : string;
  710. i,j : integer;
  711. begin
  712. { packages }
  713. s:=Trim(FromFPCMake.GetVariable('require_packages',true)+' '+FromFPCMake.GetVariable('require_packages'+TargetSuffix[t],true));
  714. Verbose(FPCMakeDebug,'Required packages for '+TargetStr[t]+': '+s);
  715. repeat
  716. reqname:=GetToken(s,' ');
  717. if reqname='' then
  718. break;
  719. i:=Pos('(',ReqName);
  720. if i>0 then
  721. begin
  722. j:=Pos(')',ReqName);
  723. if (i=1) or (j=0) then
  724. Raise Exception.Create(Format(s_err_require_format,[ReqName]));
  725. ReqVersion:=Copy(ReqName,i+1,j-i-1);
  726. ReqName:=Copy(ReqName,1,i-1);
  727. end
  728. else
  729. ReqVersion:='';
  730. { We only use lowercase names }
  731. ReqName:=Lowercase(ReqName);
  732. { Already loaded ? }
  733. if (RequireList[t].IndexOf(ReqName)=-1) then
  734. begin
  735. LoadRequiredPackage(t,ReqName,ReqVersion);
  736. RequireList[t].Add(ReqName);
  737. end;
  738. until false;
  739. { sub dirs }
  740. s:=FromFPCMake.GetVariable('target_dirs',true)+' '+FromFPCMake.GetVariable('target_dirs'+TargetSuffix[t],true);
  741. Verbose(FPCMakeDebug,'Required dirs for '+TargetStr[t]+': '+s);
  742. repeat
  743. reqdir:=GetToken(s,' ');
  744. if reqdir='' then
  745. break;
  746. LoadRequiredDir(t,FromFPCMake.FPackageName,ExtractFilePath(FromFPCMake.FFileName),ReqDir)
  747. until false;
  748. end;
  749. procedure TFPCMake.LoadRequireSection;
  750. function CheckVar(const s:string):boolean;
  751. var
  752. t : ttarget;
  753. begin
  754. result:=false;
  755. if GetVariable(s,false)<>'' then
  756. begin
  757. result:=true;
  758. exit;
  759. end;
  760. for t:=low(ttarget) to high(ttarget) do
  761. if t in FIncludeTargets then
  762. begin
  763. if GetVariable(s+targetsuffix[t],false)<>'' then
  764. begin
  765. result:=true;
  766. exit;
  767. end;
  768. end;
  769. end;
  770. var
  771. s : string;
  772. t : ttarget;
  773. begin
  774. { Check FPCMake version }
  775. s:=GetVariable('require_fpcmake',false);
  776. if (s>version) then
  777. raise Exception.Create(Format(s_fpcmake_version_required,[s]));
  778. { Maybe add an implicit rtl dependency if there is something
  779. to compile }
  780. s:=GetVariable('require_packages',false);
  781. if (GetVariable('require_nortl',false)='') and
  782. (CheckVar('target_programs') or
  783. CheckVar('target_units') or
  784. CheckVar('target_examples')) and
  785. (Pos('rtl(',s)=0) then
  786. begin
  787. s:='rtl '+s;
  788. SetVariable('require_packages',s,false);
  789. end;
  790. { Load recursively all required packages starting with this Makefile.fpc }
  791. for t:=low(TTarget) to high(TTarget) do
  792. if t in FIncludeTargets then
  793. LoadRequires(t,self);
  794. end;
  795. function TFPCMake.GetTargetRequires(t:TTarget):TStringList;
  796. var
  797. ReqSec : TFPCMakeSection;
  798. ReqList : TStringList;
  799. procedure AddReqSec(t:TTarget;Sec:TFPCMakeSection);
  800. var
  801. s,
  802. ReqName : string;
  803. RSec : TFPCMakeSection;
  804. i : integer;
  805. begin
  806. s:=Sec['packages']+' '+Sec['packages'+TargetSuffix[t]];
  807. repeat
  808. ReqName:=GetToken(s,' ');
  809. if ReqName='' then
  810. break;
  811. i:=Pos('(',ReqName);
  812. if i>0 then
  813. ReqName:=Copy(ReqName,1,i-1);
  814. { We only use lowercase names }
  815. ReqName:=Lowercase(ReqName);
  816. { Already loaded ? }
  817. if (ReqList.IndexOf(ReqName)=-1) then
  818. begin
  819. RSec:=TFPCMakeSection(FSections[ReqName+'_require']);
  820. if assigned(RSec) then
  821. AddReqSec(t,RSec);
  822. ReqList.Add(ReqName);
  823. end;
  824. until false;
  825. end;
  826. begin
  827. ReqList:=TStringList.Create;
  828. ReqSec:=TFPCMakeSection(FSections['require']);
  829. if assigned(ReqSec) then
  830. AddReqSec(t,ReqSec);
  831. GetTargetRequires:=ReqList;
  832. end;
  833. function TFPCMake.CheckLibcRequire:boolean;
  834. var
  835. i : integer;
  836. RSec : TFPCMakeSection;
  837. t : ttarget;
  838. begin
  839. Result:=false;
  840. if GetVariable('require_libc',false)<>'' then
  841. begin
  842. Result:=true;
  843. exit;
  844. end;
  845. for t:=low(ttarget) to high(ttarget) do
  846. if t in FIncludeTargets then
  847. begin
  848. for i:=0 to RequireList[t].Count-1 do
  849. begin
  850. RSec:=TFPCMakeSection(FSections[RequireList[t][i]+'_require']);
  851. if assigned(RSec) then
  852. begin
  853. if RSec['libc']<>'' then
  854. begin
  855. Result:=true;
  856. exit;
  857. end;
  858. end;
  859. end;
  860. end;
  861. end;
  862. procedure TFPCMake.AddDefaultVariables;
  863. var
  864. hs,s : string;
  865. begin
  866. { Already set FPCDIR }
  867. hs:='';
  868. s:=GetVariable('FPCDIR',false);
  869. if s<>'' then
  870. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  871. { Load from environment }
  872. if hs='' then
  873. begin
  874. s:=GetEnv('FPCDIR');
  875. if s<>'' then
  876. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  877. end;
  878. { default_fpcdir }
  879. if hs='' then
  880. begin
  881. s:=GetVariable('default_fpcdir',true);
  882. { add the current subdir to relative paths }
  883. if s<>'' then
  884. begin
  885. {$ifdef UNIX}
  886. if (s[1]<>'/') then
  887. {$else}
  888. if (length(s)>2) and (s[2]<>':') then
  889. {$endif}
  890. s:=ExtractFilePath(FFileName)+s;
  891. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  892. end
  893. end;
  894. { OS defaults }
  895. if hs='' then
  896. begin
  897. {$ifdef UNIX}
  898. {$ifndef beos}
  899. if FileExists('/usr/local/bin/ppc386') then
  900. begin
  901. s:=ExtractFilePath(ReadLink('/usr/local/bin/ppc386'));
  902. if s<>'' then
  903. begin
  904. if s[length(s)]='/' then
  905. delete(s,length(s),1);
  906. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  907. end;
  908. end;
  909. if hs='' then
  910. begin
  911. if FileExists('/usr/bin/ppc386') then
  912. begin
  913. s:=ExtractFilePath(ReadLink('/usr/bin/ppc386'));
  914. if s<>'' then
  915. begin
  916. if s[length(s)]='/' then
  917. delete(s,length(s),1);
  918. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  919. end;
  920. end;
  921. end;
  922. {$endif}
  923. {$else UNIX}
  924. hs:=ExtractFilePath(FSearch('ppc386.exe',getenv('PATH')));
  925. if hs<>'' then
  926. begin
  927. s:=hs+'/..';
  928. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  929. if hs='' then
  930. begin
  931. s:=s+'/..';
  932. hs:=SubstVariables('$(wildcard $(addprefix '+s+'/,rtl units))');
  933. end;
  934. end;
  935. if hs='' then
  936. s:='c:/pp';
  937. {$endif UNIX}
  938. end;
  939. SetVariable('FPCDIR',s,false);
  940. { PACKAGESDIR }
  941. if GetVariable('PACKAGESDIR',false)='' then
  942. SetVariable('PACKAGESDIR','$(FPCDIR)/packages',false);
  943. { UNITSDIR }
  944. if GetVariable('UNITSDIR',false)='' then
  945. SetVariable('UNITSDIR','$(FPCDIR)/units/$(TARGET)',false);
  946. Verbose(FPCMakeDebug,s_globals);
  947. Variables.Foreach(@PrintDic);
  948. end;
  949. function TFPCMake.SubstVariables(const s:string):string;
  950. function Expect(var s:string;c:char):boolean;
  951. begin
  952. if (s<>'') and (s[1]=c) then
  953. begin
  954. Delete(s,1,1);
  955. Result:=true;
  956. end
  957. else
  958. begin
  959. Verbose(FPCMakeError,'Error "'+c+'" expected');
  960. Result:=false;
  961. end;
  962. end;
  963. function GetVar(var s:string;untilc:char):string;
  964. var
  965. i,j,k : integer;
  966. first : boolean;
  967. func,
  968. tok,s1,s2,s3 : string;
  969. Sec : TFPCMakeSection;
  970. begin
  971. Result:='';
  972. repeat
  973. j:=Pos(untilc,s);
  974. if j=0 then
  975. j:=Length(s)+1;
  976. i:=Pos('$(',s);
  977. if (j<i) or (i=0) then
  978. break;
  979. Result:=Result+Copy(s,1,i-1);
  980. Delete(s,1,i+1);
  981. { Maybe Function ? }
  982. j:=Pos(')',s);
  983. if j=0 then
  984. j:=Length(s)+1;
  985. i:=Pos(' ',s);
  986. if i=0 then
  987. i:=Length(s)+1;
  988. if i<j then
  989. begin
  990. { It's a function }
  991. Func:=Copy(s,1,i-1);
  992. //writeln('func: ',func);
  993. { $(wildcard <list>) }
  994. if Func='wildcard' then
  995. begin
  996. Delete(s,1,9);
  997. s1:=GetVar(s,')');
  998. Expect(s,')');
  999. first:=true;
  1000. repeat
  1001. tok:=GetToken(s1,' ');
  1002. if tok='' then
  1003. break;
  1004. if PathOrFileExists(tok) then
  1005. begin
  1006. if not first then
  1007. Result:=Result+' '
  1008. else
  1009. first:=false;
  1010. Result:=Result+tok;
  1011. end;
  1012. until false;
  1013. end
  1014. { $(addprefix <suffix>,<list>) }
  1015. else if Func='addprefix' then
  1016. begin
  1017. Delete(s,1,10);
  1018. s1:=GetVar(s,',');
  1019. if Expect(s,',') then
  1020. begin
  1021. s2:=GetVar(s,')');
  1022. Expect(s,')');
  1023. end;
  1024. first:=true;
  1025. repeat
  1026. tok:=GetToken(s2,' ');
  1027. if tok='' then
  1028. break;
  1029. if not first then
  1030. Result:=Result+' '
  1031. else
  1032. first:=false;
  1033. Result:=Result+s1+tok;
  1034. until false;
  1035. end
  1036. { $(addsuffix <suffix>,<list>) }
  1037. else if Func='addsuffix' then
  1038. begin
  1039. Delete(s,1,10);
  1040. s1:=GetVar(s,',');
  1041. if Expect(s,',') then
  1042. begin
  1043. s2:=GetVar(s,')');
  1044. Expect(s,')');
  1045. end;
  1046. first:=true;
  1047. repeat
  1048. tok:=GetToken(s2,' ');
  1049. if tok='' then
  1050. break;
  1051. if not first then
  1052. Result:=Result+' '
  1053. else
  1054. first:=false;
  1055. Result:=Result+tok+s1;
  1056. until false;
  1057. end
  1058. { $(firstword <list>) }
  1059. else if Func='firstword' then
  1060. begin
  1061. Delete(s,1,10);
  1062. s1:=GetVar(s,')');
  1063. Expect(s,')');
  1064. Result:=GetToken(s1,' ');
  1065. end
  1066. end
  1067. else
  1068. begin
  1069. s2:=Copy(s,1,j-1);
  1070. Delete(s,1,j);
  1071. k:=pos('_',s2);
  1072. if k>0 then
  1073. begin
  1074. s3:=LowerCase(Copy(s2,k+1,Length(s2)-k));
  1075. s2:=LowerCase(Copy(s2,1,k-1));
  1076. Sec:=TFPCMakeSection(Section[s2]);
  1077. if assigned(Sec) then
  1078. s2:=Sec[s3]
  1079. else
  1080. s2:='';
  1081. end
  1082. else
  1083. s2:=Variables[s2];
  1084. Insert(s2,s,1);
  1085. end;
  1086. until false;
  1087. Result:=Result+Copy(s,1,j-1);
  1088. Delete(s,1,j-1);
  1089. end;
  1090. var
  1091. s1 : string;
  1092. begin
  1093. //writeln('S: ',s);
  1094. s1:=s;
  1095. Result:=GetVar(s1,#0);
  1096. //writeln('R: ',result);
  1097. end;
  1098. function TFPCMake.GetVariable(const inivar:string;dosubst:boolean):string;
  1099. var
  1100. Sec : TFPCMakeSection;
  1101. Dic : TKeyValue;
  1102. i : integer;
  1103. begin
  1104. Result:='';
  1105. i:=Pos('_',inivar);
  1106. if i<>0 then
  1107. begin
  1108. Sec:=TFPCMakeSection(FSections[Copy(Inivar,1,i-1)]);
  1109. if assigned(Sec) then
  1110. begin
  1111. if not assigned(Sec.Dictionary) then
  1112. Sec.ParseIni;
  1113. Dic:=TKeyValue(Sec.Dictionary);
  1114. Result:=Dic[Copy(IniVar,i+1,Length(IniVar)-i)];
  1115. end
  1116. else
  1117. exit;
  1118. end
  1119. else
  1120. Result:=Variables[IniVar];
  1121. { Substition asked ? }
  1122. if dosubst then
  1123. Result:=SubstVariables(Result);
  1124. end;
  1125. function TFPCMake.SetVariable(const inivar,value:string;add:boolean):string;
  1126. var
  1127. Sec : TFPCMakeSection;
  1128. P : TKeyValueItem;
  1129. i : integer;
  1130. key : string;
  1131. begin
  1132. Result:='';
  1133. i:=Pos('_',inivar);
  1134. if i<>0 then
  1135. begin
  1136. Sec:=TFPCMakeSection(FSections[Copy(Inivar,1,i-1)]);
  1137. if Sec=nil then
  1138. Sec:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.CreateKeyValue(Copy(Inivar,1,i-1))));
  1139. key:=Copy(IniVar,i+1,Length(IniVar)-i);
  1140. p:=TKeyValueItem(Sec.Dictionary.Search(Key));
  1141. if assigned(p) then
  1142. begin
  1143. if Add then
  1144. AddToken(p.FValue,Value,' ')
  1145. else
  1146. p.Value:=Value;
  1147. end
  1148. else
  1149. TKeyValue(Sec.Dictionary).Add(key,value);
  1150. end
  1151. else
  1152. Variables[IniVar]:=value;
  1153. end;
  1154. procedure TFPCMake.ParseSec(p:TDictionaryItem);
  1155. begin
  1156. TFPCMakeSection(p).ParseIni;
  1157. end;
  1158. procedure TFPCMake.PrintSec(p:TDictionaryItem);
  1159. var
  1160. i : integer;
  1161. begin
  1162. with TFPCMakeSection(p) do
  1163. begin
  1164. Verbose(FPCMakeDebug,'['+Name+']');
  1165. if assigned(FList) then
  1166. begin
  1167. Verbose(FPCMakeDebug,' List:');
  1168. for i:=0 to FList.Count-1 do
  1169. Verbose(FPCMakeDebug,' "'+FList[i]+'"');
  1170. if assigned(FDictionary) then
  1171. Verbose(FPCMakeDebug,'');
  1172. end;
  1173. if assigned(FDictionary) then
  1174. begin
  1175. Verbose(FPCMakeDebug,' Dictionary:');
  1176. FDictionary.Foreach(@PrintDic);
  1177. end;
  1178. end;
  1179. end;
  1180. procedure TFPCMake.PrintDic(p:TDictionaryItem);
  1181. begin
  1182. with TKeyValueItem(p) do
  1183. begin
  1184. Verbose(FPCMakeDebug,' '+name+' = "'+value+'"');
  1185. end;
  1186. end;
  1187. procedure TFPCMake.Print;
  1188. begin
  1189. { global variables }
  1190. Verbose(FPCMakeDebug,'[global variables]');
  1191. Verbose(FPCMakeDebug,' Dictionary:');
  1192. Variables.Foreach(@PrintDic);
  1193. { sections }
  1194. FSections.Foreach(@PrintSec);
  1195. end;
  1196. function TFPCMake.GetSec(const AName:string):TDictionaryItem;
  1197. begin
  1198. GetSec:=FSections.Search(AName);
  1199. end;
  1200. end.
  1201. {
  1202. $Log$
  1203. Revision 1.14 2001-09-29 19:47:50 carl
  1204. * make it work for BeOS
  1205. Revision 1.13 2001/08/22 20:45:19 peter
  1206. * firstword added
  1207. * pathexist fix to include sysfile
  1208. Revision 1.12 2001/08/10 10:28:55 pierre
  1209. + netbsd target added
  1210. Revision 1.11 2001/08/02 20:50:29 peter
  1211. * -T<target> support
  1212. * better error reporting for not found dirs
  1213. * some cleanups and nicer strings
  1214. Revision 1.10 2001/07/31 22:02:32 peter
  1215. * install Package.fpc
  1216. Revision 1.9 2001/07/24 09:06:40 pierre
  1217. + added amiga and atari targets
  1218. Revision 1.8 2001/07/13 21:01:59 peter
  1219. * cygdrive support
  1220. * fixed cygwin detection
  1221. * fixed some duplicate and extraeous spaces
  1222. Revision 1.7 2001/06/04 21:42:57 peter
  1223. * Arguments added
  1224. * Start of Package.fpc creation
  1225. Revision 1.6 2001/06/02 19:20:24 peter
  1226. * beos target added
  1227. Revision 1.5 2001/02/22 21:11:24 peter
  1228. * fpcdir detection added
  1229. * fixed loading of variables in fpcmake itself
  1230. Revision 1.4 2001/02/05 20:44:56 peter
  1231. * variable substition like GNU Make. wildcard,addprefix,addsuffix
  1232. already implemented
  1233. Revision 1.3 2001/02/01 22:00:10 peter
  1234. * default.fpcdir is back
  1235. * subdir requirement checking works, but not very optimal yet as
  1236. it can load the same Makefile.fpc multiple times
  1237. Revision 1.2 2001/01/29 21:49:10 peter
  1238. * lot of updates
  1239. Revision 1.1 2001/01/24 21:59:36 peter
  1240. * first commit of new fpcmake
  1241. }