123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509 |
- {
- Copyright (c) 2000-2002 by Florian Klaempfl
- This file is the "loader" for the Free Pascal compiler
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ****************************************************************************}
- program fpc;
- {$mode objfpc}{$H+}
- uses
- Sysutils;
- const
- {$ifdef UNIX}
- exeext='';
- {$else UNIX}
- {$ifdef HASAMIGA}
- exeext='';
- {$else}
- {$ifdef NETWARE}
- exeext='.nlm';
- {$else}
- {$ifdef ATARI}
- exeext='.ttp';
- {$else}
- exeext='.exe';
- {$endif ATARI}
- {$endif NETWARE}
- {$endif HASAMIGA}
- {$endif UNIX}
- Const
- {$ifdef darwin}
- { the mach-o format supports "fat" binaries whereby }
- { a single executable contains machine code for }
- { several architectures -> it is counter-intuitive }
- { and non-standard to use different binary names }
- { for cross-compilers vs. native compilers }
- CrossSuffix = '';
- {$else not darwin}
- CrossSuffix = 'ross';
- {$endif not darwin}
- procedure error(const s : string);
- begin
- writeln('Error: ',s);
- halt(1);
- end;
- function processortosuffix(processorstr : string ) : String;
- begin
- case processorstr of
- 'aarch64': Result := 'a64';
- 'arm': Result := 'arm';
- 'avr': Result := 'avr';
- 'i386': Result := '386';
- 'i8086': Result := '8086';
- 'jvm': Result := 'jvm';
- 'loongarch64': Result:='loongarch64';
- 'm68k': Result := '68k';
- 'mips': Result := 'mips';
- 'mipsel': Result := 'mipsel';
- 'powerpc': Result := 'ppc';
- 'powerpc64': Result := 'ppc64';
- 'riscv32': Result := 'rv32';
- 'riscv64': Result := 'rv64';
- 'sparc': Result := 'sparc';
- 'sparc64': Result := 'sparc64';
- 'x86_64': Result := 'x64';
- 'xtensa': Result := 'xtensa';
- 'z80': Result := 'z80';
- 'wasm32': Result := 'wasm32'
- else
- error('Illegal processor type "'+processorstr+'"');
- end;
- end;
- procedure InitPlatform(out ppcbin,processorname : string);
- begin
- {$ifdef i386}
- ppcbin:='ppc386';
- processorname:='i386';
- {$endif i386}
- {$ifdef m68k}
- ppcbin:='ppc68k';
- processorname:='m68k';
- {$endif m68k}
- {$ifdef powerpc}
- ppcbin:='ppcppc';
- processorname:='powerpc';
- {$endif powerpc}
- {$ifdef powerpc64}
- ppcbin:='ppcppc64';
- processorname:='powerpc64';
- {$endif powerpc64}
- {$ifdef arm}
- ppcbin:='ppcarm';
- processorname:='arm';
- {$endif arm}
- {$ifdef aarch64}
- ppcbin:='ppca64';
- processorname:='aarch64';
- {$endif aarch64}
- {$ifdef sparc}
- ppcbin:='ppcsparc';
- processorname:='sparc';
- {$endif sparc}
- {$ifdef sparc64}
- ppcbin:='ppcsparc64';
- processorname:='sparc64';
- {$endif sparc64}
- {$ifdef x86_64}
- ppcbin:='ppcx64';
- processorname:='x86_64';
- {$endif x86_64}
- {$ifdef mipsel}
- ppcbin:='ppcmipsel';
- processorname:='mipsel';
- {$else : not mipsel}
- {$ifdef mips}
- ppcbin:='ppcmips';
- processorname:='mips';
- {$endif mips}
- {$endif not mipsel}
- {$ifdef riscv32}
- ppcbin:='ppcrv32';
- processorname:='riscv32';
- {$endif riscv32}
- {$ifdef riscv64}
- ppcbin:='ppcrv64';
- processorname:='riscv64';
- {$endif riscv64}
- {$ifdef xtensa}
- ppcbin:='ppcxtensa';
- processorname:='xtensa';
- {$endif xtensa}
- {$ifdef wasm32}
- ppcbin:='ppcwasm32';
- processorname:='wasm32';
- {$endif wasm32}
- {$ifdef loongarch64}
- ppcbin:='ppcloongarch64';
- processorname:='loongarch64';
- {$endif loongarch64}
- end;
- function SplitPath(Const HStr:String):String;
- var
- i : longint;
- begin
- i:=Length(Hstr);
- while (i>0) and not(Hstr[i] in ['\','/']) do
- dec(i);
- SplitPath:=Copy(Hstr,1,i);
- end;
- function FileExists ( Const F : String) : Boolean;
- var
- Info : TSearchRec;
- begin
- FileExists:= findfirst(F,fareadonly+faarchive+fahidden,info)=0;
- findclose(Info);
- end;
- var
- warn : Boolean;
- ShowErrno : Boolean;
- extrapath : ansistring;
- function findexe(var ppcbin:string): boolean;
- var
- path : string;
- begin
- { add .exe extension }
- findexe:=false;
- ppcbin:=ppcbin+exeext;
- if (extrapath<>'') and (extrapath[length(extrapath)]<>DirectorySeparator) then
- extrapath:=extrapath+DirectorySeparator;
- { get path of fpc.exe }
- path:=splitpath(paramstr(0));
- { don't try with an empty extra patch, this might have strange results
- if the current directory contains a compiler
- }
- if (extrapath<>'') and FileExists(extrapath+ppcbin) then
- begin
- ppcbin:=extrapath+ppcbin;
- findexe:=true;
- end
- else if (path<>'') and FileExists(path+ppcbin) then
- begin
- ppcbin:=path+ppcbin;
- findexe:=true;
- end
- else
- begin
- path:=ExeSearch(ppcbin,getenvironmentvariable('PATH'));
- if path<>'' then
- begin
- ppcbin:=path;
- findexe:=true;
- end
- end;
- end;
- function findcompiler(basecompiler,cpusuffix,exesuffix : string) : string;
- begin
- Result:=basecompiler;
- if exesuffix<>'' then
- Result:=Result+'-'+exesuffix;
- if not findexe(Result) then
- begin
- if cpusuffix<>'' Then
- begin
- Result:='ppc'+cpusuffix;
- if exesuffix<>'' then
- result:=result+'-'+exesuffix;
- if not findexe(result) then
- result:='';
- end;
- end;
- end;
- procedure CheckSpecialProcessors(processorstr,processorname,ppcbin,cpusuffix,exesuffix : string);
- begin
- { -PB is a special code that will show the
- default compiler and exit immediately. It's
- main usage is for Makefile }
- if processorstr='B' then
- begin
- { report the full name of the ppcbin }
- writeln(findcompiler(ppcbin,cpusuffix,exesuffix));
- halt(0);
- end;
- { -PP is a special code that will show the
- processor and exit immediately. It's
- main usage is for Makefile }
- if processorstr='P' then
- begin
- { report the processor }
- writeln(processorname);
- halt(0);
- end;
- end;
- Function FindConfigFile(const aFile : string; const aCompiler : String) : String;
- // Adapted from check_configfile(fn:string; var foundfn:string):boolean;
- {
- Order to read configuration file :
- Unix:
- 1 - current dir
- 2 - ~/.fpc.cfg
- 3 - configpath
- 4 - /etc
- Windows:
- 1 - current dir
- 2 - home dir of user or all users
- 3 - config path
- 4 - next to binary
- Other:
- 1 - current dir
- 3 - config path
- 4 - next to binary
- }
- var
- {$ifdef unix}sl : rawbytestring;{$endif}
- {$ifdef unix}hs,{$endif} aSearchPath,exepath,configpath : string;
- Procedure AddToPath(aDir : String);
- begin
- if aDir='' then exit;
- if (aSearchPath<>'') then
- aSearchPath:=aSearchPath+PathSeparator;
- aSearchPath:=aSearchPath+IncludeTrailingPathDelimiter(SetDirSeparators(aDir));
- end;
- begin
- if FileExists(aFile) then
- Exit(aFile);
- ExePath:=SetDirSeparators(ExtractFilePath(paramstr(0)));
- aSearchPath:='';
- { retrieve configpath }
- configpath:=SetDirSeparators(GetEnvironmentVariable('PPC_CONFIG_PATH'));
- {$ifdef Unix}
- hs:=SetDirSeparators(GetEnvironmentVariable('HOME'));
- if (hs<>'') then
- begin
- Result:=IncludeTrailingPathDelimiter(hs)+'.'+aFile;
- if FileExists(Result) then
- exit;
- end;
- if configpath='' then
- begin
- {
- We need to search relative to compiler binary, not relative to FPC binary.
- Beware of symlinks !
- }
- hs:=aCompiler;
- While FileGetSymLinkTarget(hs,sl) do
- begin
- if copy(sl,1,1)<>'/' then
- hs:=ExpandFileName(ExtractFilePath(hs)+sl)
- else
- hs:=sl;
- end;
- ExePath:=ExtractFilePath(hs);
- configpath:=ExpandFileName(ExePath+'../etc/');
- end;
- {$endif}
- AddToPath(ConfigPath);
- {$ifdef WINDOWS}
- AddToPath(GetEnvironmentVariable('USERPROFILE'));
- AddToPath(GetEnvironmentVariable('ALLUSERSPROFILE'));
- {$endif WINDOWS}
- {$ifdef Unix}
- AddToPath('/etc/');
- {$else}
- AddToPath(exepath);
- {$endif}
- Result:=FileSearch(aFile,aSearchPath);
- end;
- Procedure CheckWarn(aOpt : String);
- Var
- Len,I : integer;
- begin
- Len:=Length(aOpt);
- For I:=1 to Len do
- begin
- if (aOpt[i]='w') then
- Warn:=(I=Len) or (aOpt[i+1]<>'-');
- if (aOpt[i]='q') then
- ShowErrNo:=(I=Len) or (aOpt[i+1]<>'-');
- end;
- end;
- procedure SetExeSuffix(var ExeSuffix : string; aValue : string);
- begin
- if ExeSuffix='' then
- exesuffix :=aValue
- else if Warn then
- begin
- Write('Warning: ');
- if ShowErrNo then
- Write('(99999) ');
- Writeln('Compiler version already set to: ',ExeSuffix);
- end;
- end;
- Procedure ProcessConfigFile(aFileName : String; var ExeSuffix : String);
- Function Stripline(aLine : String) : string;
- Var
- P : integer;
- begin
- if (aLine<>'') and (aLine[1]=';') then exit;
- Pos('#',aLine); // no ifdef or include.
- if P=0 then
- P:=Length(aLine)+1;
- Result:=Copy(aLine,1,P-1);
- end;
- Var
- aFile : Text;
- aLine : String;
- begin
- Assign(aFile,aFileName);
- {$push}{$I-}
- filemode:=0;
- Reset(aFile);
- {$pop}
- if ioresult<>0 then
- Error('Cannot open config file: '+aFileName);
- While not EOF(aFile) do
- begin
- ReadLn(aFile,aLine);
- aLine:=StripLine(aLine);
- if aLine='' then
- continue;
- if Copy(aLine,1,2)='-V' then
- SetExeSuffix(ExeSuffix,Copy(aLine,3,Length(aLine)-2));
- end;
- {$i+}
- Close(aFile);
- end;
- var
- s,CfgFile: ansistring;
- CPUSuffix, ExeSuffix, SourceCPU, ppcbin, TargetName, TargetCPU: string;
- PPCCommandLine: array of ansistring;
- PPCCommandLineLen: longint;
- i : longint;
- errorvalue : Longint;
- Procedure AddToCommandLine(S : String);
- begin
- PPCCommandLine [PPCCommandLineLen] := S;
- Inc(PPCCommandLineLen);
- end;
- begin
- ppccommandline := [];
- setlength(ppccommandline, paramcount);
- ppccommandlinelen := 0;
- cpusuffix := ''; // if not empty, signals attempt at cross
- // compiler.
- extrapath := '';
- initplatform(ppcbin, SourceCPU);
- exesuffix := ''; { Default is just the name }
- if ParamCount = 0 then
- begin
- SetLength(PPCCommandLine, 1);
- AddToCommandLine('-?F'+ParamStr(0));
- end
- else
- for i := 1 to paramcount do
- begin
- s := ParamStr(i);
- if pos('-t', s) = 1 then
- begin
- targetname := copy(s, 3, length(s)-2);
- AddToCommandLine(S);
- end
- else if pos('-V', s) = 1 then
- SetExeSuffix(ExeSuffix,copy(s, 3, length(s)-2))
- else
- begin
- if pos('-P', s) = 1 then
- begin
- TargetCPU:=copy(s,3,length(s)-2);
- CheckSpecialProcessors(TargetCPU,SourceCPU,ppcbin,cpusuffix,exesuffix);
- if TargetCPU <> SourceCPU then
- begin
- cpusuffix:=processortosuffix(TargetCPU);
- ppcbin:='ppc'+crosssuffix+cpusuffix;
- end;
- end
- else if pos('-Xp',s)=1 then
- extrapath:=copy(s,4,length(s)-3)
- else
- begin
- if pos('-h', s) = 1 then
- AddToCommandLine('-hF'+ParamStr(0))
- else if pos('-?', s) = 1 then
- AddToCommandLine('-?F'+ParamStr(0))
- else
- begin
- AddToCommandLine(S);
- if pos('-v', s) = 1 then
- CheckWarn(Copy(S,3,length(S)-2));
- end;
- end;
- end;
- end;
- ppcbin := findcompiler(ppcbin, cpusuffix, exesuffix);
- if (TargetName<>'') then
- begin
- S:='fpc-'+lowercase(TargetName)+'.cfg';
- CfgFile:=FindConfigFile(s,ppcbin);
- if CfgFile='' then
- Error('Cannot find subtarget config file: '+s);
- ProcessConfigFile(CfgFile,ExeSuffix);
- end;
- SetLength(ppccommandline, ppccommandlinelen);
- { call ppcXXX }
- try
- errorvalue:=ExecuteProcess(ppcbin,ppccommandline);
- except
- on e : exception do
- error(ppcbin+' can''t be executed, error message: '+e.message);
- end;
- if (errorvalue<>0) and
- (paramcount<>0) then
- error(ppcbin+' returned an error exitcode');
- halt(errorvalue);
- end.
|