{ $Id$ Copyright (c) 1998-2000 by Florian Klaempfl This unit implements an extended file management and the first loading and searching of the modules (ppufiles) 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 files; {$ifdef TP} {$V+} {$endif} {$ifdef TP} {$define SHORTASMPREFIX} {$endif} {$ifdef go32v1} {$define SHORTASMPREFIX} {$endif} {$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 globtype,cobjects,globals,ppu {$IFDEF NEWST},objects{$ENDIF}; const {$ifdef FPC} maxunits = 1024; InputFileBufSize=32*1024; linebufincrease=512; {$else} maxunits = 128; InputFileBufSize=1024; linebufincrease=64; {$endif} type trecompile_reason = (rr_unknown,rr_noppu,rr_sourcenewer, rr_build,rr_libolder,rr_objolder,rr_asmolder,rr_crcchanged); {$ifdef FPC} tlongintarr = array[0..1000000] of longint; {$else} tlongintarr = array[0..16000] of longint; {$endif} plongintarr = ^tlongintarr; pinputfile = ^tinputfile; tinputfile = object path,name : pstring; { path and filename } next : pinputfile; { next file for reading } f : file; { current file handle } is_macro, endoffile, { still bytes left to read } closed : boolean; { is the file closed } buf : pchar; { buffer } bufstart, { buffer start position in the file } bufsize, { amount of bytes in the buffer } maxbufsize : longint; { size in memory for the buffer } saveinputpointer : pchar; { save fields for scanner variables } savelastlinepos, saveline_no : longint; linebuf : plongintarr; { line buffer to retrieve lines } maxlinebuf : longint; ref_count : longint; { to handle the browser refs } ref_index : longint; ref_next : pinputfile; constructor init(const fn:string); destructor done; procedure setpos(l:longint); procedure seekbuf(fpos:longint); procedure readbuf; function open:boolean; procedure close; procedure tempclose; function tempopen:boolean; procedure setmacro(p:pchar;len:longint); procedure setline(line,linepos:longint); function getlinestr(l:longint):string; end; pfilemanager = ^tfilemanager; tfilemanager = object files : pinputfile; last_ref_index : longint; cacheindex : longint; cacheinputfile : pinputfile; constructor init; destructor done; procedure register_file(f : pinputfile); procedure inverse_register_indexes; function get_file(l:longint) : pinputfile; function get_file_name(l :longint):string; function get_file_path(l :longint):string; end; {$IFDEF NEWST} Plinkitem=^Tlinkitem; Tlinkitem=object(Tobject) data : pstring; needlink : longint; constructor init(const s:string;m:longint); destructor done;virtual; end; {$ELSE} plinkcontaineritem=^tlinkcontaineritem; tlinkcontaineritem=object(tcontaineritem) data : pstring; needlink : longint; constructor init(const s:string;m:longint); destructor done;virtual; end; plinkcontainer=^tlinkcontainer; tlinkcontainer=object(tcontainer) constructor Init; procedure insert(const s : string;m:longint); function get(var m:longint) : string; function getusemask(mask:longint) : string; function find(const s:string):boolean; end; {$ENDIF NEWST} {$ifndef NEWMAP} tunitmap = array[0..maxunits-1] of pointer; punitmap = ^tunitmap; pmodule = ^tmodule; {$else NEWMAP} pmodule = ^tmodule; tunitmap = array[0..maxunits-1] of pmodule; punitmap = ^tunitmap; {$endif NEWMAP} tmodule = object(tlinkedlist_item) ppufile : pppufile; { the PPU file } crc, interface_crc, flags : longint; { the PPU flags } compiled, { unit is already compiled } do_reload, { force reloading of the unit } do_assemble, { only assemble the object, don't recompile } 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_compile, { is it being compiled ?? } 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 } islibrary : boolean; { if it is a library (win32 dll) } map : punitmap; { mapping of all used units } unitcount : word; { local unit counter } unit_index : word; { global counter for browser } globalsymtable, { pointer to the local/static symtable of this unit } localsymtable : pointer; { pointer to the psymtable of this unit } scanner : pointer; { scanner object used } loaded_from : pmodule; uses_imports : boolean; { Set if the module imports from DLL's.} imports : plinkedlist; _exports : plinkedlist; sourcefiles : pfilemanager; resourcefiles : tstringcontainer; {$IFDEF NEWST} linkunitofiles, linkunitstaticlibs, linkunitsharedlibs, linkotherofiles, { objects,libs loaded from the source } linkothersharedlibs, { using $L or $LINKLIB or import lib (for linux) } linkotherstaticlibs : Tcollection; {$ELSE} linkunitofiles, linkunitstaticlibs, linkunitsharedlibs, linkotherofiles, { objects,libs loaded from the source } linkothersharedlibs, { using $L or $LINKLIB or import lib (for linux) } linkotherstaticlibs : tlinkcontainer; {$ENDIF NEWST} used_units : tlinkedlist; dependent_units : tlinkedlist; localunitsearchpath, { local searchpaths } localobjectsearchpath, localincludesearchpath, locallibrarysearchpath : TSearchPathList; path, { path where the module is find/created } outputpath, { path where the .s / .o / exe are created } modulename, { name of the module in uppercase } objfilename, { fullname of the objectfile } asmfilename, { fullname of the assemblerfile } ppufilename, { fullname of the ppufile } staticlibfilename, { fullname of the static libraryfile } sharedlibfilename, { fullname of the shared libraryfile } exefilename, { fullname of the exefile } asmprefix, { prefix for the smartlink asmfiles } mainsource : pstring; { name of the main sourcefile } {$ifdef Test_Double_checksum} crc_array : pointer; crc_size : longint; crc_array2 : pointer; crc_size2 : longint; {$endif def Test_Double_checksum} constructor init(const s:string;_is_unit:boolean); destructor done;virtual; procedure reset; procedure setfilename(const fn:string;allowoutput:boolean); function openppu:boolean; function search_unit(const n : string;onlysource:boolean):boolean; end; pused_unit = ^tused_unit; tused_unit = object(tlinkedlist_item) unitid : word; name : pstring; checksum, interface_checksum : longint; loaded : boolean; in_uses, in_interface, is_stab_written : boolean; u : pmodule; constructor init(_u : pmodule;intface:boolean); constructor init_to_load(const n:string;c,intfc:longint;intface:boolean); destructor done;virtual; end; pdependent_unit = ^tdependent_unit; tdependent_unit = object(tlinkedlist_item) u : pmodule; constructor init(_u : pmodule); end; var main_module : pmodule; { Main module of the program } current_module : pmodule; { Current module which is compiled or loaded } compiled_module : pmodule; { Current module which is compiled } current_ppu : pppufile; { Current ppufile which is read } global_unit_count : word; usedunits : tlinkedlist; { Used units for this program } loaded_units : tlinkedlist; { All loaded units } SmartLinkOFiles : TStringContainer; { List of .o files which are generated, used to delete them after linking } function get_source_file(moduleindex,fileindex : word) : pinputfile; implementation uses {$ifdef Delphi} dmisc, {$else Delphi} dos, {$endif Delphi} verbose,systems, symtable,scanner{$IFDEF NEWST},symtablt{$ENDIF}; {**************************************************************************** TINPUTFILE ****************************************************************************} constructor tinputfile.init(const fn:string); var p:dirstr; n:namestr; e:extstr; begin FSplit(fn,p,n,e); name:=stringdup(n+e); path:=stringdup(p); next:=nil; { file info } is_macro:=false; endoffile:=false; closed:=true; buf:=nil; bufstart:=0; bufsize:=0; maxbufsize:=InputFileBufSize; { save fields } saveinputpointer:=nil; saveline_no:=0; savelastlinepos:=0; { indexing refs } ref_next:=nil; ref_count:=0; ref_index:=0; { line buffer } linebuf:=nil; maxlinebuf:=0; end; destructor tinputfile.done; begin if not closed then close; stringdispose(path); stringdispose(name); { free memory } if assigned(linebuf) then freemem(linebuf,maxlinebuf shl 2); end; procedure tinputfile.setpos(l:longint); begin bufstart:=l; end; procedure tinputfile.seekbuf(fpos:longint); begin if closed then exit; seek(f,fpos); bufstart:=fpos; bufsize:=0; end; procedure tinputfile.readbuf; {$ifdef TP} var w : word; {$endif} begin if is_macro then endoffile:=true; if closed then exit; inc(bufstart,bufsize); {$ifdef VER70} blockread(f,buf^,maxbufsize-1,w); bufsize:=w; {$else} blockread(f,buf^,maxbufsize-1,bufsize); {$endif} buf[bufsize]:=#0; endoffile:=eof(f); end; function tinputfile.open:boolean; var ofm : byte; begin open:=false; if not closed then Close; ofm:=filemode; filemode:=0; Assign(f,path^+name^); {$I-} reset(f,1); {$I+} filemode:=ofm; if ioresult<>0 then exit; { file } endoffile:=false; closed:=false; Getmem(buf,MaxBufsize); bufstart:=0; bufsize:=0; open:=true; end; procedure tinputfile.close; begin if is_macro then begin if assigned(buf) then Freemem(buf,maxbufsize); buf:=nil; {is_macro:=false; still needed for dispose in scanner PM } closed:=true; exit; end; if not closed then begin {$I-} system.close(f); {$I+} if ioresult<>0 then; closed:=true; end; if assigned(buf) then begin Freemem(buf,maxbufsize); buf:=nil; end; bufstart:=0; end; procedure tinputfile.tempclose; begin if is_macro then exit; if not closed then begin {$I-} system.close(f); {$I+} if ioresult<>0 then; Freemem(buf,maxbufsize); buf:=nil; closed:=true; end; end; function tinputfile.tempopen:boolean; var ofm : byte; begin tempopen:=false; if is_macro then begin { seek buffer postion to bufstart } if bufstart>0 then begin move(buf[bufstart],buf[0],bufsize-bufstart+1); bufstart:=0; end; tempopen:=true; exit; end; if not closed then exit; ofm:=filemode; filemode:=0; Assign(f,path^+name^); {$I-} reset(f,1); {$I+} filemode:=ofm; if ioresult<>0 then exit; closed:=false; { get new mem } Getmem(buf,maxbufsize); { restore state } seek(f,BufStart); bufsize:=0; readbuf; tempopen:=true; end; procedure tinputfile.setmacro(p:pchar;len:longint); begin { create new buffer } getmem(buf,len+1); move(p^,buf^,len); buf[len]:=#0; { reset } bufstart:=0; bufsize:=len; maxbufsize:=len+1; is_macro:=true; endoffile:=true; closed:=true; end; procedure tinputfile.setline(line,linepos:longint); var oldlinebuf : plongintarr; begin if line<1 then exit; while (line>=maxlinebuf) do begin oldlinebuf:=linebuf; { create new linebuf and move old info } getmem(linebuf,(maxlinebuf+linebufincrease) shl 2); if assigned(oldlinebuf) then begin move(oldlinebuf^,linebuf^,maxlinebuf shl 2); freemem(oldlinebuf,maxlinebuf shl 2); end; fillchar(linebuf^[maxlinebuf],linebufincrease shl 2,0); inc(maxlinebuf,linebufincrease); end; linebuf^[line]:=linepos; end; function tinputfile.getlinestr(l:longint):string; var c : char; i, fpos : longint; p : pchar; begin getlinestr:=''; if lbufstart+bufsize) then begin seekbuf(fpos); readbuf; end; { the begin is in the buf now simply read until #13,#10 } i:=0; p:=@buf[fpos-bufstart]; repeat c:=p^; if c=#0 then begin if endoffile then break; readbuf; p:=buf; c:=p^; end; if c in [#10,#13] then break; inc(i); getlinestr[i]:=c; inc(longint(p)); until (i=255); {$ifndef TP} {$ifopt H+} setlength(getlinestr,i); {$else} getlinestr[0]:=chr(i); {$endif} {$else} getlinestr[0]:=chr(i); {$endif} end; end; {**************************************************************************** TFILEMANAGER ****************************************************************************} constructor tfilemanager.init; begin files:=nil; last_ref_index:=0; cacheindex:=0; cacheinputfile:=nil; end; destructor tfilemanager.done; var hp : pinputfile; begin hp:=files; while assigned(hp) do begin files:=files^.ref_next; dispose(hp,done); hp:=files; end; last_ref_index:=0; end; procedure tfilemanager.register_file(f : pinputfile); begin { don't register macro's } if f^.is_macro then exit; inc(last_ref_index); f^.ref_next:=files; f^.ref_index:=last_ref_index; files:=f; { update cache } cacheindex:=last_ref_index; cacheinputfile:=f; {$ifdef FPC} {$ifdef heaptrc} writeln(stderr,f^.name^,' index ',current_module^.unit_index*100000+f^.ref_index); {$endif heaptrc} {$endif FPC} end; { this procedure is necessary after loading the sources files from a PPU file PM } procedure tfilemanager.inverse_register_indexes; var f : pinputfile; begin f:=files; while assigned(f) do begin f^.ref_index:=last_ref_index-f^.ref_index+1; f:=f^.ref_next; end; { reset cache } cacheindex:=0; cacheinputfile:=nil; end; function tfilemanager.get_file(l :longint) : pinputfile; var ff : pinputfile; begin { check cache } if (l=cacheindex) and assigned(cacheinputfile) then begin get_file:=cacheinputfile; exit; end; ff:=files; while assigned(ff) and (ff^.ref_index<>l) do ff:=ff^.ref_next; get_file:=ff; end; function tfilemanager.get_file_name(l :longint):string; var hp : pinputfile; begin hp:=get_file(l); if assigned(hp) then get_file_name:=hp^.name^ else get_file_name:=''; end; function tfilemanager.get_file_path(l :longint):string; var hp : pinputfile; begin hp:=get_file(l); if assigned(hp) then get_file_path:=hp^.path^ else get_file_path:=''; end; function get_source_file(moduleindex,fileindex : word) : pinputfile; var hp : pmodule; f : pinputfile; begin hp:=pmodule(loaded_units.first); while assigned(hp) and (hp^.unit_index<>moduleindex) do hp:=pmodule(hp^.next); get_source_file:=nil; if not assigned(hp) then exit; f:=pinputfile(hp^.sourcefiles^.files); while assigned(f) do begin if f^.ref_index=fileindex then begin get_source_file:=f; exit; end; f:=pinputfile(f^.ref_next); end; end; {**************************************************************************** TLinkContainerItem ****************************************************************************} {$IFDEF NEWST} constructor TLinkItem.Init(const s:string;m:longint); begin inherited Init; data:=stringdup(s); needlink:=m; end; destructor TLinkItem.Done; begin stringdispose(data); end; {$ELSE} constructor TLinkContainerItem.Init(const s:string;m:longint); begin inherited Init; data:=stringdup(s); needlink:=m; end; destructor TLinkContainerItem.Done; begin stringdispose(data); end; {$ENDIF NEWST} {**************************************************************************** TLinkContainer ****************************************************************************} {$IFNDEF NEWST} constructor TLinkContainer.Init; begin inherited init; end; procedure TLinkContainer.insert(const s : string;m:longint); var newnode : plinkcontaineritem; begin {if find(s) then exit; } new(newnode,init(s,m)); inherited insert(newnode); end; function TLinkContainer.get(var m:longint) : string; var p : plinkcontaineritem; begin p:=plinkcontaineritem(inherited get); if p=nil then begin get:=''; m:=0; exit; end; get:=p^.data^; m:=p^.needlink; dispose(p,done); end; function TLinkContainer.getusemask(mask:longint) : string; var p : plinkcontaineritem; found : boolean; begin found:=false; repeat p:=plinkcontaineritem(inherited get); if p=nil then begin getusemask:=''; exit; end; getusemask:=p^.data^; found:=(p^.needlink and mask)<>0; dispose(p,done); until found; end; function TLinkContainer.find(const s:string):boolean; var newnode : plinkcontaineritem; begin find:=false; newnode:=plinkcontaineritem(root); while assigned(newnode) do begin if newnode^.data^=s then begin find:=true; exit; end; newnode:=plinkcontaineritem(newnode^.next); end; end; {$ENDIF NEWST} {**************************************************************************** TMODULE ****************************************************************************} procedure tmodule.setfilename(const fn:string;allowoutput:boolean); var p : dirstr; n : NameStr; e : ExtStr; begin stringdispose(objfilename); stringdispose(asmfilename); stringdispose(ppufilename); stringdispose(staticlibfilename); stringdispose(sharedlibfilename); stringdispose(exefilename); stringdispose(outputpath); stringdispose(path); { Create names } fsplit(fn,p,n,e); n:=FixFileName(n); { set path } path:=stringdup(FixPath(p,false)); { obj,asm,ppu names } p:=path^; if AllowOutput then begin if (OutputUnitDir<>'') then p:=OutputUnitDir else if (OutputExeDir<>'') then p:=OutputExeDir; end; outputpath:=stringdup(p); objfilename:=stringdup(p+n+target_info.objext); asmfilename:=stringdup(p+n+target_info.asmext); ppufilename:=stringdup(p+n+target_info.unitext); { lib and exe could be loaded with a file specified with -o } if AllowOutput and (OutputFile<>'') then n:=OutputFile; staticlibfilename:=stringdup(p+target_os.libprefix+n+target_os.staticlibext); if target_info.target=target_i386_WIN32 then sharedlibfilename:=stringdup(p+n+target_os.sharedlibext) else sharedlibfilename:=stringdup(p+target_os.libprefix+n+target_os.sharedlibext); { output dir of exe can be specified separatly } if AllowOutput and (OutputExeDir<>'') then p:=OutputExeDir else p:=path^; exefilename:=stringdup(p+n+target_info.exeext); end; function tmodule.openppu:boolean; var objfiletime, ppufiletime, asmfiletime : longint; begin openppu:=false; Message1(unit_t_ppu_loading,ppufilename^); { Get ppufile time (also check if the file exists) } ppufiletime:=getnamedfiletime(ppufilename^); if ppufiletime=-1 then exit; { Open the ppufile } Message1(unit_u_ppu_name,ppufilename^); ppufile:=new(pppufile,init(ppufilename^)); ppufile^.change_endian:=source_os.endian<>target_os.endian; if not ppufile^.open then begin dispose(ppufile,done); Message(unit_u_ppu_file_too_short); exit; end; { check for a valid PPU file } if not ppufile^.CheckPPUId then begin dispose(ppufile,done); Message(unit_u_ppu_invalid_header); exit; end; { check for allowed PPU versions } if not (ppufile^.GetPPUVersion = CurrentPPUVersion) then begin dispose(ppufile,done); Message1(unit_u_ppu_invalid_version,tostr(ppufile^.GetPPUVersion)); exit; end; { check the target processor } if ttargetcpu(ppufile^.header.cpu)<>target_cpu then begin dispose(ppufile,done); Message(unit_u_ppu_invalid_processor); exit; end; { check target } if ttarget(ppufile^.header.target)<>target_info.target then begin dispose(ppufile,done); Message(unit_u_ppu_invalid_target); exit; end; { Load values to be access easier } flags:=ppufile^.header.flags; crc:=ppufile^.header.checksum; interface_crc:=ppufile^.header.interface_checksum; { Show Debug info } Message1(unit_u_ppu_time,filetimestring(ppufiletime)); Message1(unit_u_ppu_flags,tostr(flags)); Message1(unit_u_ppu_crc,tostr(ppufile^.header.checksum)); Message1(unit_u_ppu_crc,tostr(ppufile^.header.interface_checksum)+' (intfc)'); { check the object and assembler file to see if we need only to assemble, only if it's not in a library } do_compile:=false; if (flags and uf_in_library)=0 then begin if (flags and uf_smart_linked)<>0 then begin objfiletime:=getnamedfiletime(staticlibfilename^); Message2(unit_u_check_time,staticlibfilename^,filetimestring(objfiletime)); if (ppufiletime<0) or (objfiletime<0) or (ppufiletime>objfiletime) then begin recompile_reason:=rr_libolder; Message(unit_u_recompile_staticlib_is_older); do_compile:=true; exit; end; end; if (flags and uf_static_linked)<>0 then begin { the objectfile should be newer than the ppu file } objfiletime:=getnamedfiletime(objfilename^); Message2(unit_u_check_time,objfilename^,filetimestring(objfiletime)); if (ppufiletime<0) or (objfiletime<0) or (ppufiletime>objfiletime) then begin { check if assembler file is older than ppu file } asmfileTime:=GetNamedFileTime(asmfilename^); Message2(unit_u_check_time,asmfilename^,filetimestring(asmfiletime)); if (asmfiletime<0) or (ppufiletime>asmfiletime) then begin Message(unit_u_recompile_obj_and_asm_older); recompile_reason:=rr_objolder; do_compile:=true; exit; end else begin Message(unit_u_recompile_obj_older_than_asm); if not(cs_asm_extern in aktglobalswitches) then begin do_compile:=true; recompile_reason:=rr_asmolder; exit; end; end; end; end; end; openppu:=true; end; function tmodule.search_unit(const n : string;onlysource:boolean):boolean; var singlepathstring, filename : string; Function UnitExists(const ext:string):boolean; begin Message1(unit_t_unitsearch,Singlepathstring+filename+ext); UnitExists:=FileExists(Singlepathstring+FileName+ext); end; Function PPUSearchPath(const s:string):boolean; var found : boolean; begin Found:=false; singlepathstring:=FixPath(s,false); { Check for PPU file } Found:=UnitExists(target_info.unitext); if Found then Begin SetFileName(SinglePathString+FileName,false); Found:=OpenPPU; End; PPUSearchPath:=Found; end; Function SourceSearchPath(const s:string):boolean; var found : boolean; ext : string[8]; begin Found:=false; singlepathstring:=FixPath(s,false); { Check for Sources } ppufile:=nil; do_compile:=true; recompile_reason:=rr_noppu; {Check for .pp file} Found:=UnitExists(target_os.sourceext); if Found then Ext:=target_os.sourceext else begin {Check for .pas} Found:=UnitExists(target_os.pasext); if Found then Ext:=target_os.pasext; end; stringdispose(mainsource); if Found then begin sources_avail:=true; {Load Filenames when found} mainsource:=StringDup(SinglePathString+FileName+Ext); SetFileName(SinglePathString+FileName,false); end else sources_avail:=false; SourceSearchPath:=Found; end; Function SearchPath(const s:string):boolean; var found : boolean; begin { First check for a ppu, then for the source } found:=false; if not onlysource then found:=PPUSearchPath(s); if not found then found:=SourceSearchPath(s); SearchPath:=found; end; Function SearchPathList(list:TSearchPathList):boolean; var hp : PStringQueueItem; found : boolean; begin found:=false; hp:=list.First; while assigned(hp) do begin found:=SearchPath(hp^.data^); if found then break; hp:=hp^.next; end; SearchPathList:=found; end; var fnd : boolean; begin filename:=FixFileName(n); { try to find unit 1. look for ppu in cwd 2. look for ppu in outputpath if set, this is tp7 compatible (PFV) 3. look for source in cwd 4. local unit pathlist 5. global unit pathlist } fnd:=false; if not onlysource then begin fnd:=PPUSearchPath('.'); if (not fnd) and (current_module^.outputpath^<>'') then fnd:=PPUSearchPath(current_module^.outputpath^); end; if (not fnd) then fnd:=SourceSearchPath('.'); if (not fnd) then fnd:=SearchPathList(current_module^.LocalUnitSearchPath); if (not fnd) then fnd:=SearchPathList(UnitSearchPath); { try to find a file with the first 8 chars of the modulename, like dos } if (not fnd) and (length(filename)>8) then begin filename:=copy(filename,1,8); fnd:=SearchPath('.'); if (not fnd) then fnd:=SearchPathList(current_module^.LocalUnitSearchPath); if not fnd then fnd:=SearchPathList(UnitSearchPath); end; search_unit:=fnd; end; procedure tmodule.reset; var pm : pdependent_unit; begin if assigned(scanner) then pscannerfile(scanner)^.invalid:=true; if assigned(globalsymtable) then begin dispose(punitsymtable(globalsymtable),done); globalsymtable:=nil; end; if assigned(localsymtable) then begin dispose(punitsymtable(localsymtable),done); localsymtable:=nil; end; if assigned(map) then begin dispose(map); map:=nil; end; if assigned(ppufile) then begin dispose(ppufile,done); ppufile:=nil; end; sourcefiles^.done; sourcefiles^.init; imports^.done; imports^.init; _exports^.done; _exports^.init; used_units.done; used_units.init; { all units that depend on this one must be recompiled ! } pm:=pdependent_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:=pdependent_unit(pm^.next); end; dependent_units.done; dependent_units.init; resourcefiles.done; resourcefiles.init; linkunitofiles.done; linkunitofiles.init{$IFDEF NEWST}(8,4){$ENDIF}; linkunitstaticlibs.done; linkunitstaticlibs.init{$IFDEF NEWST}(8,4){$ENDIF}; linkunitsharedlibs.done; linkunitsharedlibs.init{$IFDEF NEWST}(8,4){$ENDIF}; linkotherofiles.done; linkotherofiles.init{$IFDEF NEWST}(8,4){$ENDIF}; linkotherstaticlibs.done; linkotherstaticlibs.init{$IFDEF NEWST}(8,4){$ENDIF}; linkothersharedlibs.done; linkothersharedlibs.init{$IFDEF NEWST}(8,4){$ENDIF}; uses_imports:=false; do_assemble:=false; do_compile:=false; { sources_avail:=true; should not be changed PM } compiled:=false; in_implementation:=false; in_global:=true; {loaded_from:=nil; should not be changed PFV } flags:=0; crc:=0; interface_crc:=0; unitcount:=1; recompile_reason:=rr_unknown; end; constructor tmodule.init(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 {$ifdef UNITALIASES} modulename:=stringdup(GetUnitAlias(Upper(n))) {$else} modulename:=stringdup(Upper(n)) {$endif} else modulename:=stringdup('PROGRAM'); mainsource:=stringdup(s); ppufilename:=nil; objfilename:=nil; asmfilename:=nil; staticlibfilename:=nil; sharedlibfilename:=nil; exefilename:=nil; { Dos has the famous 8.3 limit :( } {$ifdef SHORTASMPREFIX} asmprefix:=stringdup(FixFileName('as')); {$else} asmprefix:=stringdup(FixFileName(n)); {$endif} outputpath:=nil; path:=nil; setfilename(p+n,true); localunitsearchpath.init; localobjectsearchpath.init; localincludesearchpath.init; locallibrarysearchpath.init; used_units.init; dependent_units.init; new(sourcefiles,init); resourcefiles.init; linkunitofiles.init{$IFDEF NEWST}(8,4){$ENDIF}; linkunitstaticlibs.init{$IFDEF NEWST}(8,4){$ENDIF}; linkunitsharedlibs.init{$IFDEF NEWST}(8,4){$ENDIF}; linkotherofiles.init{$IFDEF NEWST}(8,4){$ENDIF}; linkotherstaticlibs.init{$IFDEF NEWST}(8,4){$ENDIF}; linkothersharedlibs.init{$IFDEF NEWST}(8,4){$ENDIF}; ppufile:=nil; scanner:=nil; map:=nil; globalsymtable:=nil; localsymtable:=nil; loaded_from:=nil; flags:=0; crc:=0; interface_crc:=0; do_reload:=false; unitcount:=1; inc(global_unit_count); unit_index:=global_unit_count; do_assemble:=false; do_compile:=false; sources_avail:=true; sources_checked:=false; compiled:=false; recompile_reason:=rr_unknown; in_second_load:=false; in_compile:=false; in_second_compile:=false; in_implementation:=false; in_global:=true; is_unit:=_is_unit; islibrary:=false; uses_imports:=false; imports:=new(plinkedlist,init); _exports:=new(plinkedlist,init); { search the PPU file if it is an unit } if is_unit then begin search_unit(modulename^,false); { it the sources_available is changed then we know that the sources aren't available } if not sources_avail then sources_checked:=true; end; end; destructor tmodule.done; {$ifdef MEMDEBUG} var d : tmemdebug; {$endif} begin if assigned(map) then dispose(map); if assigned(ppufile) then dispose(ppufile,done); ppufile:=nil; if assigned(imports) then dispose(imports,done); imports:=nil; if assigned(_exports) then dispose(_exports,done); _exports:=nil; if assigned(scanner) then pscannerfile(scanner)^.invalid:=true; if assigned(sourcefiles) then dispose(sourcefiles,done); sourcefiles:=nil; used_units.done; dependent_units.done; resourcefiles.done; linkunitofiles.done; linkunitstaticlibs.done; linkunitsharedlibs.done; linkotherofiles.done; linkotherstaticlibs.done; linkothersharedlibs.done; stringdispose(objfilename); stringdispose(asmfilename); stringdispose(ppufilename); stringdispose(staticlibfilename); stringdispose(sharedlibfilename); stringdispose(exefilename); stringdispose(outputpath); stringdispose(path); stringdispose(modulename); stringdispose(mainsource); stringdispose(asmprefix); localunitsearchpath.done; localobjectsearchpath.done; localincludesearchpath.done; locallibrarysearchpath.done; {$ifdef MEMDEBUG} d.init('symtable'); {$endif} if assigned(globalsymtable) then dispose(punitsymtable(globalsymtable),done); globalsymtable:=nil; if assigned(localsymtable) then dispose(punitsymtable(localsymtable),done); localsymtable:=nil; {$ifdef MEMDEBUG} d.done; {$endif} inherited done; end; {**************************************************************************** TUSED_UNIT ****************************************************************************} constructor tused_unit.init(_u : pmodule;intface:boolean); begin u:=_u; in_interface:=intface; in_uses:=false; is_stab_written:=false; loaded:=true; name:=stringdup(_u^.modulename^); checksum:=_u^.crc; interface_checksum:=_u^.interface_crc; unitid:=0; end; constructor tused_unit.init_to_load(const n:string;c,intfc:longint;intface:boolean); begin u:=nil; in_interface:=intface; in_uses:=false; is_stab_written:=false; loaded:=false; name:=stringdup(n); checksum:=c; interface_checksum:=intfc; unitid:=0; end; destructor tused_unit.done; begin stringdispose(name); inherited done; end; {**************************************************************************** TDENPENDENT_UNIT ****************************************************************************} constructor tdependent_unit.init(_u : pmodule); begin u:=_u; end; end. { $Log$ Revision 1.118 2000-06-15 18:10:11 peter * first look for ppu in cwd and outputpath and after that for source in cwd * fixpath() for not linux makes path now lowercase so comparing paths with different cases (sometimes a drive letter could be uppercased) gives the expected results * sources_checked flag if there was already a full search for sources which aren't found, so another scan isn't done when checking for the sources only when recompile is needed Revision 1.117 2000/02/28 17:23:56 daniel * Current work of symtable integration committed. The symtable can be activated by defining 'newst', but doesn't compile yet. Changes in type checking and oop are completed. What is left is to write a new symtablestack and adapt the parser to use it. Revision 1.116 2000/02/24 18:41:38 peter * removed warnings/notes Revision 1.115 2000/02/10 16:00:23 peter * dont' check for ppl files as they aren't used atm. Revision 1.114 2000/02/09 13:22:52 peter * log truncated Revision 1.113 2000/01/11 09:52:06 peter * fixed placing of .sl directories * use -b again for base-file selection * fixed group writing for linux with smartlinking Revision 1.112 2000/01/07 01:14:27 peter * updated copyright to 2000 Revision 1.111 1999/12/08 01:01:11 peter * fixed circular unit reference checking. loaded_from was reset after reseting a unit, so no loaded_from info was available anymore. Revision 1.110 1999/11/16 23:39:04 peter * use outputexedir for link.res location Revision 1.109 1999/11/12 11:03:50 peter * searchpaths changed to stringqueue object Revision 1.108 1999/11/06 14:34:20 peter * truncated log to 20 revs Revision 1.107 1999/11/04 23:13:25 peter * moved unit alias support into ifdef Revision 1.106 1999/11/04 10:54:02 peter + -Ua= unit alias support Revision 1.105 1999/10/28 13:14:00 pierre * allow doubles in TLinkContainer needed for double libraries Revision 1.104 1999/09/27 23:40:12 peter * fixed macro within macro endless-loop Revision 1.103 1999/09/16 08:00:50 pierre + compiled_module to avoid wrong file info when load PPU files Revision 1.102 1999/08/31 15:51:10 pierre * in_second_compile cleaned up, in_compile and in_second_load added Revision 1.101 1999/08/27 10:43:20 pierre + interface CRC check with ifdef Test_double_checksum added Revision 1.100 1999/08/24 13:14:01 peter * MEMDEBUG to see the sizes of asmlist,asmsymbols,symtables }