fpc/compiler/compiler.pas

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.