fpc/compiler/fmodule.pas
carl 21b3a10f02 + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
+ try to fix temp allocation (still in ifdef)
+ generic constructor calls
+ start of tassembler / tmodulebase class cleanup
2002-05-16 19:46:34 +00:00

604 lines
18 KiB
ObjectPascal

{
$Id$
Copyright (c) 1998-2002 by Florian Klaempfl
This unit implements the first loading and searching of the modules
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 fmodule;
{$i fpcdefs.inc}
{$ifdef go32v2}
{$define shortasmprefix}
{$endif}
{$ifdef OS2}
{ Allthough OS/2 supports long filenames I play it safe and
use 8.3 filenames, because this allows the compiler to run
on a FAT partition. (DM) }
{$define shortasmprefix}
{$endif}
interface
uses
cutils,cclasses,
globals,finput,
symbase;
const
maxunits = 1024;
type
trecompile_reason = (rr_unknown,
rr_noppu,rr_sourcenewer,rr_build,rr_crcchanged
);
TExternalsItem=class(TLinkedListItem)
public
found : longbool;
data : pstring;
constructor Create(const s:string);
Destructor Destroy;override;
end;
tlinkcontaineritem=class(tlinkedlistitem)
public
data : pstring;
needlink : cardinal;
constructor Create(const s:string;m:cardinal);
destructor Destroy;override;
end;
tlinkcontainer=class(tlinkedlist)
procedure add(const s : string;m:cardinal);
function get(var m:cardinal) : string;
function getusemask(mask:cardinal) : string;
function find(const s:string):boolean;
end;
{$ifndef NEWMAP}
tunitmap = array[0..maxunits-1] of pointer;
punitmap = ^tunitmap;
{$else NEWMAP}
tunitmap = array[0..maxunits-1] of tmodule;
punitmap = ^tunitmap;
{$endif NEWMAP}
tmodule = class(tmodulebase)
compiled, { unit is already compiled }
do_reload, { force reloading of the unit }
do_compile, { need to compile the sources }
sources_avail, { if all sources are reachable }
sources_checked, { if there is already done a check for the sources }
is_unit,
in_second_compile, { is this unit being compiled for the 2nd time? }
in_second_load, { is this unit PPU loaded a 2nd time? }
in_implementation, { processing the implementation part? }
in_global : boolean; { allow global settings }
recompile_reason : trecompile_reason; { the reason why the unit should be recompiled }
crc,
interface_crc : cardinal;
flags : cardinal; { the PPU flags }
islibrary : boolean; { if it is a library (win32 dll) }
map : punitmap; { mapping of all used units }
unitcount : longint; { local unit counter }
globalsymtable, { pointer to the global symtable of this unit }
localsymtable : tsymtable;{ pointer to the local symtable of this unit }
scanner : pointer; { scanner object used }
loaded_from : tmodule;
uses_imports : boolean; { Set if the module imports from DLL's.}
imports : tlinkedlist;
_exports : tlinkedlist;
externals : tlinkedlist; {Only for DLL scanners by using Unix-style $LINKLIB }
resourcefiles : tstringlist;
linkunitofiles,
linkunitstaticlibs,
linkunitsharedlibs,
linkotherofiles, { objects,libs loaded from the source }
linkothersharedlibs, { using $L or $LINKLIB or import lib (for linux) }
linkotherstaticlibs : tlinkcontainer;
used_units : tlinkedlist;
dependent_units : tlinkedlist;
localunitsearchpath, { local searchpaths }
localobjectsearchpath,
localincludesearchpath,
locallibrarysearchpath : TSearchPathList;
asmprefix : pstring; { prefix for the smartlink asmfiles }
constructor create(const s:string;_is_unit:boolean);
destructor destroy;override;
procedure reset;virtual;
procedure numberunits;
end;
tused_unit = class(tlinkedlistitem)
unitid : longint;
name : pstring;
realname : pstring;
checksum,
interface_checksum : cardinal;
loaded : boolean;
in_uses,
in_interface,
is_stab_written : boolean;
u : tmodule;
constructor create(_u : tmodule;intface:boolean);
constructor create_to_load(const n:string;c,intfc:cardinal;intface:boolean);
destructor destroy;override;
end;
tdependent_unit = class(tlinkedlistitem)
u : tmodule;
constructor create(_u : tmodule);
end;
var
main_module : tmodule; { Main module of the program }
current_module : tmodule; { Current module which is compiled or loaded }
compiled_module : tmodule; { Current module which is compiled }
usedunits : tlinkedlist; { Used units for this program }
loaded_units : tlinkedlist; { All loaded units }
SmartLinkOFiles : TStringList; { List of .o files which are generated,
used to delete them after linking }
function get_source_file(moduleindex,fileindex : longint) : tinputfile;
implementation
uses
{$ifdef delphi}
dmisc,
{$else}
dos,
{$endif}
verbose,systems,
scanner;
{*****************************************************************************
Global Functions
*****************************************************************************}
function get_source_file(moduleindex,fileindex : longint) : tinputfile;
var
hp : tmodule;
begin
hp:=tmodule(loaded_units.first);
while assigned(hp) and (hp.unit_index<>moduleindex) do
hp:=tmodule(hp.next);
if assigned(hp) then
get_source_file:=hp.sourcefiles.get_file(fileindex)
else
get_source_file:=nil;
end;
{****************************************************************************
TLinkContainerItem
****************************************************************************}
constructor TLinkContainerItem.Create(const s:string;m:cardinal);
begin
inherited Create;
data:=stringdup(s);
needlink:=m;
end;
destructor TLinkContainerItem.Destroy;
begin
stringdispose(data);
end;
{****************************************************************************
TLinkContainer
****************************************************************************}
procedure TLinkContainer.add(const s : string;m:cardinal);
begin
inherited concat(TLinkContainerItem.Create(s,m));
end;
function TLinkContainer.get(var m:cardinal) : string;
var
p : tlinkcontaineritem;
begin
p:=tlinkcontaineritem(inherited getfirst);
if p=nil then
begin
get:='';
m:=0;
end
else
begin
get:=p.data^;
m:=p.needlink;
p.free;
end;
end;
function TLinkContainer.getusemask(mask:cardinal) : string;
var
p : tlinkcontaineritem;
found : boolean;
begin
found:=false;
repeat
p:=tlinkcontaineritem(inherited getfirst);
if p=nil then
begin
getusemask:='';
exit;
end;
getusemask:=p.data^;
found:=(p.needlink and mask)<>0;
p.free;
until found;
end;
function TLinkContainer.find(const s:string):boolean;
var
newnode : tlinkcontaineritem;
begin
find:=false;
newnode:=tlinkcontaineritem(First);
while assigned(newnode) do
begin
if newnode.data^=s then
begin
find:=true;
exit;
end;
newnode:=tlinkcontaineritem(newnode.next);
end;
end;
{****************************************************************************
TExternalsItem
****************************************************************************}
constructor tExternalsItem.Create(const s:string);
begin
inherited Create;
found:=false;
data:=stringdup(s);
end;
destructor tExternalsItem.Destroy;
begin
stringdispose(data);
inherited;
end;
{****************************************************************************
TUSED_UNIT
****************************************************************************}
constructor tused_unit.create(_u : tmodule;intface:boolean);
begin
u:=_u;
in_interface:=intface;
in_uses:=false;
is_stab_written:=false;
loaded:=true;
name:=stringdup(_u.modulename^);
realname:=stringdup(_u.realmodulename^);
checksum:=_u.crc;
interface_checksum:=_u.interface_crc;
unitid:=0;
end;
constructor tused_unit.create_to_load(const n:string;c,intfc:cardinal;intface:boolean);
begin
u:=nil;
in_interface:=intface;
in_uses:=false;
is_stab_written:=false;
loaded:=false;
name:=stringdup(upper(n));
realname:=stringdup(n);
checksum:=c;
interface_checksum:=intfc;
unitid:=0;
end;
destructor tused_unit.destroy;
begin
stringdispose(realname);
stringdispose(name);
inherited destroy;
end;
{****************************************************************************
TDENPENDENT_UNIT
****************************************************************************}
constructor tdependent_unit.create(_u : tmodule);
begin
u:=_u;
end;
{****************************************************************************
TMODULE
****************************************************************************}
constructor tmodule.create(const s:string;_is_unit:boolean);
var
p : dirstr;
n : namestr;
e : extstr;
begin
FSplit(s,p,n,e);
{ Programs have the name 'Program' to don't conflict with dup id's }
if _is_unit then
inherited create(n)
else
inherited create('Program');
mainsource:=stringdup(s);
{ Dos has the famous 8.3 limit :( }
{$ifdef shortasmprefix}
asmprefix:=stringdup(FixFileName('as'));
{$else}
asmprefix:=stringdup(FixFileName(n));
{$endif}
setfilename(p+n,true);
localunitsearchpath:=TSearchPathList.Create;
localobjectsearchpath:=TSearchPathList.Create;
localincludesearchpath:=TSearchPathList.Create;
locallibrarysearchpath:=TSearchPathList.Create;
used_units:=TLinkedList.Create;
dependent_units:=TLinkedList.Create;
resourcefiles:=TStringList.Create;
linkunitofiles:=TLinkContainer.Create;
linkunitstaticlibs:=TLinkContainer.Create;
linkunitsharedlibs:=TLinkContainer.Create;
linkotherofiles:=TLinkContainer.Create;
linkotherstaticlibs:=TLinkContainer.Create;
linkothersharedlibs:=TLinkContainer.Create;
crc:=0;
interface_crc:=0;
flags:=0;
scanner:=nil;
map:=nil;
globalsymtable:=nil;
localsymtable:=nil;
loaded_from:=nil;
do_reload:=false;
unitcount:=1;
do_compile:=false;
sources_avail:=true;
sources_checked:=false;
compiled:=false;
recompile_reason:=rr_unknown;
in_second_load:=false;
in_second_compile:=false;
in_implementation:=false;
in_global:=true;
is_unit:=_is_unit;
islibrary:=false;
uses_imports:=false;
imports:=TLinkedList.Create;
_exports:=TLinkedList.Create;
externals:=TLinkedList.Create;
end;
destructor tmodule.Destroy;
{$ifdef MEMDEBUG}
var
d : tmemdebug;
{$endif}
begin
if assigned(map) then
dispose(map);
if assigned(imports) then
imports.free;
imports:=nil;
if assigned(_exports) then
_exports.free;
_exports:=nil;
if assigned(externals) then
externals.free;
externals:=nil;
if assigned(scanner) then
tscannerfile(scanner).invalid:=true;
used_units.free;
dependent_units.free;
resourcefiles.Free;
linkunitofiles.Free;
linkunitstaticlibs.Free;
linkunitsharedlibs.Free;
linkotherofiles.Free;
linkotherstaticlibs.Free;
linkothersharedlibs.Free;
stringdispose(objfilename);
stringdispose(newfilename);
stringdispose(ppufilename);
stringdispose(staticlibfilename);
stringdispose(sharedlibfilename);
stringdispose(exefilename);
stringdispose(outputpath);
stringdispose(path);
stringdispose(modulename);
stringdispose(realmodulename);
stringdispose(mainsource);
stringdispose(asmprefix);
localunitsearchpath.Free;
localobjectsearchpath.free;
localincludesearchpath.free;
locallibrarysearchpath.free;
{$ifdef MEMDEBUG}
d:=tmemdebug.create('symtable');
{$endif}
if assigned(globalsymtable) then
globalsymtable.free;
globalsymtable:=nil;
if assigned(localsymtable) then
localsymtable.free;
localsymtable:=nil;
{$ifdef MEMDEBUG}
d.free;
{$endif}
inherited Destroy;
end;
procedure tmodule.reset;
var
pm : tdependent_unit;
begin
if assigned(scanner) then
tscannerfile(scanner).invalid:=true;
if assigned(globalsymtable) then
begin
globalsymtable.free;
globalsymtable:=nil;
end;
if assigned(localsymtable) then
begin
localsymtable.free;
localsymtable:=nil;
end;
if assigned(map) then
begin
dispose(map);
map:=nil;
end;
sourcefiles.free;
sourcefiles:=tinputfilemanager.create;
imports.free;
imports:=tlinkedlist.create;
_exports.free;
_exports:=tlinkedlist.create;
externals.free;
externals:=tlinkedlist.create;
used_units.free;
used_units:=TLinkedList.Create;
{ all units that depend on this one must be recompiled ! }
pm:=tdependent_unit(dependent_units.first);
while assigned(pm) do
begin
if pm.u.in_second_compile then
Comment(v_debug,'No reload already in second compile: '+pm.u.modulename^)
else
begin
pm.u.do_reload:=true;
Comment(v_debug,'Reloading '+pm.u.modulename^+' needed because '+modulename^+' is reloaded');
end;
pm:=tdependent_unit(pm.next);
end;
dependent_units.free;
dependent_units:=TLinkedList.Create;
resourcefiles.Free;
resourcefiles:=TStringList.Create;
linkunitofiles.Free;
linkunitofiles:=TLinkContainer.Create;
linkunitstaticlibs.Free;
linkunitstaticlibs:=TLinkContainer.Create;
linkunitsharedlibs.Free;
linkunitsharedlibs:=TLinkContainer.Create;
linkotherofiles.Free;
linkotherofiles:=TLinkContainer.Create;
linkotherstaticlibs.Free;
linkotherstaticlibs:=TLinkContainer.Create;
linkothersharedlibs.Free;
linkothersharedlibs:=TLinkContainer.Create;
uses_imports:=false;
do_compile:=false;
{ sources_avail:=true;
should not be changed PM }
compiled:=false;
in_implementation:=false;
in_global:=true;
crc:=0;
interface_crc:=0;
flags:=0;
{loaded_from:=nil;
should not be changed PFV }
unitcount:=1;
recompile_reason:=rr_unknown;
end;
procedure tmodule.numberunits;
var
counter : longint;
hp : tused_unit;
hp1 : tmodule;
begin
{ Reset all numbers to -1 }
hp1:=tmodule(loaded_units.first);
while assigned(hp1) do
begin
if assigned(hp1.globalsymtable) then
hp1.globalsymtable.unitid:=$ffff;
hp1:=tmodule(hp1.next);
end;
{ Our own symtable gets unitid 0, for a program there is
no globalsymtable }
if assigned(globalsymtable) then
globalsymtable.unitid:=0;
{ number units }
counter:=1;
hp:=tused_unit(used_units.first);
while assigned(hp) do
begin
tsymtable(hp.u.globalsymtable).unitid:=counter;
inc(counter);
hp:=tused_unit(hp.next);
end;
end;
end.
{
$Log$
Revision 1.23 2002-05-16 19:46:36 carl
+ defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
+ try to fix temp allocation (still in ifdef)
+ generic constructor calls
+ start of tassembler / tmodulebase class cleanup
Revision 1.22 2002/05/14 19:34:41 peter
* removed old logs and updated copyright year
Revision 1.21 2002/04/04 19:05:55 peter
* removed unused units
* use tlocation.size in cg.a_*loc*() routines
Revision 1.20 2002/03/28 20:46:59 carl
- remove go32v1 support
}