fpcmkcfg.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  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. result := '#IFNDEF ' + BuildOSTarget + LineEnding +
  86. '#DEFINE NEEDCROSSBINUTILS' + LineEnding +
  87. '#ENDIF'
  88. else if (BuildTarget = 'i386') or (BuildTarget = 'x86_64') then
  89. begin
  90. // Cross-binutils are not needed to compile for i386 on an x86_64 system
  91. result := '#IFNDEF CPUI386' + LineEnding +
  92. '#IFNDEF CPUAMD64' + LineEnding +
  93. '#DEFINE NEEDCROSSBINUTILS' + LineEnding +
  94. '#ENDIF' + LineEnding +
  95. '#ENDIF' + LineEnding +
  96. LineEnding +
  97. '#IFNDEF ' + BuildOSTarget + LineEnding +
  98. '#DEFINE NEEDCROSSBINUTILS' + LineEnding +
  99. '#ENDIF';
  100. end
  101. else
  102. result := '#DEFINE NEEDCROSSBINUTILS';
  103. end;
  104. function GetDefaultGCCDir: string;
  105. var GccExecutable: string;
  106. function GetGccExecutable: string;
  107. begin
  108. if GccExecutable='' then
  109. begin
  110. GccExecutable := ExeSearch('gcc'+ExeExt,GetEnvironmentVariable('PATH'));
  111. if GccExecutable='' then
  112. begin
  113. Writeln(StdErr,SWarngccNotFound);
  114. GccExecutable:='-';
  115. end;
  116. end;
  117. if GccExecutable = '-' then
  118. result := ''
  119. else
  120. result := GccExecutable;
  121. end;
  122. function ExecuteProc(const CommandLine: string; ReadStdErr: boolean) : string;
  123. const BufSize=2048;
  124. var S: TProcess;
  125. buf: array[0..BufSize-1] of byte;
  126. count: integer;
  127. begin
  128. S:=TProcess.Create(Nil);
  129. try
  130. S.Commandline:=CommandLine;
  131. S.Options:=[poUsePipes,poWaitOnExit];
  132. S.execute;
  133. Count:=s.output.read(buf,BufSize);
  134. if (count=0) and ReadStdErr then
  135. Count:=s.Stderr.read(buf,BufSize);
  136. setlength(result,count);
  137. move(buf[0],result[1],count);
  138. finally
  139. S.Free;
  140. end;
  141. end;
  142. function Get4thWord(const AString: string): string;
  143. var p: pchar;
  144. spacecount: integer;
  145. StartWord: pchar;
  146. begin
  147. if length(AString)>6 then
  148. begin
  149. p := @AString[1];
  150. spacecount:=0;
  151. StartWord:=nil;
  152. while (not (p^ in [#0,#10,#13])) and ((p^<>' ') or (StartWord=nil)) do
  153. begin
  154. if p^=' ' then
  155. begin
  156. inc(spacecount);
  157. if spacecount=3 then StartWord:=p+1;
  158. end;
  159. inc(p);
  160. end;
  161. if StartWord<>nil then
  162. begin
  163. SetLength(result,p-StartWord);
  164. move(StartWord^,result[1],p-StartWord);
  165. end
  166. else
  167. result := '';
  168. end;
  169. end;
  170. function GetGccDirArch(const ACpuType, GCCParams: string) : string;
  171. var ExecResult: string;
  172. libgccFilename: string;
  173. gccDir: string;
  174. begin
  175. ExecResult:=ExecuteProc(GetGccExecutable+' -v '+GCCParams, True);
  176. libgccFilename:=Get4thWord(ExecResult);
  177. if libgccFilename='' then
  178. libgccFilename:=ExecuteProc(GetGccExecutable+' --print-libgcc-file-name '+GCCParams, False);
  179. gccDir := ExtractFileDir(libgccFilename);
  180. if gccDir='' then
  181. result := ''
  182. else if ACpuType = '' then
  183. result := '-Fl'+gccDir
  184. else
  185. result := '#ifdef ' + ACpuType + LineEnding + '-Fl' + gccDir + LineEnding + '#endif';
  186. end;
  187. begin
  188. result := '';
  189. GccExecutable:='';
  190. if sametext(BuildOSTarget,'Freebsd') or sametext(BuildOSTarget,'Openbsd') then
  191. result := '-Fl/usr/local/lib'
  192. else if sametext(BuildOSTarget,'Netbsd') then
  193. result := '-Fl/usr/pkg/lib'
  194. else if sametext(BuildOSTarget,'Linux') then
  195. begin
  196. if (BuildTarget = 'i386') or (BuildTarget = 'x86_64') then
  197. result := GetGccDirArch('cpui386','-m32') + LineEnding +
  198. GetGccDirArch('cpux86_64','-m64')
  199. else if (BuildTarget = 'powerpc') or (BuildTarget = 'powerpc64') then
  200. result := GetGccDirArch('cpupowerpc','-m32') + LineEnding +
  201. GetGccDirArch('cpupowerpc64','-m64')
  202. end
  203. else if sametext(BuildOSTarget,'Darwin') then
  204. result := GetGccDirArch('cpupowerpc','-arch ppc') + LineEnding +
  205. GetGccDirArch('cpupowerpc64','-arch ppc64') + LineEnding +
  206. GetGccDirArch('cpui386','-arch i386') + LineEnding +
  207. GetGccDirArch('cpux86_64','-arch x86_64');
  208. end;
  209. procedure Init;
  210. begin
  211. Verbose:=False;
  212. IDEBuildIn:=0;
  213. TemplateParser := TTemplateParser.Create;
  214. TemplateParser.StartDelimiter:='%';
  215. TemplateParser.EndDelimiter:='%';
  216. TemplateParser.Values['FPCVERSION'] := BuildVersion;
  217. TemplateParser.Values['FPCTARGET'] := BuildTarget;
  218. TemplateParser.Values['FPCTARGETOS'] := BuildOSTarget;
  219. TemplateParser.Values['PWD'] := GetCurrentDir;
  220. TemplateParser.Values['BUILDDATE'] := DateToStr(Date);
  221. TemplateParser.Values['BUILDTIME'] := TimeToStr(Time);
  222. TemplateParser.Values['LOCALREPOSITORY'] := GetDefaultLocalRepository;
  223. TemplateParser.Values['NEEDCROSSBINUTILSIFDEF'] := GetDefaultNeedCrossBinutilsIfdef;
  224. TemplateParser.Values['GCCLIBPATH'] := GetDefaultGCCDIR;
  225. Cfg:=TStringList.Create;
  226. Cfg.Text:=StrPas(Addr(DefaultConfig[0][1]));
  227. end;
  228. Procedure Done;
  229. begin
  230. FreeAndNil(Cfg);
  231. FreeAndNil(TemplateParser);
  232. end;
  233. Procedure Usage;
  234. begin
  235. Writeln(Format(SUsage00,[ExtractFileName(Paramstr(0))]));
  236. Writeln(SUsage10);
  237. Writeln(SUsage20);
  238. Writeln(SUsage30);
  239. Writeln(SUsage40);
  240. Writeln(SUsage50);
  241. Writeln(SUsage60);
  242. Writeln(SUsage70);
  243. Writeln(SUsage80);
  244. Writeln(SUsage90);
  245. Writeln(SUsage100);
  246. Writeln(SUsage110);
  247. Writeln(SUsage120);
  248. Writeln(SUsage130);
  249. Writeln(SUsage140);
  250. Halt(1);
  251. end;
  252. Procedure UnknownOption(Const S : String);
  253. begin
  254. Writeln(SErrUnknownOption,S);
  255. Usage;
  256. end;
  257. Procedure ShowBuiltIn;
  258. Var
  259. I : Integer;
  260. begin
  261. For I:=0 to Cfg.Count-1 do
  262. Writeln(Cfg[I]);
  263. end;
  264. Procedure ShowBuiltInMacros;
  265. Var
  266. I : Integer;
  267. begin
  268. For I:=0 to TemplateParser.ValueCount-1 do
  269. Writeln(TemplateParser.NamesByIndex[I]+'='+TemplateParser.ValuesByIndex[I]);
  270. end;
  271. Procedure ProcessCommandline;
  272. Var
  273. I : Integer;
  274. S : String;
  275. ShowBuiltinCommand : boolean;
  276. Function GetOptArg : String;
  277. begin
  278. If I=ParamCount then
  279. begin
  280. Writeln(StdErr,Format(SErrArgExpected,[S]));
  281. Halt(1);
  282. end;
  283. inc(I);
  284. Result:=ParamStr(I);
  285. end;
  286. procedure AddPair(const Value: String);
  287. var P: integer;
  288. N,V: String;
  289. begin
  290. P:=Pos('=',Value);
  291. If p=0 then
  292. begin
  293. Writeln(StdErr,Format(SErrIncompletePair,[Value]));
  294. Halt(1);
  295. end;
  296. V:=Value;
  297. N:=Copy(V,1,P-1);
  298. Delete(V,1,P);
  299. TemplateParser.Values[N] := V;
  300. end;
  301. begin
  302. I:=1;
  303. ShowBuiltinCommand := False;
  304. While( I<=ParamCount) do
  305. begin
  306. S:=Paramstr(i);
  307. If Length(S)<=1 then
  308. UnknownOption(S)
  309. else
  310. case S[2] of
  311. 'v' : Verbose:=True;
  312. 'h' : Usage;
  313. 'b' : ShowBuiltinCommand := true;
  314. 'm' : begin
  315. ShowBuiltinMacros;
  316. halt(0);
  317. end;
  318. 't' : TemplateFileName:=GetOptArg;
  319. 'd' : AddPair(GetOptArg);
  320. 'u' : TemplateParser.Values[GetOptArg]:='';
  321. 'o' : OutputFileName:=GetoptArg;
  322. 's' : SkipBackup:=True;
  323. '0' : IDEBuildin:=0;
  324. '1' : IDEBuildin:=1;
  325. '2' : IDEBuildin:=2;
  326. '3' : IDEBuildin:=3;
  327. '4' : IDEBuildin:=4;
  328. else
  329. UnknownOption(S);
  330. end;
  331. Inc(I);
  332. end;
  333. If (TemplateFileName<>'') then
  334. begin
  335. If Not FileExists(TemplateFileName) then
  336. begin
  337. Writeln(StdErr,Format(SErrNoSuchFile,[TemplateFileName]));
  338. Halt(1);
  339. end;
  340. Cfg.LoadFromFile(TemplateFileName);
  341. TemplateParser.Values['TEMPLATEFILE'] := TemplateFileName;
  342. end
  343. else
  344. begin
  345. case IDEBuildin of
  346. 1:
  347. Cfg.Text:=StrPas(Addr(fpcfg[0][1]));
  348. 2:
  349. Cfg.Text:=StrPas(Addr(fpini[0][1]));
  350. 3:
  351. Cfg.Text:=StrPas(Addr(fppkg[0][1]));
  352. 4:
  353. Cfg.Text:=StrPas(Addr(fppkg_default[0][1]));
  354. end;
  355. TemplateParser.Values['TEMPLATEFILE'] := 'builtin';
  356. end;
  357. if ShowBuiltinCommand then
  358. begin
  359. ShowBuiltIn;
  360. halt(0);
  361. end;
  362. end;
  363. Procedure CreateFile;
  364. Var
  365. Fout : Text;
  366. S,BFN : String;
  367. I : Integer;
  368. begin
  369. If (OutputFileName<>'')
  370. and FileExists(OutputFileName)
  371. and not SkipBackup then
  372. begin
  373. BFN:=ChangeFileExt(OutputFileName,'.bak');
  374. If FileExists(BFN) and not DeleteFile(BFN) then
  375. begin
  376. Writeln(StdErr,Format(SErrDelBackupFailed,[BFN]));
  377. Halt(1);
  378. end;
  379. If not RenameFile(OutputFileName,BFN) then
  380. begin
  381. Writeln(StdErr,Format(SErrBackupFailed,[OutputFileName,BFN]));
  382. Halt(1);
  383. end;
  384. end;
  385. Assign(Fout,OutputFileName);
  386. Rewrite(FOut);
  387. Try
  388. For I:=0 to Cfg.Count-1 do
  389. begin
  390. S:=Cfg[i];
  391. S := TemplateParser.ParseString(S);
  392. Writeln(FOut,S);
  393. end;
  394. Finally
  395. Close(Fout);
  396. end;
  397. end;
  398. begin
  399. Init;
  400. Try
  401. ProcessCommandLine;
  402. CreateFile;
  403. Finally
  404. Done;
  405. end;
  406. end.