fpcmkcfg.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. {$mode objfpc}
  2. {$H+}
  3. {
  4. This file is part of Free Pascal Build tools
  5. Copyright (c) 2005 by Michael Van Canneyt
  6. Create a configuration file
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. program fpcmkcfg;
  14. uses SysUtils,Classes,fpTemplate, process;
  15. {
  16. The inc files must be built from a template with the data2inc
  17. command.
  18. data2inc -b -s fpc.cft fpccfg.inc DefaultConfig
  19. data2inc -b -s fpinc.ini fpini.inc fpini
  20. data2inc -b -s fpinc.cfg fpcfg.inc fpcfg
  21. data2inc -b -s fppkg.cfg fppkg.inc fppkg
  22. data2inc -b -s default.cft default.inc fppkg_default
  23. }
  24. {$i fpccfg.inc}
  25. {$i fpini.inc}
  26. {$i fpcfg.inc}
  27. {$i fppkg.inc}
  28. {$i default.inc}
  29. Const
  30. BuildVersion={$I %FPCVERSION%};
  31. BuildTarget={$I %FPCTARGET%};
  32. BuildOSTarget={$I %FPCTARGETOS%};
  33. {$ifdef unix}
  34. ExeExt = '';
  35. {$else unix}
  36. ExeExt = '.exe';
  37. {$endif unix}
  38. Resourcestring
  39. SUsage00 = 'Usage: %s [options]';
  40. SUsage10 = 'Where options is one or more of';
  41. SUSage20 = ' -t filename Template file name. Default is built-in';
  42. SUSage30 = ' -o filename Set output file. Default is standard output.';
  43. SUsage40 = ' -d name=value define name=value pair.';
  44. SUsage50 = ' -h show this help and exit.';
  45. SUsage60 = ' -u name remove name from list of name/value pairs.';
  46. // SUsage70 = ' -l filename read name/value pairs from filename';
  47. SUsage70 = ' -m show builtin macros and exit.';
  48. SUsage80 = ' -b show builtin template and exit.';
  49. SUsage90 = ' -v be verbose.';
  50. Susage100 = ' -0 use built in fpc.cfg template (default)';
  51. Susage110 = ' -1 use built in fp.cfg template';
  52. Susage120 = ' -2 use built in fp.ini template';
  53. Susage130 = ' -3 use built in fppkg.cfg template';
  54. Susage140 = ' -4 use built in fppkg default compiler template';
  55. SErrUnknownOption = 'Error: Unknown option.';
  56. SErrArgExpected = 'Error: Option "%s" requires an argument.';
  57. SErrIncompletePair = 'Error: Incomplete name-value pair "%s".';
  58. SErrNoSuchFile = 'Error: File "%s" does not exist.';
  59. SErrBackupFailed = 'Error: Backup of file "%s" to "%s" failed.';
  60. SErrDelBackupFailed = 'Error: Delete of old backup file "%s" failed.';
  61. SWarnIgnoringFile = 'Warning: Ignoring non-existent file: ';
  62. SWarnIgnoringPair = 'Warning: Ignoring wrong name/value pair: ';
  63. SWarngccNotFound = 'Warning: Could not find gcc. Unable to determine the gcclib path.';
  64. Var
  65. Verbose : Boolean;
  66. SkipBackup : Boolean;
  67. Cfg : TStringList;
  68. TemplateParser: TTemplateParser;
  69. TemplateFileName,
  70. OutputFileName : String;
  71. IDEBuildin : Integer;
  72. function GetDefaultLocalRepository: string;
  73. begin
  74. {$IFDEF Unix}
  75. result := '{UserDir}.fppkg'+PathDelim;
  76. {$ELSE Unix}
  77. result := '{AppConfigDir}';
  78. {$ENDIF Unix}
  79. end;
  80. function GetDefaultNeedCrossBinutilsIfdef: string;
  81. begin
  82. result := '';
  83. // On Darwin there is never a need for a crossbinutils prefix
  84. if SameText(BuildOSTarget,'Darwin') then
  85. Exit;
  86. if (BuildTarget = 'i386') or (BuildTarget = 'x86_64') then
  87. begin
  88. // Cross-binutils are not needed to compile for i386 on an x86_64 system
  89. result := '#IFNDEF CPUI386' + LineEnding +
  90. '#IFNDEF CPUAMD64' + LineEnding +
  91. '#DEFINE NEEDCROSSBINUTILS' + LineEnding +
  92. '#ENDIF' + LineEnding +
  93. '#ENDIF' + LineEnding +
  94. LineEnding +
  95. '#IFNDEF ' + BuildOSTarget + LineEnding +
  96. '#DEFINE NEEDCROSSBINUTILS' + LineEnding +
  97. '#ENDIF';
  98. end
  99. else
  100. result := '#DEFINE NEEDCROSSBINUTILS';
  101. end;
  102. function GetDefaultGCCDir: string;
  103. var GccExecutable: string;
  104. function GetGccExecutable: string;
  105. begin
  106. if GccExecutable='' then
  107. begin
  108. GccExecutable := ExeSearch('gcc'+ExeExt,GetEnvironmentVariable('PATH'));
  109. if GccExecutable='' then
  110. begin
  111. Writeln(StdErr,SWarngccNotFound);
  112. GccExecutable:='-';
  113. end;
  114. end;
  115. if GccExecutable = '-' then
  116. result := ''
  117. else
  118. result := GccExecutable;
  119. end;
  120. function ExecuteProc(const CommandLine: string; ReadStdErr: boolean) : string;
  121. const BufSize=2048;
  122. var S: TProcess;
  123. buf: array[0..BufSize-1] of byte;
  124. count: integer;
  125. begin
  126. S:=TProcess.Create(Nil);
  127. try
  128. S.Commandline:=CommandLine;
  129. S.Options:=[poUsePipes,poWaitOnExit];
  130. S.execute;
  131. Count:=s.output.read(buf,BufSize);
  132. if (count=0) and ReadStdErr then
  133. Count:=s.Stderr.read(buf,BufSize);
  134. setlength(result,count);
  135. move(buf[0],result[1],count);
  136. finally
  137. S.Free;
  138. end;
  139. end;
  140. function Get4thWord(const AString: string): string;
  141. var p: pchar;
  142. spacecount: integer;
  143. StartWord: pchar;
  144. begin
  145. if length(AString)>6 then
  146. begin
  147. p := @AString[1];
  148. spacecount:=0;
  149. StartWord:=nil;
  150. while (not (p^ in [#0,#10,#13])) and ((p^<>' ') or (StartWord=nil)) do
  151. begin
  152. if p^=' ' then
  153. begin
  154. inc(spacecount);
  155. if spacecount=3 then StartWord:=p+1;
  156. end;
  157. inc(p);
  158. end;
  159. if StartWord<>nil then
  160. begin
  161. SetLength(result,p-StartWord);
  162. move(StartWord^,result[1],p-StartWord);
  163. end
  164. else
  165. result := '';
  166. end;
  167. end;
  168. function GetGccDirArch(const ACpuType, GCCParams: string) : string;
  169. var ExecResult: string;
  170. libgccFilename: string;
  171. gccDir: string;
  172. begin
  173. ExecResult:=ExecuteProc(GetGccExecutable+' -v '+GCCParams, True);
  174. libgccFilename:=Get4thWord(ExecResult);
  175. if libgccFilename='' then
  176. libgccFilename:=ExecuteProc(GetGccExecutable+' --print-libgcc-file-name '+GCCParams, False);
  177. gccDir := ExtractFileDir(libgccFilename);
  178. if gccDir='' then
  179. result := ''
  180. else if ACpuType = '' then
  181. result := '-Fl'+gccDir
  182. else
  183. result := '#ifdef ' + ACpuType + LineEnding + '-Fl' + gccDir + LineEnding + '#endif';
  184. end;
  185. begin
  186. result := '';
  187. GccExecutable:='';
  188. if sametext(BuildOSTarget,'Freebsd') or sametext(BuildOSTarget,'Openbsd') then
  189. result := '-Fl/usr/local/lib'
  190. else if sametext(BuildOSTarget,'Netbsd') then
  191. result := '-Fl/usr/pkg/lib'
  192. else if sametext(BuildOSTarget,'Linux') then
  193. begin
  194. if (BuildTarget = 'i386') or (BuildTarget = 'x86_64') then
  195. result := GetGccDirArch('cpui386','-m32') + LineEnding +
  196. GetGccDirArch('cpux86_64','-m64')
  197. else if (BuildTarget = 'powerpc') or (BuildTarget = 'powerpc64') then
  198. result := GetGccDirArch('cpupowerpc','-m32') + LineEnding +
  199. GetGccDirArch('cpupowerpc64','-m64')
  200. end
  201. else if sametext(BuildOSTarget,'Darwin') then
  202. result := GetGccDirArch('cpupowerpc','-arch ppc') + LineEnding +
  203. GetGccDirArch('cpupowerpc64','-arch ppc64') + LineEnding +
  204. GetGccDirArch('cpui386','-arch i386') + LineEnding +
  205. GetGccDirArch('cpux86_64','-arch x86_64');
  206. end;
  207. procedure Init;
  208. begin
  209. Verbose:=False;
  210. IDEBuildIn:=0;
  211. TemplateParser := TTemplateParser.Create;
  212. TemplateParser.StartDelimiter:='%';
  213. TemplateParser.EndDelimiter:='%';
  214. TemplateParser.Values['FPCVERSION'] := BuildVersion;
  215. TemplateParser.Values['FPCTARGET'] := BuildTarget;
  216. TemplateParser.Values['FPCTARGETOS'] := BuildOSTarget;
  217. TemplateParser.Values['PWD'] := GetCurrentDir;
  218. TemplateParser.Values['BUILDDATE'] := DateToStr(Date);
  219. TemplateParser.Values['BUILDTIME'] := TimeToStr(Time);
  220. TemplateParser.Values['LOCALREPOSITORY'] := GetDefaultLocalRepository;
  221. TemplateParser.Values['NEEDCROSSBINUTILSIFDEF'] := GetDefaultNeedCrossBinutilsIfdef;
  222. TemplateParser.Values['GCCLIBPATH'] := GetDefaultGCCDIR;
  223. Cfg:=TStringList.Create;
  224. Cfg.Text:=StrPas(Addr(DefaultConfig[0][1]));
  225. end;
  226. Procedure Done;
  227. begin
  228. FreeAndNil(Cfg);
  229. FreeAndNil(TemplateParser);
  230. end;
  231. Procedure Usage;
  232. begin
  233. Writeln(Format(SUsage00,[ExtractFileName(Paramstr(0))]));
  234. Writeln(SUsage10);
  235. Writeln(SUsage20);
  236. Writeln(SUsage30);
  237. Writeln(SUsage40);
  238. Writeln(SUsage50);
  239. Writeln(SUsage60);
  240. Writeln(SUsage70);
  241. Writeln(SUsage80);
  242. Writeln(SUsage90);
  243. Writeln(SUsage100);
  244. Writeln(SUsage110);
  245. Writeln(SUsage120);
  246. Writeln(SUsage130);
  247. Writeln(SUsage140);
  248. Halt(1);
  249. end;
  250. Procedure UnknownOption(Const S : String);
  251. begin
  252. Writeln(SErrUnknownOption,S);
  253. Usage;
  254. end;
  255. Procedure ShowBuiltIn;
  256. Var
  257. I : Integer;
  258. begin
  259. For I:=0 to Cfg.Count-1 do
  260. Writeln(Cfg[I]);
  261. end;
  262. Procedure ShowBuiltInMacros;
  263. Var
  264. I : Integer;
  265. begin
  266. For I:=0 to TemplateParser.ValueCount-1 do
  267. Writeln(TemplateParser.NamesByIndex[I]+'='+TemplateParser.ValuesByIndex[I]);
  268. end;
  269. Procedure ProcessCommandline;
  270. Var
  271. I : Integer;
  272. S : String;
  273. Function GetOptArg : String;
  274. begin
  275. If I=ParamCount then
  276. begin
  277. Writeln(StdErr,Format(SErrArgExpected,[S]));
  278. Halt(1);
  279. end;
  280. inc(I);
  281. Result:=ParamStr(I);
  282. end;
  283. procedure AddPair(const Value: String);
  284. var P: integer;
  285. N,V: String;
  286. begin
  287. P:=Pos('=',Value);
  288. If p=0 then
  289. begin
  290. Writeln(StdErr,Format(SErrIncompletePair,[Value]));
  291. Halt(1);
  292. end;
  293. V:=Value;
  294. N:=Copy(V,1,P-1);
  295. Delete(V,1,P);
  296. TemplateParser.Values[N] := V;
  297. end;
  298. begin
  299. I:=1;
  300. While( I<=ParamCount) do
  301. begin
  302. S:=Paramstr(i);
  303. If Length(S)<=1 then
  304. UnknownOption(S)
  305. else
  306. case S[2] of
  307. 'v' : Verbose:=True;
  308. 'h' : Usage;
  309. 'b' : begin
  310. ShowBuiltin;
  311. halt(0);
  312. end;
  313. 'm' : begin
  314. ShowBuiltinMacros;
  315. halt(0);
  316. end;
  317. 't' : TemplateFileName:=GetOptArg;
  318. 'd' : AddPair(GetOptArg);
  319. 'u' : TemplateParser.Values[GetOptArg]:='';
  320. 'o' : OutputFileName:=GetoptArg;
  321. 's' : SkipBackup:=True;
  322. '0' : IDEBuildin:=0;
  323. '1' : IDEBuildin:=1;
  324. '2' : IDEBuildin:=2;
  325. '3' : IDEBuildin:=3;
  326. '4' : IDEBuildin:=4;
  327. else
  328. UnknownOption(S);
  329. end;
  330. Inc(I);
  331. end;
  332. If (TemplateFileName<>'') then
  333. begin
  334. If Not FileExists(TemplateFileName) then
  335. begin
  336. Writeln(StdErr,Format(SErrNoSuchFile,[TemplateFileName]));
  337. Halt(1);
  338. end;
  339. Cfg.LoadFromFile(TemplateFileName);
  340. TemplateParser.Values['TEMPLATEFILE'] := TemplateFileName;
  341. end
  342. else
  343. begin
  344. case IDEBuildin of
  345. 1:
  346. Cfg.Text:=StrPas(Addr(fpcfg[0][1]));
  347. 2:
  348. Cfg.Text:=StrPas(Addr(fpini[0][1]));
  349. 3:
  350. Cfg.Text:=StrPas(Addr(fppkg[0][1]));
  351. 4:
  352. Cfg.Text:=StrPas(Addr(fppkg_default[0][1]));
  353. end;
  354. TemplateParser.Values['TEMPLATEFILE'] := 'builtin';
  355. end;
  356. end;
  357. Procedure CreateFile;
  358. Var
  359. Fout : Text;
  360. S,BFN : String;
  361. I : Integer;
  362. begin
  363. If (OutputFileName<>'')
  364. and FileExists(OutputFileName)
  365. and not SkipBackup then
  366. begin
  367. BFN:=ChangeFileExt(OutputFileName,'.bak');
  368. If FileExists(BFN) and not DeleteFile(BFN) then
  369. begin
  370. Writeln(StdErr,Format(SErrDelBackupFailed,[BFN]));
  371. Halt(1);
  372. end;
  373. If not RenameFile(OutputFileName,BFN) then
  374. begin
  375. Writeln(StdErr,Format(SErrBackupFailed,[OutputFileName,BFN]));
  376. Halt(1);
  377. end;
  378. end;
  379. Assign(Fout,OutputFileName);
  380. Rewrite(FOut);
  381. Try
  382. For I:=0 to Cfg.Count-1 do
  383. begin
  384. S:=Cfg[i];
  385. S := TemplateParser.ParseString(S);
  386. Writeln(FOut,S);
  387. end;
  388. Finally
  389. Close(Fout);
  390. end;
  391. end;
  392. begin
  393. Init;
  394. Try
  395. ProcessCommandLine;
  396. CreateFile;
  397. Finally
  398. Done;
  399. end;
  400. end.