mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-05 15:28:01 +02:00
448 lines
11 KiB
ObjectPascal
448 lines
11 KiB
ObjectPascal
{
|
|
This unit is the interface of the compiler which can be used by
|
|
external programs to link in the compiler
|
|
|
|
Copyright (c) 1998-2005 by Florian Klaempfl
|
|
|
|
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.
|
|
|
|
****************************************************************************}
|
|
|
|
unit compiler;
|
|
|
|
{$i fpcdefs.inc}
|
|
|
|
{ some units are implicitly needed by the compiler }
|
|
{$WARN 5023 off : Unit "$1" not used in $2}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$ifdef GO32V2}
|
|
emu387,
|
|
{$endif GO32V2}
|
|
{$ifdef WATCOM}
|
|
emu387,
|
|
{$endif WATCOM}
|
|
{$if defined(unix)}
|
|
{ system code page stuff for unix }
|
|
unixcp,
|
|
fpwidestring,
|
|
{$endif}
|
|
{$IFNDEF USE_FAKE_SYSUTILS}
|
|
sysutils,math,
|
|
{$ELSE}
|
|
fksysutl,
|
|
{$ENDIF}
|
|
verbose,comphook,systems,
|
|
cutils,cfileutl,cclasses,globals,options,fmodule,parser,symtable,
|
|
assemble,link,dbgbase,import,export,tokens,wpo
|
|
{ cpu parameter handling }
|
|
,cpupara
|
|
{ procinfo stuff }
|
|
,cpupi
|
|
{ cpu codegenerator }
|
|
,cgcpu
|
|
{$ifndef NOPASS2}
|
|
,cpunode
|
|
{$endif}
|
|
{ cpu targets }
|
|
,cputarg
|
|
{$ifdef llvm}
|
|
,llvmtarg
|
|
{$endif llvm}
|
|
{ system information for source system }
|
|
{ the information about the target os }
|
|
{ are pulled in by the t_* units }
|
|
{$ifdef amiga}
|
|
,i_amiga
|
|
{$endif amiga}
|
|
{$ifdef android}
|
|
,i_android
|
|
{$endif android}
|
|
{$ifdef aros}
|
|
,i_aros
|
|
{$endif}
|
|
{$ifdef atari}
|
|
,i_atari
|
|
{$endif atari}
|
|
{$ifdef beos}
|
|
,i_beos
|
|
{$endif beos}
|
|
{$ifdef bsd}
|
|
{$ifdef darwin}
|
|
,i_darwin
|
|
{$else darwin}
|
|
,i_bsd
|
|
{$endif darwin}
|
|
{$endif bsd}
|
|
{$ifdef gba}
|
|
,i_gba
|
|
{$endif gba}
|
|
{$ifdef go32v2}
|
|
,i_go32v2
|
|
{$endif go32v2}
|
|
{$ifdef haiku}
|
|
,i_haiku
|
|
{$endif haiku}
|
|
{$ifdef human68k}
|
|
,i_human68k
|
|
{$endif human68k}
|
|
{$ifdef linux}
|
|
,i_linux
|
|
{$endif linux}
|
|
{$ifdef macos}
|
|
,i_macos
|
|
{$endif macos}
|
|
{$ifdef morphos}
|
|
,i_morph
|
|
{$endif morphos}
|
|
{$ifdef nds}
|
|
,i_nds
|
|
{$endif nds}
|
|
{$ifdef nwm}
|
|
,i_nwm
|
|
{$endif nwm}
|
|
{$ifdef nwl}
|
|
,i_nwl
|
|
{$endif nwm}
|
|
{$ifdef os2}
|
|
{$ifdef emx}
|
|
,i_emx
|
|
{$else emx}
|
|
,i_os2
|
|
{$endif emx}
|
|
{$endif os2}
|
|
{$ifdef palmos}
|
|
,i_palmos
|
|
{$endif palmos}
|
|
{$ifdef solaris}
|
|
,i_sunos
|
|
{$endif solaris}
|
|
{$ifdef sinclairql}
|
|
,i_sinclairql
|
|
{$endif sinclairql}
|
|
{$ifdef wdosx}
|
|
,i_wdosx
|
|
{$endif wdosx}
|
|
{$ifdef wii}
|
|
,i_wii
|
|
{$endif wii}
|
|
{$ifdef windows}
|
|
,i_win
|
|
{$endif windows}
|
|
{$ifdef symbian}
|
|
,i_symbian
|
|
{$endif symbian}
|
|
{$ifdef nativent}
|
|
,i_nativent
|
|
{$endif nativent}
|
|
{$ifdef aix}
|
|
,i_aix
|
|
{$endif aix}
|
|
,ctask
|
|
,globtype;
|
|
|
|
function Compile(const cmd:TCmdStr):longint;
|
|
|
|
implementation
|
|
|
|
uses
|
|
finput,
|
|
fppu,
|
|
aasmcpu;
|
|
|
|
{$if defined(MEMDEBUG)}
|
|
{$define SHOWUSEDMEM}
|
|
{$endif}
|
|
|
|
var
|
|
CompilerInitedAfterArgs,
|
|
CompilerInited : boolean;
|
|
|
|
|
|
{****************************************************************************
|
|
Compiler
|
|
****************************************************************************}
|
|
|
|
procedure DoneCompiler;
|
|
begin
|
|
if not CompilerInited then
|
|
exit;
|
|
{ Free compiler if args are read }
|
|
if CompilerInitedAfterArgs then
|
|
begin
|
|
CompilerInitedAfterArgs:=false;
|
|
DoneParser;
|
|
DoneImport;
|
|
DoneExport;
|
|
DoneLinker;
|
|
DoneAsm;
|
|
DoneWpo;
|
|
end;
|
|
{ Free memory for the others }
|
|
CompilerInited:=false;
|
|
do_doneSymbolInfo;
|
|
DoneSymtable;
|
|
DoneGlobals;
|
|
DoneFileUtils;
|
|
donetokens;
|
|
DoneTaskHandler;
|
|
end;
|
|
|
|
|
|
procedure InitCompiler(const cmd:TCmdStr);
|
|
begin
|
|
if CompilerInited then
|
|
DoneCompiler;
|
|
{$if defined(unix)}
|
|
{ Set default code page for ansistrings on unix-like systems }
|
|
DefaultSystemCodePage:=GetSystemCodePage;
|
|
{$endif}
|
|
{ inits which need to be done before the arguments are parsed }
|
|
InitSystems;
|
|
{ fileutils depends on source_info so it must be after systems }
|
|
InitFileUtils;
|
|
{ globals depends on source_info so it must be after systems }
|
|
InitGlobals;
|
|
{ verbose depends on exe_path and must be after globals }
|
|
InitVerbose;
|
|
inittokens;
|
|
IniTSymtable; {Must come before read_arguments, to enable macrosymstack}
|
|
do_initSymbolInfo;
|
|
CompilerInited:=true;
|
|
{ this is needed here for the IDE
|
|
in case of compilation failure
|
|
at the previous compile }
|
|
set_current_module(nil);
|
|
{ read the arguments }
|
|
read_arguments(cmd);
|
|
{ inits which depend on arguments }
|
|
InitParser;
|
|
InitImport;
|
|
InitExport;
|
|
InitLinker;
|
|
InitAsm;
|
|
InitWpo;
|
|
|
|
InitTaskHandler;
|
|
CompilerInitedAfterArgs:=true;
|
|
end;
|
|
|
|
|
|
function Compile(const cmd:TCmdStr):longint;
|
|
|
|
{$maxfpuregisters 0}
|
|
|
|
procedure writecmdstrlist(w:longint;l:TCmdStrList);
|
|
var
|
|
hp : TCmdStrListItem;
|
|
begin
|
|
hp:=TCmdStrListItem(l.first);
|
|
while assigned(hp) do
|
|
begin
|
|
Message1(w,hp.str);
|
|
hp:=TCmdStrListItem(hp.next);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
timestr : string[20];
|
|
linkstr : string[64];
|
|
{$ifdef SHOWUSEDMEM}
|
|
hstatus : TFPCHeapStatus;
|
|
{$endif SHOWUSEDMEM}
|
|
ExceptionMask : TFPUExceptionMask;
|
|
totaltime : real;
|
|
m : tppumodule;
|
|
|
|
begin
|
|
m:=nil;
|
|
try
|
|
try
|
|
ExceptionMask:=GetExceptionMask;
|
|
SetExceptionMask([exInvalidOp, exDenormalized, exZeroDivide,
|
|
exOverflow, exUnderflow, exPrecision]);
|
|
|
|
GetLocalTime(startsystime);
|
|
starttime := getrealtime(startsystime);
|
|
|
|
{ Initialize the compiler }
|
|
InitCompiler(cmd);
|
|
|
|
{ show some info }
|
|
Message1(general_t_compilername,FixFileName(system.paramstr(0)));
|
|
Message1(general_d_sourceos,source_info.name);
|
|
Message1(general_i_targetos,target_info.name);
|
|
Message1(general_t_exepath,exepath);
|
|
WriteCmdStrList(general_t_unitpath,unitsearchpath);
|
|
WriteCmdStrList(general_t_includepath,includesearchpath);
|
|
WriteCmdStrList(general_t_librarypath,librarysearchpath);
|
|
WriteCmdStrList(general_t_objectpath,objectsearchpath);
|
|
WriteCmdStrList(general_t_unitscope,namespacelist);
|
|
|
|
{ Compile the program }
|
|
{$ifdef PREPROCWRITE}
|
|
if parapreprocess then
|
|
parser.preprocess(inputfilepath+inputfilename)
|
|
else
|
|
{$endif PREPROCWRITE}
|
|
begin
|
|
m:=tppumodule.create(Nil,'',inputfilepath+inputfilename,false);
|
|
m.state:=ms_compile;
|
|
m.is_initial:=true;
|
|
{ We need to add the initial module manually to the list of units }
|
|
addloadedunit(m);
|
|
main_module:=m;
|
|
m.state:=ms_compile;
|
|
task_handler.addmodule(m);
|
|
task_handler.processqueue;
|
|
end;
|
|
|
|
|
|
{ Show statistics }
|
|
if status.errorcount=0 then
|
|
begin
|
|
totaltime:=getrealtime-starttime;
|
|
if totaltime<0 then
|
|
totaltime:=totaltime+3600.0*24.0;
|
|
if round(frac(totaltime)*10) >= 10 then
|
|
totaltime:=trunc(totaltime) + 1;
|
|
timestr:=tostr(trunc(totaltime))+'.'+tostr(round(frac(totaltime)*10));
|
|
if status.codesize<>aword(-1) then
|
|
linkstr:=', '+tostr(status.codesize)+' ' +MessageStr(general_text_bytes_code)+', '+tostr(status.datasize)+' '+MessageStr(general_text_bytes_data)
|
|
else
|
|
linkstr:='';
|
|
Message3(general_i_abslines_compiled,tostr(status.compiledlines),timestr,linkstr);
|
|
if (Status.Verbosity and V_Warning = V_Warning) and
|
|
(Status.CountWarnings <> 0) then
|
|
Message1 (general_i_number_of_warnings, tostr (Status.CountWarnings));
|
|
if (Status.Verbosity and V_Hint = V_Hint) and
|
|
(Status.CountHints <> 0) then
|
|
Message1 (general_i_number_of_hints, tostr (Status.CountHints));
|
|
if (Status.Verbosity and V_Note = V_Note) and
|
|
(Status.CountNotes <> 0) then
|
|
Message1 (general_i_number_of_notes, tostr (Status.CountNotes));
|
|
end;
|
|
finally
|
|
{ no message possible after this !! }
|
|
DoneCompiler;
|
|
|
|
SetExceptionMask(ExceptionMask);
|
|
end;
|
|
DoneVerbose;
|
|
except
|
|
on EControlCAbort do
|
|
begin
|
|
try
|
|
{ in case of 50 errors, this could cause another exception,
|
|
suppress this exception
|
|
}
|
|
if assigned(m) then
|
|
Message(general_f_compilation_aborted)
|
|
else
|
|
Message(general_f_compiler_aborted);
|
|
except
|
|
on ECompilerAbort do
|
|
;
|
|
end;
|
|
DoneVerbose;
|
|
end;
|
|
on ECompilerAbort do
|
|
begin
|
|
try
|
|
{ in case of 50 errors, this could cause another exception,
|
|
suppress this exception
|
|
}
|
|
{$ifdef DUMP_EXCEPTION_BACKTRACE}
|
|
DumpExceptionBackTrace(stderr);
|
|
{$endif DUMP_EXCEPTION_BACKTRACE}
|
|
Message(general_f_compilation_aborted);
|
|
except
|
|
on ECompilerAbort do
|
|
;
|
|
end;
|
|
DoneVerbose;
|
|
end;
|
|
on ECompilerAbortSilent do
|
|
begin
|
|
DoneVerbose;
|
|
end;
|
|
on EOutOfMemory do
|
|
begin
|
|
try
|
|
Message(general_f_no_memory_left);
|
|
except
|
|
on ECompilerAbort do
|
|
;
|
|
end;
|
|
DoneVerbose;
|
|
end;
|
|
on e : EInOutError do
|
|
begin
|
|
try
|
|
Message1(general_f_ioerror,e.message);
|
|
except
|
|
on ECompilerAbort do
|
|
;
|
|
end;
|
|
DoneVerbose;
|
|
end;
|
|
on e : EOSError do
|
|
begin
|
|
try
|
|
Message1(general_f_oserror,e.message);
|
|
except
|
|
on ECompilerAbort do
|
|
;
|
|
end;
|
|
DoneVerbose;
|
|
end;
|
|
on Exception do
|
|
begin
|
|
{ General catchall, normally not used }
|
|
try
|
|
{ in case of 50 errors, this could cause another exception,
|
|
suppress this exception
|
|
}
|
|
if not exception_raised then
|
|
begin
|
|
exception_raised:=true;
|
|
Message(general_e_exception_raised);
|
|
end
|
|
else
|
|
Message(general_f_compilation_aborted);
|
|
except
|
|
on ECompilerAbort do
|
|
;
|
|
end;
|
|
DoneVerbose;
|
|
Raise;
|
|
end;
|
|
end;
|
|
{$ifdef SHOWUSEDMEM}
|
|
hstatus:=GetFPCHeapStatus;
|
|
Writeln('Max Memory used/heapsize: ',DStr(hstatus.MaxHeapUsed shr 10),'/',DStr(hstatus.MaxHeapSize shr 10),' Kb');
|
|
{$endif SHOWUSEDMEM}
|
|
|
|
{ Set the return value if an error has occurred }
|
|
if status.errorcount=0 then
|
|
result:=0
|
|
else
|
|
result:=1;
|
|
end;
|
|
|
|
end.
|