fpcmkcfg.pp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  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. SVersion = 'Version: %s';
  83. SErrUnknownOption = 'Error: Unknown option.';
  84. SErrArgExpected = 'Error: Option "%s" requires an argument.';
  85. SErrIncompletePair = 'Error: Incomplete name-value pair "%s".';
  86. SErrNoSuchFile = 'Error: File "%s" does not exist.';
  87. SErrNoSuchDirectory = 'Error: Directory of file "%s" does not exists. User -p to force creation.';
  88. SErrBackupFailed = 'Error: Backup of file "%s" to "%s" failed.';
  89. SErrDelBackupFailed = 'Error: Delete of old backup file "%s" failed.';
  90. SErrCreateDirFailed = 'Error: Could not create the directory for file "%s".';
  91. SErrDestDirectory = 'Error: The output file "%s" is a directory.';
  92. SWarnIgnoringFile = 'Warning: Ignoring non-existent file: ';
  93. SWarnIgnoringPair = 'Warning: Ignoring wrong name/value pair: ';
  94. SWarngccNotFound = 'Warning: Could not find gcc. Unable to determine the gcclib path.';
  95. SWarnCouldNotExecute= 'Warning: Could not execute command ''%s''';
  96. SBackupCreated = 'Saved old "%s" to "%s"';
  97. Var
  98. Verbose : Boolean;
  99. SkipBackup : Boolean;
  100. CreateDir: Boolean;
  101. Cfg : TStringList;
  102. TemplateParser: TTemplateParser;
  103. TemplateFileName,
  104. OutputFileName : String;
  105. IDEBuildin : Integer;
  106. function IsSuperUser:boolean;
  107. begin
  108. {$ifdef unix}
  109. result:=(fpGetUID=0);
  110. {$else unix}
  111. result:=false;
  112. {$endif unix}
  113. end;
  114. function GetDefaultLocalRepository: string;
  115. begin
  116. {$IFDEF Unix}
  117. result := '{UserDir}.fppkg'+PathDelim;
  118. {$ELSE Unix}
  119. result := '{AppConfigDir}';
  120. {$ENDIF Unix}
  121. end;
  122. function GetDefaultLocalBasepath: string;
  123. begin
  124. {$IFDEF Unix}
  125. result := '~/.fppkg'+PathDelim+'lib'+PathDelim+'fpc'+PathDelim+'$fpcversion';
  126. {$ELSE Unix}
  127. result := '$LOCAL_APPDATA'+PathDelim+'FreePascal'+PathDelim+'fppkg';
  128. {$ENDIF Unix}
  129. end;
  130. function GetDefaultCompilerConfigDir: string;
  131. begin
  132. {$IFDEF Unix}
  133. if IsSuperUser then
  134. result := '/etc/fppkg/'
  135. else
  136. {$ENDIF}
  137. result := '{LocalRepository}config/';
  138. end;
  139. function GetDefaultNeedCrossBinutilsIfdef: string;
  140. begin
  141. result := '';
  142. // On Darwin there is never a need for a crossbinutils prefix
  143. if SameText(BuildOSTarget,'Darwin') then
  144. result := '#IFNDEF ' + BuildOSTarget + LineEnding +
  145. '#DEFINE NEEDCROSSBINUTILS' + LineEnding +
  146. '#ENDIF'
  147. else if (BuildTarget = 'i386') or (BuildTarget = 'x86_64') then
  148. begin
  149. // Cross-binutils are not needed to compile for i386 on an x86_64 system
  150. result := '#IFNDEF CPUI386' + LineEnding +
  151. '#IFNDEF CPUAMD64' + LineEnding +
  152. '#DEFINE NEEDCROSSBINUTILS' + LineEnding +
  153. '#ENDIF' + LineEnding +
  154. '#ENDIF' + LineEnding +
  155. LineEnding +
  156. '#IFNDEF ' + BuildOSTarget + LineEnding +
  157. '#DEFINE NEEDCROSSBINUTILS' + LineEnding +
  158. '#ENDIF';
  159. end
  160. else
  161. result := '#DEFINE NEEDCROSSBINUTILS';
  162. end;
  163. function GetDefaultUserPathSuffix: string;
  164. begin
  165. if not (StringToOS(BuildOSTarget) in AllWindowsOSes) then
  166. Result := 'lib/fpc/{CompilerVersion}'
  167. else
  168. Result := '';
  169. end;
  170. function GetDefaultGCCDir: string;
  171. var
  172. OS: TOS;
  173. CPU: TCPU;
  174. s: string;
  175. procedure AddConditionalLinkerPath(const aCpuType: string; const ACPU: TCPU; var ConfigFileOption: string);
  176. var
  177. path: string;
  178. ErrS: string;
  179. begin
  180. path := GetDefaultLibGCCDir(ACPU, OS, ErrS);
  181. if ErrS<>'' then
  182. Writeln(StdErr, ErrS);
  183. if path <> '' then
  184. begin
  185. if ConfigFileOption<>'' then ConfigFileOption:=ConfigFileOption+LineEnding;
  186. ConfigFileOption := ConfigFileOption + '#ifdef ' + ACpuType + LineEnding + '-Fl' + Path + LineEnding + '#endif';
  187. end;
  188. end;
  189. begin
  190. CPU := StringToCPU(BuildTarget);
  191. OS := StringToOS(BuildOSTarget);
  192. result := '';
  193. case OS of
  194. freebsd, openbsd, netbsd :
  195. result := '-Fl'+GetDefaultLibGCCDir(CPU, OS, S);
  196. linux :
  197. begin
  198. if CPU in [i386, x86_64] then
  199. begin
  200. AddConditionalLinkerPath('cpui386', i386, result);
  201. AddConditionalLinkerPath('cpux86_64', x86_64, result);
  202. end
  203. else if CPU in [powerpc, powerpc64] then
  204. begin
  205. AddConditionalLinkerPath('cpupowerpc', powerpc, result);
  206. AddConditionalLinkerPath('cpupowerpc64', powerpc64, result);
  207. end
  208. end;
  209. darwin :
  210. begin
  211. AddConditionalLinkerPath('cpui386', i386, result);
  212. AddConditionalLinkerPath('cpux86_64', x86_64, result);
  213. AddConditionalLinkerPath('cpupowerpc', powerpc, result);
  214. AddConditionalLinkerPath('cpupowerpc64', powerpc64, result);
  215. { macOS 10.14 or later:
  216. 1) command line tools are installed under /Library/Developer/CommandLineTools
  217. 2) the system libraries still contain i386 code, but the 10.14 sdk doesn't
  218. (-> only use the 10.14 sdk when targeting x86_64 or unknown architectures )
  219. 3) crt1.o is no longer installed under /usr -> add its directory explicitly via
  220. -Fl
  221. We can't detect the macOS version inside fpc.cfg, unfortunately, so we can only
  222. insert this while generating the configuration file.
  223. This will stop working when macOS 10.15 is released without i386 support, but then
  224. users will be responsible for supplying their own i386 SDK anyway.
  225. }
  226. if DirectoryExists('/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk') then
  227. begin
  228. result:=result + LineEnding +
  229. '-FD/Library/Developer/CommandLineTools/usr/bin' + LineEnding +
  230. '#ifdef cpui386' + LineEnding +
  231. '-Fl/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib' + LineEnding +
  232. '#endif' + LineEnding +
  233. '#ifndef cpui386' + LineEnding +
  234. '#ifndef cpupowerpc' + LineEnding +
  235. '#ifndef cpupowerpc64' + LineEnding +
  236. '-XR/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk' + LineEnding +
  237. '#endif' + LineEnding +
  238. '#endif' + LineEnding +
  239. '#endif';
  240. end
  241. else
  242. begin
  243. { add Xcode.app binutils to search path}
  244. result:=result + LineEnding +
  245. '-FD/Applications/Xcode.app/Contents/Developer/usr/bin';
  246. end;
  247. end;
  248. end; {case}
  249. end;
  250. procedure Init;
  251. begin
  252. Verbose:=False;
  253. IDEBuildIn:=0;
  254. TemplateParser := TTemplateParser.Create;
  255. TemplateParser.StartDelimiter:='%';
  256. TemplateParser.EndDelimiter:='%';
  257. TemplateParser.Values['FPCVERSION'] := BuildVersion;
  258. TemplateParser.Values['FPCTARGET'] := BuildTarget;
  259. TemplateParser.Values['FPCTARGETOS'] := BuildOSTarget;
  260. TemplateParser.Values['FPCBIN'] := 'fpc';
  261. TemplateParser.Values['PWD'] := GetCurrentDir;
  262. TemplateParser.Values['BUILDDATE'] := DateToStr(Date);
  263. TemplateParser.Values['BUILDTIME'] := TimeToStr(Time);
  264. TemplateParser.Values['LOCALREPOSITORY'] := GetDefaultLocalRepository;
  265. TemplateParser.Values['LOCALBASEPATH'] := GetDefaultLocalBasepath;
  266. TemplateParser.Values['COMPILERCONFIGDIR'] := GetDefaultCompilerConfigDir;
  267. TemplateParser.Values['NEEDCROSSBINUTILSIFDEF'] := GetDefaultNeedCrossBinutilsIfdef;
  268. TemplateParser.Values['GCCLIBPATH'] := GetDefaultGCCDIR;
  269. TemplateParser.Values['USERPATHSUFFIX'] := GetDefaultUserPathSuffix;
  270. Cfg:=TStringList.Create;
  271. Cfg.Text:=StrPas(Addr(DefaultConfig[0][1]));
  272. end;
  273. Procedure Done;
  274. begin
  275. FreeAndNil(Cfg);
  276. FreeAndNil(TemplateParser);
  277. end;
  278. Procedure Usage;
  279. begin
  280. Writeln(Format(SUsage00,[ExtractFileName(Paramstr(0))]));
  281. Writeln(SUsage10);
  282. Writeln(SUsage20);
  283. Writeln(SUsage30);
  284. Writeln(SUsage40);
  285. Writeln(SUsage50);
  286. Writeln(SUsage60);
  287. Writeln(SUsage70);
  288. Writeln(SUsage80);
  289. Writeln(SUsage84);
  290. Writeln(SUsage87);
  291. Writeln(SUsage90);
  292. Writeln(SUsage95);
  293. Writeln(SUsage100);
  294. Writeln(SUsage110);
  295. Writeln(SUsage120);
  296. Writeln(SUsage130);
  297. Writeln(SUsage140);
  298. Halt(1);
  299. end;
  300. Procedure Version;
  301. var
  302. Version: string;
  303. begin
  304. Version := '';
  305. if version_major <> -1 then
  306. Version := Version + IntToStr(version_major);
  307. if version_minor <> -1 then
  308. Version := Version + '.' + IntToStr(version_minor);
  309. if version_micro <> -1 then
  310. Version := Version + '.' + IntToStr(version_micro);
  311. if version_build <> -1 then
  312. Version := Version + '-' + IntToStr(version_build);
  313. Writeln(Format(SVersion,[Version]));
  314. Halt(0);
  315. end;
  316. Procedure UnknownOption(Const S : String);
  317. begin
  318. Writeln(SErrUnknownOption,S);
  319. Usage;
  320. end;
  321. Procedure ShowBuiltIn;
  322. Var
  323. I : Integer;
  324. begin
  325. For I:=0 to Cfg.Count-1 do
  326. Writeln(Cfg[I]);
  327. end;
  328. Procedure ShowBuiltInMacros;
  329. Var
  330. I : Integer;
  331. begin
  332. For I:=0 to TemplateParser.ValueCount-1 do
  333. Writeln(TemplateParser.NamesByIndex[I]+'='+TemplateParser.ValuesByIndex[I]);
  334. end;
  335. Procedure ProcessCommandline;
  336. Var
  337. I : Integer;
  338. S : String;
  339. ShowBuiltinCommand : boolean;
  340. Function GetOptArg : String;
  341. begin
  342. If I=ParamCount then
  343. begin
  344. Writeln(StdErr,Format(SErrArgExpected,[S]));
  345. Halt(1);
  346. end;
  347. inc(I);
  348. Result:=ParamStr(I);
  349. end;
  350. procedure AddPair(const Value: String);
  351. var P: integer;
  352. N,V: String;
  353. begin
  354. P:=Pos('=',Value);
  355. If p=0 then
  356. begin
  357. Writeln(StdErr,Format(SErrIncompletePair,[Value]));
  358. Halt(1);
  359. end;
  360. V:=Value;
  361. N:=Copy(V,1,P-1);
  362. Delete(V,1,P);
  363. TemplateParser.Values[N] := V;
  364. end;
  365. begin
  366. I:=1;
  367. ShowBuiltinCommand := False;
  368. SkipBackup := False;
  369. CreateDir := False;
  370. While( I<=ParamCount) do
  371. begin
  372. S:=Paramstr(i);
  373. If Length(S)<=1 then
  374. UnknownOption(S)
  375. else
  376. case S[2] of
  377. 'v' : Verbose:=True;
  378. 'V' : Version;
  379. 'h' : Usage;
  380. 'b' : ShowBuiltinCommand := true;
  381. 'm' : begin
  382. ShowBuiltinMacros;
  383. halt(0);
  384. end;
  385. 't' : TemplateFileName:=GetOptArg;
  386. 'd' : AddPair(GetOptArg);
  387. 'u' : TemplateParser.Values[GetOptArg]:='';
  388. 'o' : OutputFileName:=GetoptArg;
  389. 's' : SkipBackup:=True;
  390. 'p' : CreateDir:=True;
  391. '0' : IDEBuildin:=0;
  392. '1' : IDEBuildin:=1;
  393. '2' : IDEBuildin:=2;
  394. '3' : IDEBuildin:=3;
  395. '4' : IDEBuildin:=4;
  396. else
  397. UnknownOption(S);
  398. end;
  399. Inc(I);
  400. end;
  401. If (TemplateFileName<>'') then
  402. begin
  403. If Not FileExists(TemplateFileName) then
  404. begin
  405. Writeln(StdErr,Format(SErrNoSuchFile,[TemplateFileName]));
  406. Halt(1);
  407. end;
  408. Cfg.LoadFromFile(TemplateFileName);
  409. TemplateParser.Values['TEMPLATEFILE'] := TemplateFileName;
  410. end
  411. else
  412. begin
  413. case IDEBuildin of
  414. 1:
  415. Cfg.Text:=StrPas(Addr(fpcfg[0][1]));
  416. 2:
  417. Cfg.Text:=StrPas(Addr(fpini[0][1]));
  418. 3:
  419. Cfg.Text:=StrPas(Addr(fppkg[0][1]));
  420. 4:
  421. Cfg.Text:=StrPas(Addr(fppkg_default[0][1]));
  422. end;
  423. TemplateParser.Values['TEMPLATEFILE'] := 'builtin';
  424. end;
  425. if ShowBuiltinCommand then
  426. begin
  427. ShowBuiltIn;
  428. halt(0);
  429. end;
  430. end;
  431. Procedure CreateFile;
  432. Var
  433. Fout : Text;
  434. S,BFN,ODir : String;
  435. I : Integer;
  436. begin
  437. if (OutputFileName<>'') and
  438. DirectoryExists(OutputFileName) then
  439. begin
  440. Writeln(StdErr,Format(SErrDestDirectory,[OutputFileName]));
  441. Halt(1);
  442. end;
  443. If (OutputFileName<>'')
  444. and FileExists(OutputFileName)
  445. and not SkipBackup then
  446. begin
  447. BFN:=ChangeFileExt(OutputFileName,'.bak');
  448. If FileExists(BFN) and not DeleteFile(BFN) then
  449. begin
  450. Writeln(StdErr,Format(SErrDelBackupFailed,[BFN]));
  451. Halt(1);
  452. end;
  453. If not RenameFile(OutputFileName,BFN) then
  454. begin
  455. Writeln(StdErr,Format(SErrBackupFailed,[OutputFileName,BFN]));
  456. Halt(1);
  457. end
  458. else
  459. Writeln(Format(SBackupCreated,[ExtractFileName(OutputFileName),ExtractFileName(BFN)]));
  460. end;
  461. ODir:=ExtractFilePath(OutputFileName);
  462. if (OutputFileName<>'') and (ODir<>'') and not DirectoryExists(ODir) then
  463. begin
  464. if CreateDir then
  465. begin
  466. if not ForceDirectories(ExtractFilePath(OutputFileName)) then
  467. begin
  468. Writeln(StdErr,Format(SErrCreateDirFailed,[OutputFileName]));
  469. Halt(1);
  470. end;
  471. end
  472. else
  473. begin
  474. Writeln(StdErr,Format(SErrNoSuchDirectory,[OutputFileName]));
  475. Halt(1);
  476. end;
  477. end;
  478. Assign(Fout,OutputFileName);
  479. Rewrite(FOut);
  480. Try
  481. For I:=0 to Cfg.Count-1 do
  482. begin
  483. S:=Cfg[i];
  484. S := TemplateParser.ParseString(S);
  485. Writeln(FOut,S);
  486. end;
  487. Finally
  488. Close(Fout);
  489. end;
  490. end;
  491. begin
  492. Init;
  493. Try
  494. ProcessCommandLine;
  495. CreateFile;
  496. Finally
  497. Done;
  498. end;
  499. end.