fpcmkcfg.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. {$mode objfpc}
  2. {$H+}
  3. {$macro on}
  4. {
  5. This file is part of Free Pascal Build tools
  6. Copyright (c) 2005 by Michael Van Canneyt
  7. Create a configuration file
  8. See the file COPYING.FPC, included in this distribution,
  9. for details about the copyright.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. **********************************************************************}
  14. program fpcmkcfg;
  15. uses
  16. fpmkunit,
  17. SysUtils,
  18. Classes,
  19. {$ifdef unix}
  20. baseunix,
  21. {$endif}
  22. fpTemplate;
  23. {
  24. The inc files must be built from a template with the data2inc
  25. command.
  26. data2inc -b -s fpc.cft fpccfg.inc DefaultConfig
  27. data2inc -b -s fpinc.ini fpini.inc fpini
  28. data2inc -b -s fpinc.cfg fpcfg.inc fpcfg
  29. data2inc -b -s fppkg.cfg fppkg.inc fppkg
  30. data2inc -b -s default.cft default.inc fppkg_default
  31. }
  32. {$i fpccfg.inc}
  33. {$i fpini.inc}
  34. {$i fpcfg.inc}
  35. {$i fppkg.inc}
  36. {$i default.inc}
  37. {$ifndef package_version_major}
  38. {$define package_version_major:=0}
  39. {$endif}
  40. {$ifndef package_version_minor}
  41. {$define package_version_minor:=0}
  42. {$endif}
  43. {$ifndef package_version_micro}
  44. {$define package_version_micro:=0}
  45. {$endif}
  46. {$ifndef package_version_build}
  47. {$define package_version_build:=0}
  48. {$endif}
  49. Const
  50. BuildVersion={$I %FPCVERSION%};
  51. BuildTarget={$I %FPCTARGET%};
  52. BuildOSTarget={$I %FPCTARGETOS%};
  53. {$ifdef unix}
  54. ExeExt = '';
  55. {$else unix}
  56. ExeExt = '.exe';
  57. {$endif unix}
  58. version_major = package_version_major;
  59. version_minor = package_version_minor;
  60. version_micro = package_version_micro;
  61. version_build = package_version_build;
  62. Resourcestring
  63. SUsage00 = 'Usage: %s [options]';
  64. SUsage10 = 'Where options is one or more of';
  65. SUSage20 = ' -t filename Template file name. Default is built-in';
  66. SUSage30 = ' -o filename Set output file. Default is standard output.';
  67. SUsage40 = ' -d name=value define name=value pair.';
  68. SUsage50 = ' -h show this help and exit.';
  69. SUsage60 = ' -u name remove name from list of name/value pairs.';
  70. // SUsage70 = ' -l filename read name/value pairs from filename';
  71. SUsage70 = ' -m show builtin macros and exit.';
  72. SUsage80 = ' -b show builtin template and exit.';
  73. SUsage84 = ' -s skip the creation of a backup-file.';
  74. SUsage87 = ' -p force directory creation.';
  75. SUsage90 = ' -v be verbose.';
  76. SUsage95 = ' -V show version.';
  77. Susage100 = ' -0 use built in fpc.cfg template (default)';
  78. Susage110 = ' -1 use built in fp.cfg template';
  79. Susage120 = ' -2 use built in fp.ini template';
  80. Susage130 = ' -3 use built in fppkg.cfg template';
  81. Susage140 = ' -4 use built in fppkg default compiler template';
  82. Susage150 = ' -g add help section to fp.ini';
  83. SVersion = 'Version: %s';
  84. SErrUnknownOption = 'Error: Unknown option.';
  85. SErrArgExpected = 'Error: Option "%s" requires an argument.';
  86. SErrIncompletePair = 'Error: Incomplete name-value pair "%s".';
  87. SErrNoSuchFile = 'Error: File "%s" does not exist.';
  88. SErrNoSuchDirectory = 'Error: Directory of file "%s" does not exists. User -p to force creation.';
  89. SErrBackupFailed = 'Error: Backup of file "%s" to "%s" failed.';
  90. SErrDelBackupFailed = 'Error: Delete of old backup file "%s" failed.';
  91. SErrCreateDirFailed = 'Error: Could not create the directory for file "%s".';
  92. SErrDestDirectory = 'Error: The output file "%s" is a directory.';
  93. SWarnIgnoringFile = 'Warning: Ignoring non-existent file: ';
  94. SWarnIgnoringPair = 'Warning: Ignoring wrong name/value pair: ';
  95. SWarngccNotFound = 'Warning: Could not find gcc. Unable to determine the gcclib path.';
  96. SWarnCouldNotExecute= 'Warning: Could not execute command ''%s''';
  97. SBackupCreated = 'Saved old "%s" to "%s"';
  98. Var
  99. Verbose : Boolean;
  100. SkipBackup : Boolean;
  101. CreateDir: Boolean;
  102. Cfg : TStringList;
  103. TemplateParser: TTemplateParser;
  104. TemplateFileName,
  105. OutputFileName : String;
  106. IDEBuildin : Integer;
  107. function IsSuperUser:boolean;
  108. begin
  109. {$ifdef unix}
  110. result:=(fpGetUID=0);
  111. {$else unix}
  112. result:=false;
  113. {$endif unix}
  114. end;
  115. function GetDefaultLocalRepository: string;
  116. begin
  117. {$IFDEF Unix}
  118. result := '{UserDir}.fppkg'+PathDelim;
  119. {$ELSE Unix}
  120. result := '{AppConfigDir}';
  121. {$ENDIF Unix}
  122. end;
  123. function GetDefaultLocalBasepath: string;
  124. begin
  125. {$IFDEF Unix}
  126. result := '~/.fppkg'+PathDelim+'lib'+PathDelim+'fpc'+PathDelim+'$fpcversion';
  127. {$ELSE Unix}
  128. result := '$LOCAL_APPDATA'+PathDelim+'FreePascal'+PathDelim+'fppkg';
  129. {$ENDIF Unix}
  130. end;
  131. function GetDefaultCompilerConfigDir: string;
  132. begin
  133. {$IFDEF Unix}
  134. if IsSuperUser then
  135. result := '/etc/fppkg/'
  136. else
  137. {$ENDIF}
  138. result := '{LocalRepository}config/';
  139. end;
  140. function GetDefaultNeedCrossBinutilsIfdef: string;
  141. begin
  142. result := '';
  143. // On Darwin there is never a need for a crossbinutils prefix
  144. if SameText(BuildOSTarget,'Darwin') then
  145. result := '#IFNDEF ' + BuildOSTarget + LineEnding +
  146. '#DEFINE NEEDCROSSBINUTILS' + LineEnding +
  147. '#ENDIF'
  148. else if (BuildTarget = 'i386') or (BuildTarget = 'x86_64') then
  149. begin
  150. // Cross-binutils are not needed to compile for i386 on an x86_64 system
  151. result := '#IFNDEF CPUI386' + LineEnding +
  152. '#IFNDEF CPUAMD64' + LineEnding +
  153. '#DEFINE NEEDCROSSBINUTILS' + LineEnding +
  154. '#ENDIF' + LineEnding +
  155. '#ENDIF' + LineEnding +
  156. LineEnding +
  157. '#IFNDEF ' + BuildOSTarget + LineEnding +
  158. '#DEFINE NEEDCROSSBINUTILS' + LineEnding +
  159. '#ENDIF';
  160. end
  161. else
  162. result := '#DEFINE NEEDCROSSBINUTILS';
  163. end;
  164. function GetDefaultUserPathSuffix: string;
  165. begin
  166. if not (StringToOS(BuildOSTarget) in AllWindowsOSes) then
  167. Result := 'lib/fpc/{CompilerVersion}'
  168. else
  169. Result := '';
  170. end;
  171. function GetDefaultGCCDir: string;
  172. var
  173. OS: TOS;
  174. CPU: TCPU;
  175. s: string;
  176. procedure AddConditionalLinkerPath(const aCpuType: string; const ACPU: TCPU; var ConfigFileOption: string);
  177. var
  178. path: string;
  179. ErrS: string;
  180. begin
  181. path := GetDefaultLibGCCDir(ACPU, OS, ErrS);
  182. if ErrS<>'' then
  183. Writeln(StdErr, ErrS);
  184. if path <> '' then
  185. begin
  186. if ConfigFileOption<>'' then ConfigFileOption:=ConfigFileOption+LineEnding;
  187. ConfigFileOption := ConfigFileOption + '#ifdef ' + ACpuType + LineEnding + '-Fl' + Path + LineEnding + '#endif';
  188. end;
  189. end;
  190. begin
  191. CPU := StringToCPU(BuildTarget);
  192. OS := StringToOS(BuildOSTarget);
  193. result := '';
  194. case OS of
  195. freebsd, openbsd, netbsd :
  196. result := '-Fl'+GetDefaultLibGCCDir(CPU, OS, S);
  197. linux :
  198. begin
  199. if CPU in [i386, x86_64] then
  200. begin
  201. AddConditionalLinkerPath('cpui386', i386, result);
  202. AddConditionalLinkerPath('cpux86_64', x86_64, result);
  203. end
  204. else if CPU in [powerpc, powerpc64] then
  205. begin
  206. AddConditionalLinkerPath('cpupowerpc', powerpc, result);
  207. AddConditionalLinkerPath('cpupowerpc64', powerpc64, result);
  208. end
  209. else if CPU in [arm, aarch64] then
  210. begin
  211. AddConditionalLinkerPath('cpuarm', arm, result);
  212. AddConditionalLinkerPath('cpuaarch64', aarch64, result);
  213. end
  214. else
  215. result := '-Fl'+GetDefaultLibGCCDir(CPU, OS, S);
  216. end;
  217. darwin :
  218. begin
  219. AddConditionalLinkerPath('cpui386', i386, result);
  220. AddConditionalLinkerPath('cpux86_64', x86_64, result);
  221. AddConditionalLinkerPath('cpupowerpc', powerpc, result);
  222. AddConditionalLinkerPath('cpupowerpc64', powerpc64, result);
  223. AddConditionalLinkerPath('cpuaarch64', aarch64, result);
  224. { macOS 10.14 or later:
  225. 1) command line tools are installed under /Library/Developer/CommandLineTools
  226. 2) the system libraries still contain i386 code, but the 10.14 sdk doesn't
  227. (-> only use the 10.14 sdk when targeting x86_64 or unknown architectures )
  228. 3) crt1.o is no longer installed under /usr -> add its directory explicitly via
  229. -Fl
  230. We can't detect the macOS version inside fpc.cfg, unfortunately, so we can only
  231. insert this while generating the configuration file.
  232. This will stop working when macOS 10.15 is released without i386 support, but then
  233. users will be responsible for supplying their own i386 SDK anyway.
  234. }
  235. if DirectoryExists('/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk') then
  236. begin
  237. result:=result + LineEnding +
  238. '-FD/Library/Developer/CommandLineTools/usr/bin' + LineEnding +
  239. '#ifdef cpui386' + LineEnding +
  240. '-Fl/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib' + LineEnding +
  241. '#endif' + LineEnding +
  242. '#ifndef cpui386' + LineEnding +
  243. '#ifndef cpupowerpc' + LineEnding +
  244. '#ifndef cpupowerpc64' + LineEnding +
  245. '-XR/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk' + LineEnding +
  246. '#endif' + LineEnding +
  247. '#endif' + LineEnding +
  248. '#endif';
  249. end
  250. else
  251. begin
  252. { add Xcode.app binutils to search path}
  253. result:=result + LineEnding +
  254. '-FD/Applications/Xcode.app/Contents/Developer/usr/bin';
  255. end;
  256. end;
  257. end; {case}
  258. end;
  259. procedure Init;
  260. begin
  261. Verbose:=False;
  262. IDEBuildIn:=0;
  263. TemplateParser := TTemplateParser.Create;
  264. TemplateParser.StartDelimiter:='%';
  265. TemplateParser.EndDelimiter:='%';
  266. TemplateParser.Values['FPCVERSION'] := BuildVersion;
  267. TemplateParser.Values['FPCTARGET'] := BuildTarget;
  268. TemplateParser.Values['FPCTARGETOS'] := BuildOSTarget;
  269. TemplateParser.Values['FPCBIN'] := 'fpc';
  270. TemplateParser.Values['PWD'] := GetCurrentDir;
  271. TemplateParser.Values['BUILDDATE'] := DateToStr(Date);
  272. TemplateParser.Values['BUILDTIME'] := TimeToStr(Time);
  273. TemplateParser.Values['LOCALREPOSITORY'] := GetDefaultLocalRepository;
  274. TemplateParser.Values['LOCALBASEPATH'] := GetDefaultLocalBasepath;
  275. TemplateParser.Values['COMPILERCONFIGDIR'] := GetDefaultCompilerConfigDir;
  276. TemplateParser.Values['NEEDCROSSBINUTILSIFDEF'] := GetDefaultNeedCrossBinutilsIfdef;
  277. TemplateParser.Values['GCCLIBPATH'] := GetDefaultGCCDIR;
  278. TemplateParser.Values['USERPATHSUFFIX'] := GetDefaultUserPathSuffix;
  279. Cfg:=TStringList.Create;
  280. Cfg.Text:=StrPas(Addr(DefaultConfig[0][1]));
  281. end;
  282. Procedure Done;
  283. begin
  284. FreeAndNil(Cfg);
  285. FreeAndNil(TemplateParser);
  286. end;
  287. Procedure Usage;
  288. begin
  289. Writeln(Format(SUsage00,[ExtractFileName(Paramstr(0))]));
  290. Writeln(SUsage10);
  291. Writeln(SUsage20);
  292. Writeln(SUsage30);
  293. Writeln(SUsage40);
  294. Writeln(SUsage50);
  295. Writeln(SUsage60);
  296. Writeln(SUsage70);
  297. Writeln(SUsage80);
  298. Writeln(SUsage84);
  299. Writeln(SUsage87);
  300. Writeln(SUsage90);
  301. Writeln(SUsage95);
  302. Writeln(SUsage100);
  303. Writeln(SUsage110);
  304. Writeln(SUsage120);
  305. Writeln(SUsage130);
  306. Writeln(SUsage140);
  307. Writeln(SUsage150);
  308. Halt(1);
  309. end;
  310. Procedure Version;
  311. var
  312. Version: string;
  313. begin
  314. Version := '';
  315. if version_major <> -1 then
  316. Version := Version + IntToStr(version_major);
  317. if version_minor <> -1 then
  318. Version := Version + '.' + IntToStr(version_minor);
  319. if version_micro <> -1 then
  320. Version := Version + '.' + IntToStr(version_micro);
  321. if version_build <> -1 then
  322. Version := Version + '-' + IntToStr(version_build);
  323. Writeln(Format(SVersion,[Version]));
  324. Halt(0);
  325. end;
  326. Procedure UnknownOption(Const S : String);
  327. begin
  328. Writeln(SErrUnknownOption,S);
  329. Usage;
  330. end;
  331. Procedure ShowBuiltIn;
  332. Var
  333. I : Integer;
  334. begin
  335. For I:=0 to Cfg.Count-1 do
  336. Writeln(Cfg[I]);
  337. end;
  338. Procedure ShowBuiltInMacros;
  339. Var
  340. I : Integer;
  341. begin
  342. For I:=0 to TemplateParser.ValueCount-1 do
  343. Writeln(TemplateParser.NamesByIndex[I]+'='+TemplateParser.ValuesByIndex[I]);
  344. end;
  345. Procedure ProcessCommandline;
  346. Var
  347. I : Integer;
  348. S : String;
  349. ShowBuiltinCommand : boolean;
  350. AppendHelp : boolean;
  351. Function GetOptArg : String;
  352. begin
  353. If I=ParamCount then
  354. begin
  355. Writeln(StdErr,Format(SErrArgExpected,[S]));
  356. Halt(1);
  357. end;
  358. inc(I);
  359. Result:=ParamStr(I);
  360. end;
  361. procedure AddPair(const Value: String);
  362. var P: integer;
  363. N,V: String;
  364. begin
  365. P:=Pos('=',Value);
  366. If p=0 then
  367. begin
  368. Writeln(StdErr,Format(SErrIncompletePair,[Value]));
  369. Halt(1);
  370. end;
  371. V:=Value;
  372. N:=Copy(V,1,P-1);
  373. Delete(V,1,P);
  374. TemplateParser.Values[N] := V;
  375. end;
  376. begin
  377. I:=1;
  378. ShowBuiltinCommand := False;
  379. SkipBackup := False;
  380. CreateDir := False;
  381. AppendHelp:=False;
  382. While( I<=ParamCount) do
  383. begin
  384. S:=Paramstr(i);
  385. If Length(S)<=1 then
  386. UnknownOption(S)
  387. else
  388. case S[2] of
  389. 'v' : Verbose:=True;
  390. 'V' : Version;
  391. 'h' : Usage;
  392. 'b' : ShowBuiltinCommand := true;
  393. 'm' : begin
  394. ShowBuiltinMacros;
  395. halt(0);
  396. end;
  397. 'g' : AppendHelp:=True;
  398. 't' : TemplateFileName:=GetOptArg;
  399. 'd' : AddPair(GetOptArg);
  400. 'u' : TemplateParser.Values[GetOptArg]:='';
  401. 'o' : OutputFileName:=GetoptArg;
  402. 's' : SkipBackup:=True;
  403. 'p' : CreateDir:=True;
  404. '0' : IDEBuildin:=0;
  405. '1' : IDEBuildin:=1;
  406. '2' : IDEBuildin:=2;
  407. '3' : IDEBuildin:=3;
  408. '4' : IDEBuildin:=4;
  409. else
  410. UnknownOption(S);
  411. end;
  412. Inc(I);
  413. end;
  414. If (TemplateFileName<>'') then
  415. begin
  416. If Not FileExists(TemplateFileName) then
  417. begin
  418. Writeln(StdErr,Format(SErrNoSuchFile,[TemplateFileName]));
  419. Halt(1);
  420. end;
  421. Cfg.LoadFromFile(TemplateFileName);
  422. TemplateParser.Values['TEMPLATEFILE'] := TemplateFileName;
  423. end
  424. else
  425. begin
  426. case IDEBuildin of
  427. 1:
  428. Cfg.Text:=StrPas(Addr(fpcfg[0][1]));
  429. 2:
  430. Cfg.Text:=StrPas(Addr(fpini[0][1]));
  431. 3:
  432. Cfg.Text:=StrPas(Addr(fppkg[0][1]));
  433. 4:
  434. Cfg.Text:=StrPas(Addr(fppkg_default[0][1]));
  435. end;
  436. TemplateParser.Values['TEMPLATEFILE'] := 'builtin';
  437. end;
  438. If AppendHelp Then
  439. Cfg.Text:=Cfg.Text+'[Help]'+LineEnding+'Files="%basepath%/help/toc.chm;%basepath%/help/fcl.chm;%basepath%/help/ref.chm;%basepath%/help/rtl.chm;%basepath%/help/prog.chm;%basepath%/help/user.chm;%basepath%/help/fclres.chm"'+LineEnding;
  440. if ShowBuiltinCommand then
  441. begin
  442. ShowBuiltIn;
  443. halt(0);
  444. end;
  445. end;
  446. Procedure CreateFile;
  447. Var
  448. Fout : Text;
  449. S,BFN,ODir : String;
  450. I : Integer;
  451. begin
  452. if (OutputFileName<>'') and
  453. DirectoryExists(OutputFileName) then
  454. begin
  455. Writeln(StdErr,Format(SErrDestDirectory,[OutputFileName]));
  456. Halt(1);
  457. end;
  458. If (OutputFileName<>'')
  459. and FileExists(OutputFileName)
  460. and not SkipBackup then
  461. begin
  462. BFN:=ChangeFileExt(OutputFileName,'.bak');
  463. If FileExists(BFN) and not DeleteFile(BFN) then
  464. begin
  465. Writeln(StdErr,Format(SErrDelBackupFailed,[BFN]));
  466. Halt(1);
  467. end;
  468. If not RenameFile(OutputFileName,BFN) then
  469. begin
  470. Writeln(StdErr,Format(SErrBackupFailed,[OutputFileName,BFN]));
  471. Halt(1);
  472. end
  473. else
  474. Writeln(Format(SBackupCreated,[ExtractFileName(OutputFileName),ExtractFileName(BFN)]));
  475. end;
  476. ODir:=ExtractFilePath(OutputFileName);
  477. if (OutputFileName<>'') and (ODir<>'') and not DirectoryExists(ODir) then
  478. begin
  479. if CreateDir then
  480. begin
  481. if not ForceDirectories(ExtractFilePath(OutputFileName)) then
  482. begin
  483. Writeln(StdErr,Format(SErrCreateDirFailed,[OutputFileName]));
  484. Halt(1);
  485. end;
  486. end
  487. else
  488. begin
  489. Writeln(StdErr,Format(SErrNoSuchDirectory,[OutputFileName]));
  490. Halt(1);
  491. end;
  492. end;
  493. Assign(Fout,OutputFileName);
  494. Rewrite(FOut);
  495. Try
  496. For I:=0 to Cfg.Count-1 do
  497. begin
  498. S:=Cfg[i];
  499. S := TemplateParser.ParseString(S);
  500. Writeln(FOut,S);
  501. end;
  502. Finally
  503. Close(Fout);
  504. end;
  505. end;
  506. begin
  507. Init;
  508. Try
  509. ProcessCommandLine;
  510. CreateFile;
  511. Finally
  512. Done;
  513. end;
  514. end.