fpcmkcfg.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  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
  15. fpmkunit,
  16. SysUtils,
  17. Classes,
  18. {$ifdef unix}
  19. baseunix,
  20. {$endif}
  21. fpTemplate;
  22. {
  23. The inc files must be built from a template with the data2inc
  24. command.
  25. data2inc -b -s fpc.cft fpccfg.inc DefaultConfig
  26. data2inc -b -s fpinc.ini fpini.inc fpini
  27. data2inc -b -s fpinc.cfg fpcfg.inc fpcfg
  28. data2inc -b -s fppkg.cfg fppkg.inc fppkg
  29. data2inc -b -s default.cft default.inc fppkg_default
  30. }
  31. {$i fpccfg.inc}
  32. {$i fpini.inc}
  33. {$i fpcfg.inc}
  34. {$i fppkg.inc}
  35. {$i default.inc}
  36. Const
  37. BuildVersion={$I %FPCVERSION%};
  38. BuildTarget={$I %FPCTARGET%};
  39. BuildOSTarget={$I %FPCTARGETOS%};
  40. {$ifdef unix}
  41. ExeExt = '';
  42. {$else unix}
  43. ExeExt = '.exe';
  44. {$endif unix}
  45. Resourcestring
  46. SUsage00 = 'Usage: %s [options]';
  47. SUsage10 = 'Where options is one or more of';
  48. SUSage20 = ' -t filename Template file name. Default is built-in';
  49. SUSage30 = ' -o filename Set output file. Default is standard output.';
  50. SUsage40 = ' -d name=value define name=value pair.';
  51. SUsage50 = ' -h show this help and exit.';
  52. SUsage60 = ' -u name remove name from list of name/value pairs.';
  53. // SUsage70 = ' -l filename read name/value pairs from filename';
  54. SUsage70 = ' -m show builtin macros and exit.';
  55. SUsage80 = ' -b show builtin template and exit.';
  56. SUsage84 = ' -s skip the creation of a backup-file.';
  57. SUsage87 = ' -p force directory creation.';
  58. SUsage90 = ' -v be verbose.';
  59. Susage100 = ' -0 use built in fpc.cfg template (default)';
  60. Susage110 = ' -1 use built in fp.cfg template';
  61. Susage120 = ' -2 use built in fp.ini template';
  62. Susage130 = ' -3 use built in fppkg.cfg template';
  63. Susage140 = ' -4 use built in fppkg default compiler template';
  64. SErrUnknownOption = 'Error: Unknown option.';
  65. SErrArgExpected = 'Error: Option "%s" requires an argument.';
  66. SErrIncompletePair = 'Error: Incomplete name-value pair "%s".';
  67. SErrNoSuchFile = 'Error: File "%s" does not exist.';
  68. SErrNoSuchDirectory = 'Error: Directory of file "%s" does not exists. User -p to force creation.';
  69. SErrBackupFailed = 'Error: Backup of file "%s" to "%s" failed.';
  70. SErrDelBackupFailed = 'Error: Delete of old backup file "%s" failed.';
  71. SErrCreateDirFailed = 'Error: Could not create the directory for file "%s".';
  72. SErrDestDirectory = 'Error: The output file "%s" is a directory.';
  73. SWarnIgnoringFile = 'Warning: Ignoring non-existent file: ';
  74. SWarnIgnoringPair = 'Warning: Ignoring wrong name/value pair: ';
  75. SWarngccNotFound = 'Warning: Could not find gcc. Unable to determine the gcclib path.';
  76. SWarnCouldNotExecute= 'Warning: Could not execute command ''%s''';
  77. SBackupCreated = 'Saved old "%s" to "%s"';
  78. Var
  79. Verbose : Boolean;
  80. SkipBackup : Boolean;
  81. CreateDir: Boolean;
  82. Cfg : TStringList;
  83. TemplateParser: TTemplateParser;
  84. TemplateFileName,
  85. OutputFileName : String;
  86. IDEBuildin : Integer;
  87. function IsSuperUser:boolean;
  88. begin
  89. {$ifdef unix}
  90. result:=(fpGetUID=0);
  91. {$else unix}
  92. result:=false;
  93. {$endif unix}
  94. end;
  95. function GetDefaultLocalRepository: string;
  96. begin
  97. {$IFDEF Unix}
  98. result := '{UserDir}.fppkg'+PathDelim;
  99. {$ELSE Unix}
  100. result := '{AppConfigDir}';
  101. {$ENDIF Unix}
  102. end;
  103. function GetDefaultLocalBasepath: string;
  104. begin
  105. {$IFDEF Unix}
  106. result := '~/.fppkg'+PathDelim+'lib'+PathDelim+'fpc'+PathDelim+'$fpcversion';
  107. {$ELSE Unix}
  108. result := '$LOCAL_APPDATA'+PathDelim+'FreePascal'+PathDelim+'fppkg';
  109. {$ENDIF Unix}
  110. end;
  111. function GetDefaultCompilerConfigDir: string;
  112. begin
  113. {$IFDEF Unix}
  114. if IsSuperUser then
  115. result := '/etc/fppkg/'
  116. else
  117. {$ENDIF}
  118. result := '{LocalRepository}config/';
  119. end;
  120. function GetDefaultNeedCrossBinutilsIfdef: string;
  121. begin
  122. result := '';
  123. // On Darwin there is never a need for a crossbinutils prefix
  124. if SameText(BuildOSTarget,'Darwin') then
  125. result := '#IFNDEF ' + BuildOSTarget + LineEnding +
  126. '#DEFINE NEEDCROSSBINUTILS' + LineEnding +
  127. '#ENDIF'
  128. else if (BuildTarget = 'i386') or (BuildTarget = 'x86_64') then
  129. begin
  130. // Cross-binutils are not needed to compile for i386 on an x86_64 system
  131. result := '#IFNDEF CPUI386' + LineEnding +
  132. '#IFNDEF CPUAMD64' + LineEnding +
  133. '#DEFINE NEEDCROSSBINUTILS' + LineEnding +
  134. '#ENDIF' + LineEnding +
  135. '#ENDIF' + LineEnding +
  136. LineEnding +
  137. '#IFNDEF ' + BuildOSTarget + LineEnding +
  138. '#DEFINE NEEDCROSSBINUTILS' + LineEnding +
  139. '#ENDIF';
  140. end
  141. else
  142. result := '#DEFINE NEEDCROSSBINUTILS';
  143. end;
  144. function GetDefaultGCCDir: string;
  145. var
  146. OS: TOS;
  147. CPU: TCPU;
  148. s: string;
  149. procedure AddConditionalLinkerPath(const aCpuType: string; const ACPU: TCPU; var ConfigFileOption: string);
  150. var
  151. path: string;
  152. ErrS: string;
  153. begin
  154. path := GetDefaultLibGCCDir(ACPU, OS, ErrS);
  155. if ErrS<>'' then
  156. Writeln(StdErr, ErrS);
  157. if path <> '' then
  158. begin
  159. if ConfigFileOption<>'' then ConfigFileOption:=ConfigFileOption+LineEnding;
  160. ConfigFileOption := ConfigFileOption + '#ifdef ' + ACpuType + LineEnding + '-Fl' + Path + LineEnding + '#endif';
  161. end;
  162. end;
  163. begin
  164. CPU := StringToCPU(BuildTarget);
  165. OS := StringToOS(BuildOSTarget);
  166. result := '';
  167. case OS of
  168. freebsd, openbsd, netbsd :
  169. result := '-Fl'+GetDefaultLibGCCDir(CPU, OS, S);
  170. linux :
  171. begin
  172. if CPU in [i386, x86_64] then
  173. begin
  174. AddConditionalLinkerPath('cpui386', i386, result);
  175. AddConditionalLinkerPath('cpux86_64', x86_64, result);
  176. end
  177. else if CPU in [powerpc, powerpc64] then
  178. begin
  179. AddConditionalLinkerPath('cpupowerpc', powerpc, result);
  180. AddConditionalLinkerPath('cpupowerpc64', powerpc64, result);
  181. end
  182. end;
  183. darwin :
  184. begin
  185. AddConditionalLinkerPath('cpui386', i386, result);
  186. AddConditionalLinkerPath('cpux86_64', x86_64, result);
  187. AddConditionalLinkerPath('cpupowerpc', powerpc, result);
  188. AddConditionalLinkerPath('cpupowerpc64', powerpc64, result);
  189. end
  190. end; {case}
  191. end;
  192. procedure Init;
  193. begin
  194. Verbose:=False;
  195. IDEBuildIn:=0;
  196. TemplateParser := TTemplateParser.Create;
  197. TemplateParser.StartDelimiter:='%';
  198. TemplateParser.EndDelimiter:='%';
  199. TemplateParser.Values['FPCVERSION'] := BuildVersion;
  200. TemplateParser.Values['FPCTARGET'] := BuildTarget;
  201. TemplateParser.Values['FPCTARGETOS'] := BuildOSTarget;
  202. TemplateParser.Values['FPCBIN'] := 'fpc';
  203. TemplateParser.Values['PWD'] := GetCurrentDir;
  204. TemplateParser.Values['BUILDDATE'] := DateToStr(Date);
  205. TemplateParser.Values['BUILDTIME'] := TimeToStr(Time);
  206. TemplateParser.Values['LOCALREPOSITORY'] := GetDefaultLocalRepository;
  207. TemplateParser.Values['LOCALBASEPATH'] := GetDefaultLocalBasepath;
  208. TemplateParser.Values['COMPILERCONFIGDIR'] := GetDefaultCompilerConfigDir;
  209. TemplateParser.Values['NEEDCROSSBINUTILSIFDEF'] := GetDefaultNeedCrossBinutilsIfdef;
  210. TemplateParser.Values['GCCLIBPATH'] := GetDefaultGCCDIR;
  211. Cfg:=TStringList.Create;
  212. Cfg.Text:=StrPas(Addr(DefaultConfig[0][1]));
  213. end;
  214. Procedure Done;
  215. begin
  216. FreeAndNil(Cfg);
  217. FreeAndNil(TemplateParser);
  218. end;
  219. Procedure Usage;
  220. begin
  221. Writeln(Format(SUsage00,[ExtractFileName(Paramstr(0))]));
  222. Writeln(SUsage10);
  223. Writeln(SUsage20);
  224. Writeln(SUsage30);
  225. Writeln(SUsage40);
  226. Writeln(SUsage50);
  227. Writeln(SUsage60);
  228. Writeln(SUsage70);
  229. Writeln(SUsage80);
  230. Writeln(SUsage84);
  231. Writeln(SUsage87);
  232. Writeln(SUsage90);
  233. Writeln(SUsage100);
  234. Writeln(SUsage110);
  235. Writeln(SUsage120);
  236. Writeln(SUsage130);
  237. Writeln(SUsage140);
  238. Halt(1);
  239. end;
  240. Procedure UnknownOption(Const S : String);
  241. begin
  242. Writeln(SErrUnknownOption,S);
  243. Usage;
  244. end;
  245. Procedure ShowBuiltIn;
  246. Var
  247. I : Integer;
  248. begin
  249. For I:=0 to Cfg.Count-1 do
  250. Writeln(Cfg[I]);
  251. end;
  252. Procedure ShowBuiltInMacros;
  253. Var
  254. I : Integer;
  255. begin
  256. For I:=0 to TemplateParser.ValueCount-1 do
  257. Writeln(TemplateParser.NamesByIndex[I]+'='+TemplateParser.ValuesByIndex[I]);
  258. end;
  259. Procedure ProcessCommandline;
  260. Var
  261. I : Integer;
  262. S : String;
  263. ShowBuiltinCommand : boolean;
  264. Function GetOptArg : String;
  265. begin
  266. If I=ParamCount then
  267. begin
  268. Writeln(StdErr,Format(SErrArgExpected,[S]));
  269. Halt(1);
  270. end;
  271. inc(I);
  272. Result:=ParamStr(I);
  273. end;
  274. procedure AddPair(const Value: String);
  275. var P: integer;
  276. N,V: String;
  277. begin
  278. P:=Pos('=',Value);
  279. If p=0 then
  280. begin
  281. Writeln(StdErr,Format(SErrIncompletePair,[Value]));
  282. Halt(1);
  283. end;
  284. V:=Value;
  285. N:=Copy(V,1,P-1);
  286. Delete(V,1,P);
  287. TemplateParser.Values[N] := V;
  288. end;
  289. begin
  290. I:=1;
  291. ShowBuiltinCommand := False;
  292. SkipBackup := False;
  293. CreateDir := False;
  294. While( I<=ParamCount) do
  295. begin
  296. S:=Paramstr(i);
  297. If Length(S)<=1 then
  298. UnknownOption(S)
  299. else
  300. case S[2] of
  301. 'v' : Verbose:=True;
  302. 'h' : Usage;
  303. 'b' : ShowBuiltinCommand := true;
  304. 'm' : begin
  305. ShowBuiltinMacros;
  306. halt(0);
  307. end;
  308. 't' : TemplateFileName:=GetOptArg;
  309. 'd' : AddPair(GetOptArg);
  310. 'u' : TemplateParser.Values[GetOptArg]:='';
  311. 'o' : OutputFileName:=GetoptArg;
  312. 's' : SkipBackup:=True;
  313. 'p' : CreateDir:=True;
  314. '0' : IDEBuildin:=0;
  315. '1' : IDEBuildin:=1;
  316. '2' : IDEBuildin:=2;
  317. '3' : IDEBuildin:=3;
  318. '4' : IDEBuildin:=4;
  319. else
  320. UnknownOption(S);
  321. end;
  322. Inc(I);
  323. end;
  324. If (TemplateFileName<>'') then
  325. begin
  326. If Not FileExists(TemplateFileName) then
  327. begin
  328. Writeln(StdErr,Format(SErrNoSuchFile,[TemplateFileName]));
  329. Halt(1);
  330. end;
  331. Cfg.LoadFromFile(TemplateFileName);
  332. TemplateParser.Values['TEMPLATEFILE'] := TemplateFileName;
  333. end
  334. else
  335. begin
  336. case IDEBuildin of
  337. 1:
  338. Cfg.Text:=StrPas(Addr(fpcfg[0][1]));
  339. 2:
  340. Cfg.Text:=StrPas(Addr(fpini[0][1]));
  341. 3:
  342. Cfg.Text:=StrPas(Addr(fppkg[0][1]));
  343. 4:
  344. Cfg.Text:=StrPas(Addr(fppkg_default[0][1]));
  345. end;
  346. TemplateParser.Values['TEMPLATEFILE'] := 'builtin';
  347. end;
  348. if ShowBuiltinCommand then
  349. begin
  350. ShowBuiltIn;
  351. halt(0);
  352. end;
  353. end;
  354. Procedure CreateFile;
  355. Var
  356. Fout : Text;
  357. S,BFN : String;
  358. I : Integer;
  359. begin
  360. if (OutputFileName<>'') and
  361. DirectoryExists(OutputFileName) then
  362. begin
  363. Writeln(StdErr,Format(SErrDestDirectory,[OutputFileName]));
  364. Halt(1);
  365. end;
  366. If (OutputFileName<>'')
  367. and FileExists(OutputFileName)
  368. and not SkipBackup then
  369. begin
  370. BFN:=ChangeFileExt(OutputFileName,'.bak');
  371. If FileExists(BFN) and not DeleteFile(BFN) then
  372. begin
  373. Writeln(StdErr,Format(SErrDelBackupFailed,[BFN]));
  374. Halt(1);
  375. end;
  376. If not RenameFile(OutputFileName,BFN) then
  377. begin
  378. Writeln(StdErr,Format(SErrBackupFailed,[OutputFileName,BFN]));
  379. Halt(1);
  380. end
  381. else
  382. Writeln(Format(SBackupCreated,[ExtractFileName(OutputFileName),ExtractFileName(BFN)]));
  383. end;
  384. if (OutputFileName<>'') and not DirectoryExists(ExtractFilePath(OutputFileName)) then
  385. begin
  386. if CreateDir then
  387. begin
  388. if not ForceDirectories(ExtractFilePath(OutputFileName)) then
  389. begin
  390. Writeln(StdErr,Format(SErrCreateDirFailed,[OutputFileName]));
  391. Halt(1);
  392. end;
  393. end
  394. else
  395. begin
  396. Writeln(StdErr,Format(SErrNoSuchDirectory,[OutputFileName]));
  397. Halt(1);
  398. end;
  399. end;
  400. Assign(Fout,OutputFileName);
  401. Rewrite(FOut);
  402. Try
  403. For I:=0 to Cfg.Count-1 do
  404. begin
  405. S:=Cfg[i];
  406. S := TemplateParser.ParseString(S);
  407. Writeln(FOut,S);
  408. end;
  409. Finally
  410. Close(Fout);
  411. end;
  412. end;
  413. begin
  414. Init;
  415. Try
  416. ProcessCommandLine;
  417. CreateFile;
  418. Finally
  419. Done;
  420. end;
  421. end.