fpcmkcfg.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  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. SysUtils,
  16. Classes,
  17. {$ifdef unix}
  18. baseunix,
  19. {$endif}
  20. fpTemplate,
  21. process;
  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. SWarnIgnoringFile = 'Warning: Ignoring non-existent file: ';
  73. SWarnIgnoringPair = 'Warning: Ignoring wrong name/value pair: ';
  74. SWarngccNotFound = 'Warning: Could not find gcc. Unable to determine the gcclib path.';
  75. SBackupCreated = 'Saved old "%s" to "%s"';
  76. Var
  77. Verbose : Boolean;
  78. SkipBackup : Boolean;
  79. CreateDir: Boolean;
  80. Cfg : TStringList;
  81. TemplateParser: TTemplateParser;
  82. TemplateFileName,
  83. OutputFileName : String;
  84. IDEBuildin : Integer;
  85. function IsSuperUser:boolean;
  86. begin
  87. {$ifdef unix}
  88. result:=(fpGetUID=0);
  89. {$else unix}
  90. result:=false;
  91. {$endif unix}
  92. end;
  93. function GetDefaultLocalRepository: string;
  94. begin
  95. {$IFDEF Unix}
  96. result := '{UserDir}.fppkg'+PathDelim;
  97. {$ELSE Unix}
  98. result := '{AppConfigDir}';
  99. {$ENDIF Unix}
  100. end;
  101. function GetDefaultLocalBasepath: string;
  102. begin
  103. {$IFDEF Unix}
  104. result := '~/.fppkg'+PathDelim+'lib'+PathDelim+'fpc'+PathDelim+'$fpcversion';
  105. {$ELSE Unix}
  106. result := '$LOCAL_APPDATA'+PathDelim+'FreePascal'+PathDelim+'fppkg';
  107. {$ENDIF Unix}
  108. end;
  109. function GetDefaultCompilerConfigDir: string;
  110. begin
  111. {$IFDEF Unix}
  112. if IsSuperUser then
  113. result := '/etc/fppkg/'
  114. else
  115. {$ENDIF}
  116. result := '{LocalRepository}config/';
  117. end;
  118. function GetDefaultNeedCrossBinutilsIfdef: string;
  119. begin
  120. result := '';
  121. // On Darwin there is never a need for a crossbinutils prefix
  122. if SameText(BuildOSTarget,'Darwin') then
  123. result := '#IFNDEF ' + BuildOSTarget + LineEnding +
  124. '#DEFINE NEEDCROSSBINUTILS' + LineEnding +
  125. '#ENDIF'
  126. else if (BuildTarget = 'i386') or (BuildTarget = 'x86_64') then
  127. begin
  128. // Cross-binutils are not needed to compile for i386 on an x86_64 system
  129. result := '#IFNDEF CPUI386' + LineEnding +
  130. '#IFNDEF CPUAMD64' + LineEnding +
  131. '#DEFINE NEEDCROSSBINUTILS' + LineEnding +
  132. '#ENDIF' + LineEnding +
  133. '#ENDIF' + LineEnding +
  134. LineEnding +
  135. '#IFNDEF ' + BuildOSTarget + LineEnding +
  136. '#DEFINE NEEDCROSSBINUTILS' + LineEnding +
  137. '#ENDIF';
  138. end
  139. else
  140. result := '#DEFINE NEEDCROSSBINUTILS';
  141. end;
  142. function GetDefaultGCCDir: string;
  143. var GccExecutable: string;
  144. function GetGccExecutable: string;
  145. begin
  146. if GccExecutable='' then
  147. begin
  148. GccExecutable := ExeSearch('gcc'+ExeExt,GetEnvironmentVariable('PATH'));
  149. if GccExecutable='' then
  150. begin
  151. Writeln(StdErr,SWarngccNotFound);
  152. GccExecutable:='-';
  153. end;
  154. end;
  155. if GccExecutable = '-' then
  156. result := ''
  157. else
  158. result := GccExecutable;
  159. end;
  160. function ExecuteProc(const CommandLine: string; ReadStdErr: boolean) : string;
  161. const BufSize=2048;
  162. var S: TProcess;
  163. buf: array[0..BufSize-1] of byte;
  164. count: integer;
  165. begin
  166. S:=TProcess.Create(Nil);
  167. try
  168. S.Commandline:=CommandLine;
  169. S.Options:=[poUsePipes,poWaitOnExit];
  170. S.execute;
  171. Count:=s.output.read(buf,BufSize);
  172. if (count=0) and ReadStdErr then
  173. Count:=s.Stderr.read(buf,BufSize);
  174. setlength(result,count);
  175. move(buf[0],result[1],count);
  176. finally
  177. S.Free;
  178. end;
  179. end;
  180. function Get4thWord(const AString: string): string;
  181. var p: pchar;
  182. spacecount: integer;
  183. StartWord: pchar;
  184. begin
  185. if length(AString)>6 then
  186. begin
  187. p := @AString[1];
  188. spacecount:=0;
  189. StartWord:=nil;
  190. while (not (p^ in [#0,#10,#13])) and ((p^<>' ') or (StartWord=nil)) do
  191. begin
  192. if p^=' ' then
  193. begin
  194. inc(spacecount);
  195. if spacecount=3 then StartWord:=p+1;
  196. end;
  197. inc(p);
  198. end;
  199. if StartWord<>nil then
  200. begin
  201. SetLength(result,p-StartWord);
  202. move(StartWord^,result[1],p-StartWord);
  203. end
  204. else
  205. result := '';
  206. end;
  207. end;
  208. function GetGccDirArch(const ACpuType, GCCParams: string) : string;
  209. var ExecResult: string;
  210. libgccFilename: string;
  211. gccDir: string;
  212. begin
  213. ExecResult:=ExecuteProc(GetGccExecutable+' -v '+GCCParams, True);
  214. libgccFilename:=Get4thWord(ExecResult);
  215. if libgccFilename='' then
  216. libgccFilename:=ExecuteProc(GetGccExecutable+' --print-libgcc-file-name '+GCCParams, False);
  217. gccDir := ExtractFileDir(libgccFilename);
  218. if gccDir='' then
  219. result := ''
  220. else if ACpuType = '' then
  221. result := '-Fl'+gccDir
  222. else
  223. result := '#ifdef ' + ACpuType + LineEnding + '-Fl' + gccDir + LineEnding + '#endif';
  224. end;
  225. begin
  226. result := '';
  227. GccExecutable:='';
  228. if sametext(BuildOSTarget,'Freebsd') or sametext(BuildOSTarget,'Openbsd') then
  229. result := '-Fl/usr/local/lib'
  230. else if sametext(BuildOSTarget,'Netbsd') then
  231. result := '-Fl/usr/pkg/lib'
  232. else if sametext(BuildOSTarget,'Linux') then
  233. begin
  234. if (BuildTarget = 'i386') or (BuildTarget = 'x86_64') then
  235. result := GetGccDirArch('cpui386','-m32') + LineEnding +
  236. GetGccDirArch('cpux86_64','-m64')
  237. else if (BuildTarget = 'powerpc') or (BuildTarget = 'powerpc64') then
  238. result := GetGccDirArch('cpupowerpc','-m32') + LineEnding +
  239. GetGccDirArch('cpupowerpc64','-m64')
  240. end
  241. else if sametext(BuildOSTarget,'Darwin') then
  242. result := GetGccDirArch('cpupowerpc','-arch ppc') + LineEnding +
  243. GetGccDirArch('cpupowerpc64','-arch ppc64') + LineEnding +
  244. GetGccDirArch('cpui386','-arch i386') + LineEnding +
  245. GetGccDirArch('cpux86_64','-arch x86_64');
  246. end;
  247. procedure Init;
  248. begin
  249. Verbose:=False;
  250. IDEBuildIn:=0;
  251. TemplateParser := TTemplateParser.Create;
  252. TemplateParser.StartDelimiter:='%';
  253. TemplateParser.EndDelimiter:='%';
  254. TemplateParser.Values['FPCVERSION'] := BuildVersion;
  255. TemplateParser.Values['FPCTARGET'] := BuildTarget;
  256. TemplateParser.Values['FPCTARGETOS'] := BuildOSTarget;
  257. TemplateParser.Values['FPCBIN'] := 'fpc';
  258. TemplateParser.Values['PWD'] := GetCurrentDir;
  259. TemplateParser.Values['BUILDDATE'] := DateToStr(Date);
  260. TemplateParser.Values['BUILDTIME'] := TimeToStr(Time);
  261. TemplateParser.Values['LOCALREPOSITORY'] := GetDefaultLocalRepository;
  262. TemplateParser.Values['LOCALBASEPATH'] := GetDefaultLocalBasepath;
  263. TemplateParser.Values['COMPILERCONFIGDIR'] := GetDefaultCompilerConfigDir;
  264. TemplateParser.Values['NEEDCROSSBINUTILSIFDEF'] := GetDefaultNeedCrossBinutilsIfdef;
  265. TemplateParser.Values['GCCLIBPATH'] := GetDefaultGCCDIR;
  266. Cfg:=TStringList.Create;
  267. Cfg.Text:=StrPas(Addr(DefaultConfig[0][1]));
  268. end;
  269. Procedure Done;
  270. begin
  271. FreeAndNil(Cfg);
  272. FreeAndNil(TemplateParser);
  273. end;
  274. Procedure Usage;
  275. begin
  276. Writeln(Format(SUsage00,[ExtractFileName(Paramstr(0))]));
  277. Writeln(SUsage10);
  278. Writeln(SUsage20);
  279. Writeln(SUsage30);
  280. Writeln(SUsage40);
  281. Writeln(SUsage50);
  282. Writeln(SUsage60);
  283. Writeln(SUsage70);
  284. Writeln(SUsage80);
  285. Writeln(SUsage84);
  286. Writeln(SUsage87);
  287. Writeln(SUsage90);
  288. Writeln(SUsage100);
  289. Writeln(SUsage110);
  290. Writeln(SUsage120);
  291. Writeln(SUsage130);
  292. Writeln(SUsage140);
  293. Halt(1);
  294. end;
  295. Procedure UnknownOption(Const S : String);
  296. begin
  297. Writeln(SErrUnknownOption,S);
  298. Usage;
  299. end;
  300. Procedure ShowBuiltIn;
  301. Var
  302. I : Integer;
  303. begin
  304. For I:=0 to Cfg.Count-1 do
  305. Writeln(Cfg[I]);
  306. end;
  307. Procedure ShowBuiltInMacros;
  308. Var
  309. I : Integer;
  310. begin
  311. For I:=0 to TemplateParser.ValueCount-1 do
  312. Writeln(TemplateParser.NamesByIndex[I]+'='+TemplateParser.ValuesByIndex[I]);
  313. end;
  314. Procedure ProcessCommandline;
  315. Var
  316. I : Integer;
  317. S : String;
  318. ShowBuiltinCommand : boolean;
  319. Function GetOptArg : String;
  320. begin
  321. If I=ParamCount then
  322. begin
  323. Writeln(StdErr,Format(SErrArgExpected,[S]));
  324. Halt(1);
  325. end;
  326. inc(I);
  327. Result:=ParamStr(I);
  328. end;
  329. procedure AddPair(const Value: String);
  330. var P: integer;
  331. N,V: String;
  332. begin
  333. P:=Pos('=',Value);
  334. If p=0 then
  335. begin
  336. Writeln(StdErr,Format(SErrIncompletePair,[Value]));
  337. Halt(1);
  338. end;
  339. V:=Value;
  340. N:=Copy(V,1,P-1);
  341. Delete(V,1,P);
  342. TemplateParser.Values[N] := V;
  343. end;
  344. begin
  345. I:=1;
  346. ShowBuiltinCommand := False;
  347. SkipBackup := False;
  348. CreateDir := False;
  349. While( I<=ParamCount) do
  350. begin
  351. S:=Paramstr(i);
  352. If Length(S)<=1 then
  353. UnknownOption(S)
  354. else
  355. case S[2] of
  356. 'v' : Verbose:=True;
  357. 'h' : Usage;
  358. 'b' : ShowBuiltinCommand := true;
  359. 'm' : begin
  360. ShowBuiltinMacros;
  361. halt(0);
  362. end;
  363. 't' : TemplateFileName:=GetOptArg;
  364. 'd' : AddPair(GetOptArg);
  365. 'u' : TemplateParser.Values[GetOptArg]:='';
  366. 'o' : OutputFileName:=GetoptArg;
  367. 's' : SkipBackup:=True;
  368. 'p' : CreateDir:=True;
  369. '0' : IDEBuildin:=0;
  370. '1' : IDEBuildin:=1;
  371. '2' : IDEBuildin:=2;
  372. '3' : IDEBuildin:=3;
  373. '4' : IDEBuildin:=4;
  374. else
  375. UnknownOption(S);
  376. end;
  377. Inc(I);
  378. end;
  379. If (TemplateFileName<>'') then
  380. begin
  381. If Not FileExists(TemplateFileName) then
  382. begin
  383. Writeln(StdErr,Format(SErrNoSuchFile,[TemplateFileName]));
  384. Halt(1);
  385. end;
  386. Cfg.LoadFromFile(TemplateFileName);
  387. TemplateParser.Values['TEMPLATEFILE'] := TemplateFileName;
  388. end
  389. else
  390. begin
  391. case IDEBuildin of
  392. 1:
  393. Cfg.Text:=StrPas(Addr(fpcfg[0][1]));
  394. 2:
  395. Cfg.Text:=StrPas(Addr(fpini[0][1]));
  396. 3:
  397. Cfg.Text:=StrPas(Addr(fppkg[0][1]));
  398. 4:
  399. Cfg.Text:=StrPas(Addr(fppkg_default[0][1]));
  400. end;
  401. TemplateParser.Values['TEMPLATEFILE'] := 'builtin';
  402. end;
  403. if ShowBuiltinCommand then
  404. begin
  405. ShowBuiltIn;
  406. halt(0);
  407. end;
  408. end;
  409. Procedure CreateFile;
  410. Var
  411. Fout : Text;
  412. S,BFN : String;
  413. I : Integer;
  414. begin
  415. If (OutputFileName<>'')
  416. and FileExists(OutputFileName)
  417. and not SkipBackup then
  418. begin
  419. BFN:=ChangeFileExt(OutputFileName,'.bak');
  420. If FileExists(BFN) and not DeleteFile(BFN) then
  421. begin
  422. Writeln(StdErr,Format(SErrDelBackupFailed,[BFN]));
  423. Halt(1);
  424. end;
  425. If not RenameFile(OutputFileName,BFN) then
  426. begin
  427. Writeln(StdErr,Format(SErrBackupFailed,[OutputFileName,BFN]));
  428. Halt(1);
  429. end
  430. else
  431. Writeln(Format(SBackupCreated,[ExtractFileName(OutputFileName),ExtractFileName(BFN)]));
  432. end;
  433. if (OutputFileName<>'') and not DirectoryExists(ExtractFilePath(OutputFileName)) then
  434. begin
  435. if CreateDir then
  436. begin
  437. if not ForceDirectories(ExtractFilePath(OutputFileName)) then
  438. begin
  439. Writeln(StdErr,Format(SErrCreateDirFailed,[OutputFileName]));
  440. Halt(1);
  441. end;
  442. end
  443. else
  444. begin
  445. Writeln(StdErr,Format(SErrNoSuchDirectory,[OutputFileName]));
  446. Halt(1);
  447. end;
  448. end;
  449. Assign(Fout,OutputFileName);
  450. Rewrite(FOut);
  451. Try
  452. For I:=0 to Cfg.Count-1 do
  453. begin
  454. S:=Cfg[i];
  455. S := TemplateParser.ParseString(S);
  456. Writeln(FOut,S);
  457. end;
  458. Finally
  459. Close(Fout);
  460. end;
  461. end;
  462. begin
  463. Init;
  464. Try
  465. ProcessCommandLine;
  466. CreateFile;
  467. Finally
  468. Done;
  469. end;
  470. end.