fpcmkcfg.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  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 GetDefaultUserPathSuffix: string;
  145. begin
  146. if not (StringToOS(BuildOSTarget) in AllWindowsOSes) then
  147. Result := 'lib/fpc/{CompilerVersion}'
  148. else
  149. Result := '';
  150. end;
  151. function GetDefaultGCCDir: string;
  152. var
  153. OS: TOS;
  154. CPU: TCPU;
  155. s: string;
  156. procedure AddConditionalLinkerPath(const aCpuType: string; const ACPU: TCPU; var ConfigFileOption: string);
  157. var
  158. path: string;
  159. ErrS: string;
  160. begin
  161. path := GetDefaultLibGCCDir(ACPU, OS, ErrS);
  162. if ErrS<>'' then
  163. Writeln(StdErr, ErrS);
  164. if path <> '' then
  165. begin
  166. if ConfigFileOption<>'' then ConfigFileOption:=ConfigFileOption+LineEnding;
  167. ConfigFileOption := ConfigFileOption + '#ifdef ' + ACpuType + LineEnding + '-Fl' + Path + LineEnding + '#endif';
  168. end;
  169. end;
  170. begin
  171. CPU := StringToCPU(BuildTarget);
  172. OS := StringToOS(BuildOSTarget);
  173. result := '';
  174. case OS of
  175. freebsd, openbsd, netbsd :
  176. result := '-Fl'+GetDefaultLibGCCDir(CPU, OS, S);
  177. linux :
  178. begin
  179. if CPU in [i386, x86_64] then
  180. begin
  181. AddConditionalLinkerPath('cpui386', i386, result);
  182. AddConditionalLinkerPath('cpux86_64', x86_64, result);
  183. end
  184. else if CPU in [powerpc, powerpc64] then
  185. begin
  186. AddConditionalLinkerPath('cpupowerpc', powerpc, result);
  187. AddConditionalLinkerPath('cpupowerpc64', powerpc64, result);
  188. end
  189. end;
  190. darwin :
  191. begin
  192. AddConditionalLinkerPath('cpui386', i386, result);
  193. AddConditionalLinkerPath('cpux86_64', x86_64, result);
  194. AddConditionalLinkerPath('cpupowerpc', powerpc, result);
  195. AddConditionalLinkerPath('cpupowerpc64', powerpc64, result);
  196. { macOS 10.14 or later:
  197. 1) command line tools are installed under /Library/Developer/CommandLineTools
  198. 2) the system libraries still contain i386 code, but the 10.14 sdk doesn't
  199. (-> only use the 10.14 sdk when targeting x86_64 or unknown architectures )
  200. 3) crt1.o is no longer installed under /usr -> add its directory explicitly via
  201. -Fl
  202. We can't detect the macOS version inside fpc.cfg, unfortunately, so we can only
  203. insert this while generating the configuration file.
  204. This will stop working when macOS 10.15 is released without i386 support, but then
  205. users will be responsible for supplying their own i386 SDK anyway.
  206. }
  207. if DirectoryExists('/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk') then
  208. begin
  209. result:=result + LineEnding +
  210. '-FD/Library/Developer/CommandLineTools/usr/bin' + LineEnding +
  211. '#ifdef cpui386' + LineEnding +
  212. '-Fl/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib' + LineEnding +
  213. '#endif' + LineEnding +
  214. '#ifndef cpui386' + LineEnding +
  215. '#ifndef cpupowerpc' + LineEnding +
  216. '#ifndef cpupowerpc64' + LineEnding +
  217. '-XR/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk' + LineEnding +
  218. '#endif' + LineEnding +
  219. '#endif' + LineEnding +
  220. '#endif';
  221. end
  222. else
  223. begin
  224. { add Xcode.app binutils to search path}
  225. result:=result + LineEnding +
  226. '-FD/Applications/Xcode.app/Contents/Developer/usr/bin';
  227. end;
  228. end;
  229. end; {case}
  230. end;
  231. procedure Init;
  232. begin
  233. Verbose:=False;
  234. IDEBuildIn:=0;
  235. TemplateParser := TTemplateParser.Create;
  236. TemplateParser.StartDelimiter:='%';
  237. TemplateParser.EndDelimiter:='%';
  238. TemplateParser.Values['FPCVERSION'] := BuildVersion;
  239. TemplateParser.Values['FPCTARGET'] := BuildTarget;
  240. TemplateParser.Values['FPCTARGETOS'] := BuildOSTarget;
  241. TemplateParser.Values['FPCBIN'] := 'fpc';
  242. TemplateParser.Values['PWD'] := GetCurrentDir;
  243. TemplateParser.Values['BUILDDATE'] := DateToStr(Date);
  244. TemplateParser.Values['BUILDTIME'] := TimeToStr(Time);
  245. TemplateParser.Values['LOCALREPOSITORY'] := GetDefaultLocalRepository;
  246. TemplateParser.Values['LOCALBASEPATH'] := GetDefaultLocalBasepath;
  247. TemplateParser.Values['COMPILERCONFIGDIR'] := GetDefaultCompilerConfigDir;
  248. TemplateParser.Values['NEEDCROSSBINUTILSIFDEF'] := GetDefaultNeedCrossBinutilsIfdef;
  249. TemplateParser.Values['GCCLIBPATH'] := GetDefaultGCCDIR;
  250. TemplateParser.Values['USERPATHSUFFIX'] := GetDefaultUserPathSuffix;
  251. Cfg:=TStringList.Create;
  252. Cfg.Text:=StrPas(Addr(DefaultConfig[0][1]));
  253. end;
  254. Procedure Done;
  255. begin
  256. FreeAndNil(Cfg);
  257. FreeAndNil(TemplateParser);
  258. end;
  259. Procedure Usage;
  260. begin
  261. Writeln(Format(SUsage00,[ExtractFileName(Paramstr(0))]));
  262. Writeln(SUsage10);
  263. Writeln(SUsage20);
  264. Writeln(SUsage30);
  265. Writeln(SUsage40);
  266. Writeln(SUsage50);
  267. Writeln(SUsage60);
  268. Writeln(SUsage70);
  269. Writeln(SUsage80);
  270. Writeln(SUsage84);
  271. Writeln(SUsage87);
  272. Writeln(SUsage90);
  273. Writeln(SUsage100);
  274. Writeln(SUsage110);
  275. Writeln(SUsage120);
  276. Writeln(SUsage130);
  277. Writeln(SUsage140);
  278. Halt(1);
  279. end;
  280. Procedure UnknownOption(Const S : String);
  281. begin
  282. Writeln(SErrUnknownOption,S);
  283. Usage;
  284. end;
  285. Procedure ShowBuiltIn;
  286. Var
  287. I : Integer;
  288. begin
  289. For I:=0 to Cfg.Count-1 do
  290. Writeln(Cfg[I]);
  291. end;
  292. Procedure ShowBuiltInMacros;
  293. Var
  294. I : Integer;
  295. begin
  296. For I:=0 to TemplateParser.ValueCount-1 do
  297. Writeln(TemplateParser.NamesByIndex[I]+'='+TemplateParser.ValuesByIndex[I]);
  298. end;
  299. Procedure ProcessCommandline;
  300. Var
  301. I : Integer;
  302. S : String;
  303. ShowBuiltinCommand : boolean;
  304. Function GetOptArg : String;
  305. begin
  306. If I=ParamCount then
  307. begin
  308. Writeln(StdErr,Format(SErrArgExpected,[S]));
  309. Halt(1);
  310. end;
  311. inc(I);
  312. Result:=ParamStr(I);
  313. end;
  314. procedure AddPair(const Value: String);
  315. var P: integer;
  316. N,V: String;
  317. begin
  318. P:=Pos('=',Value);
  319. If p=0 then
  320. begin
  321. Writeln(StdErr,Format(SErrIncompletePair,[Value]));
  322. Halt(1);
  323. end;
  324. V:=Value;
  325. N:=Copy(V,1,P-1);
  326. Delete(V,1,P);
  327. TemplateParser.Values[N] := V;
  328. end;
  329. begin
  330. I:=1;
  331. ShowBuiltinCommand := False;
  332. SkipBackup := False;
  333. CreateDir := False;
  334. While( I<=ParamCount) do
  335. begin
  336. S:=Paramstr(i);
  337. If Length(S)<=1 then
  338. UnknownOption(S)
  339. else
  340. case S[2] of
  341. 'v' : Verbose:=True;
  342. 'h' : Usage;
  343. 'b' : ShowBuiltinCommand := true;
  344. 'm' : begin
  345. ShowBuiltinMacros;
  346. halt(0);
  347. end;
  348. 't' : TemplateFileName:=GetOptArg;
  349. 'd' : AddPair(GetOptArg);
  350. 'u' : TemplateParser.Values[GetOptArg]:='';
  351. 'o' : OutputFileName:=GetoptArg;
  352. 's' : SkipBackup:=True;
  353. 'p' : CreateDir:=True;
  354. '0' : IDEBuildin:=0;
  355. '1' : IDEBuildin:=1;
  356. '2' : IDEBuildin:=2;
  357. '3' : IDEBuildin:=3;
  358. '4' : IDEBuildin:=4;
  359. else
  360. UnknownOption(S);
  361. end;
  362. Inc(I);
  363. end;
  364. If (TemplateFileName<>'') then
  365. begin
  366. If Not FileExists(TemplateFileName) then
  367. begin
  368. Writeln(StdErr,Format(SErrNoSuchFile,[TemplateFileName]));
  369. Halt(1);
  370. end;
  371. Cfg.LoadFromFile(TemplateFileName);
  372. TemplateParser.Values['TEMPLATEFILE'] := TemplateFileName;
  373. end
  374. else
  375. begin
  376. case IDEBuildin of
  377. 1:
  378. Cfg.Text:=StrPas(Addr(fpcfg[0][1]));
  379. 2:
  380. Cfg.Text:=StrPas(Addr(fpini[0][1]));
  381. 3:
  382. Cfg.Text:=StrPas(Addr(fppkg[0][1]));
  383. 4:
  384. Cfg.Text:=StrPas(Addr(fppkg_default[0][1]));
  385. end;
  386. TemplateParser.Values['TEMPLATEFILE'] := 'builtin';
  387. end;
  388. if ShowBuiltinCommand then
  389. begin
  390. ShowBuiltIn;
  391. halt(0);
  392. end;
  393. end;
  394. Procedure CreateFile;
  395. Var
  396. Fout : Text;
  397. S,BFN : String;
  398. I : Integer;
  399. begin
  400. if (OutputFileName<>'') and
  401. DirectoryExists(OutputFileName) then
  402. begin
  403. Writeln(StdErr,Format(SErrDestDirectory,[OutputFileName]));
  404. Halt(1);
  405. end;
  406. If (OutputFileName<>'')
  407. and FileExists(OutputFileName)
  408. and not SkipBackup then
  409. begin
  410. BFN:=ChangeFileExt(OutputFileName,'.bak');
  411. If FileExists(BFN) and not DeleteFile(BFN) then
  412. begin
  413. Writeln(StdErr,Format(SErrDelBackupFailed,[BFN]));
  414. Halt(1);
  415. end;
  416. If not RenameFile(OutputFileName,BFN) then
  417. begin
  418. Writeln(StdErr,Format(SErrBackupFailed,[OutputFileName,BFN]));
  419. Halt(1);
  420. end
  421. else
  422. Writeln(Format(SBackupCreated,[ExtractFileName(OutputFileName),ExtractFileName(BFN)]));
  423. end;
  424. if (OutputFileName<>'') and not DirectoryExists(ExtractFilePath(OutputFileName)) then
  425. begin
  426. if CreateDir then
  427. begin
  428. if not ForceDirectories(ExtractFilePath(OutputFileName)) then
  429. begin
  430. Writeln(StdErr,Format(SErrCreateDirFailed,[OutputFileName]));
  431. Halt(1);
  432. end;
  433. end
  434. else
  435. begin
  436. Writeln(StdErr,Format(SErrNoSuchDirectory,[OutputFileName]));
  437. Halt(1);
  438. end;
  439. end;
  440. Assign(Fout,OutputFileName);
  441. Rewrite(FOut);
  442. Try
  443. For I:=0 to Cfg.Count-1 do
  444. begin
  445. S:=Cfg[i];
  446. S := TemplateParser.ParseString(S);
  447. Writeln(FOut,S);
  448. end;
  449. Finally
  450. Close(Fout);
  451. end;
  452. end;
  453. begin
  454. Init;
  455. Try
  456. ProcessCommandLine;
  457. CreateFile;
  458. Finally
  459. Done;
  460. end;
  461. end.