Initial revision
[AROS-Contrib.git] / development / compilers / freepascal / compiler / files.pas
blobe07b884abd6589d4e646cf4a8c43905f762bda6d
2 $Id$
3 Copyright (c) 1998-2000 by Florian Klaempfl
5 This unit implements an extended file management and the first loading
6 and searching of the modules (ppufiles)
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 ****************************************************************************
24 unit files;
26 {$ifdef TP}
27 {$V+}
28 {$endif}
30 {$ifdef TP}
31 {$define SHORTASMPREFIX}
32 {$endif}
33 {$ifdef go32v1}
34 {$define SHORTASMPREFIX}
35 {$endif}
36 {$ifdef go32v2}
37 {$define SHORTASMPREFIX}
38 {$endif}
39 {$ifdef OS2}
40 { Allthough OS/2 supports long filenames I play it safe and
41 use 8.3 filenames, because this allows the compiler to run
42 on a FAT partition. (DM) }
43 {$define SHORTASMPREFIX}
44 {$endif}
47 interface
49 uses
50 globtype,cobjects,globals,ppu
51 {$IFDEF NEWST},objects{$ENDIF};
53 const
54 {$ifdef FPC}
55 maxunits = 1024;
56 InputFileBufSize=32*1024;
57 linebufincrease=512;
58 {$else}
59 maxunits = 128;
60 InputFileBufSize=1024;
61 linebufincrease=64;
62 {$endif}
64 type
65 trecompile_reason = (rr_unknown,rr_noppu,rr_sourcenewer,
66 rr_build,rr_libolder,rr_objolder,rr_asmolder,rr_crcchanged);
67 {$ifdef FPC}
68 tlongintarr = array[0..1000000] of longint;
69 {$else}
70 tlongintarr = array[0..16000] of longint;
71 {$endif}
72 plongintarr = ^tlongintarr;
74 pinputfile = ^tinputfile;
75 tinputfile = object
76 path,name : pstring; { path and filename }
77 next : pinputfile; { next file for reading }
79 is_macro,
80 endoffile, { still bytes left to read }
81 closed : boolean; { is the file closed }
83 buf : pchar; { buffer }
84 bufstart, { buffer start position in the file }
85 bufsize, { amount of bytes in the buffer }
86 maxbufsize : longint; { size in memory for the buffer }
88 saveinputpointer : pchar; { save fields for scanner variables }
89 savelastlinepos,
90 saveline_no : longint;
92 linebuf : plongintarr; { line buffer to retrieve lines }
93 maxlinebuf : longint;
95 ref_count : longint; { to handle the browser refs }
96 ref_index : longint;
97 ref_next : pinputfile;
99 constructor init(const fn:string);
100 destructor done;
101 procedure setpos(l:longint);
102 procedure seekbuf(fpos:longint);
103 procedure readbuf;
104 function open:boolean;
105 procedure close;
106 procedure tempclose;
107 function tempopen:boolean;
108 procedure setmacro(p:pchar;len:longint);
109 procedure setline(line,linepos:longint);
110 function getlinestr(l:longint):string;
111 {$ifdef FPC}protected{$else}public{$endif}
112 function fileopen(const filename: string): boolean; virtual;
113 function fileseek(pos: longint): boolean; virtual;
114 function fileread(var databuf; maxsize: longint): longint; virtual;
115 function fileeof: boolean; virtual;
116 function fileclose: boolean; virtual;
117 end;
119 pdosinputfile = ^tdosinputfile;
120 tdosinputfile = object(tinputfile)
121 {$ifdef FPC}protected{$else}public{$endif}
122 function fileopen(const filename: string): boolean; virtual;
123 function fileseek(pos: longint): boolean; virtual;
124 function fileread(var databuf; maxsize: longint): longint; virtual;
125 function fileeof: boolean; virtual;
126 function fileclose: boolean; virtual;
127 private
128 f : file; { current file handle }
129 end;
131 pfilemanager = ^tfilemanager;
132 tfilemanager = object
133 files : pinputfile;
134 last_ref_index : longint;
135 cacheindex : longint;
136 cacheinputfile : pinputfile;
137 constructor init;
138 destructor done;
139 procedure register_file(f : pinputfile);
140 procedure inverse_register_indexes;
141 function get_file(l:longint) : pinputfile;
142 function get_file_name(l :longint):string;
143 function get_file_path(l :longint):string;
144 end;
146 {$IFDEF NEWST}
147 Plinkitem=^Tlinkitem;
148 Tlinkitem=object(Tobject)
149 data : pstring;
150 needlink : longint;
151 constructor init(const s:string;m:longint);
152 destructor done;virtual;
153 end;
154 {$ELSE}
155 plinkcontaineritem=^tlinkcontaineritem;
156 tlinkcontaineritem=object(tcontaineritem)
157 data : pstring;
158 needlink : longint;
159 constructor init(const s:string;m:longint);
160 destructor done;virtual;
161 end;
163 plinkcontainer=^tlinkcontainer;
164 tlinkcontainer=object(tcontainer)
165 constructor Init;
166 procedure insert(const s : string;m:longint);
167 function get(var m:longint) : string;
168 function getusemask(mask:longint) : string;
169 function find(const s:string):boolean;
170 end;
171 {$ENDIF NEWST}
173 {$ifndef NEWMAP}
174 tunitmap = array[0..maxunits-1] of pointer;
175 punitmap = ^tunitmap;
177 pmodule = ^tmodule;
179 {$else NEWMAP}
180 pmodule = ^tmodule;
182 tunitmap = array[0..maxunits-1] of pmodule;
183 punitmap = ^tunitmap;
184 {$endif NEWMAP}
186 tmodule = object(tlinkedlist_item)
187 ppufile : pppufile; { the PPU file }
188 crc,
189 interface_crc,
190 flags : longint; { the PPU flags }
192 compiled, { unit is already compiled }
193 do_reload, { force reloading of the unit }
194 do_assemble, { only assemble the object, don't recompile }
195 do_compile, { need to compile the sources }
196 sources_avail, { if all sources are reachable }
197 sources_checked, { if there is already done a check for the sources }
198 is_unit,
199 in_compile, { is it being compiled ?? }
200 in_second_compile, { is this unit being compiled for the 2nd time? }
201 in_second_load, { is this unit PPU loaded a 2nd time? }
202 in_implementation, { processing the implementation part? }
203 in_global : boolean; { allow global settings }
204 recompile_reason : trecompile_reason; { the reason why the unit should be recompiled }
206 islibrary : boolean; { if it is a library (win32 dll) }
207 map : punitmap; { mapping of all used units }
208 unitcount : word; { local unit counter }
209 unit_index : word; { global counter for browser }
210 globalsymtable, { pointer to the local/static symtable of this unit }
211 localsymtable : pointer; { pointer to the psymtable of this unit }
212 scanner : pointer; { scanner object used }
213 loaded_from : pmodule;
214 uses_imports : boolean; { Set if the module imports from DLL's.}
215 imports : plinkedlist;
216 _exports : plinkedlist;
218 sourcefiles : pfilemanager;
219 resourcefiles : tstringcontainer;
221 {$IFDEF NEWST}
222 linkunitofiles,
223 linkunitstaticlibs,
224 linkunitsharedlibs,
225 linkotherofiles, { objects,libs loaded from the source }
226 linkothersharedlibs, { using $L or $LINKLIB or import lib (for linux) }
227 linkotherstaticlibs : Tcollection;
228 {$ELSE}
229 linkunitofiles,
230 linkunitstaticlibs,
231 linkunitsharedlibs,
232 linkotherofiles, { objects,libs loaded from the source }
233 linkothersharedlibs, { using $L or $LINKLIB or import lib (for linux) }
234 linkotherstaticlibs : tlinkcontainer;
235 {$ENDIF NEWST}
237 used_units : tlinkedlist;
238 dependent_units : tlinkedlist;
240 localunitsearchpath, { local searchpaths }
241 localobjectsearchpath,
242 localincludesearchpath,
243 locallibrarysearchpath : TSearchPathList;
245 path, { path where the module is find/created }
246 outputpath, { path where the .s / .o / exe are created }
247 modulename, { name of the module in uppercase }
248 objfilename, { fullname of the objectfile }
249 asmfilename, { fullname of the assemblerfile }
250 ppufilename, { fullname of the ppufile }
251 staticlibfilename, { fullname of the static libraryfile }
252 sharedlibfilename, { fullname of the shared libraryfile }
253 exefilename, { fullname of the exefile }
254 asmprefix, { prefix for the smartlink asmfiles }
255 mainsource : pstring; { name of the main sourcefile }
256 {$ifdef Test_Double_checksum}
257 crc_array : pointer;
258 crc_size : longint;
259 crc_array2 : pointer;
260 crc_size2 : longint;
261 {$endif def Test_Double_checksum}
262 constructor init(const s:string;_is_unit:boolean);
263 destructor done;virtual;
264 procedure reset;
265 procedure setfilename(const fn:string;allowoutput:boolean);
266 function openppu:boolean;
267 function search_unit(const n : string;onlysource:boolean):boolean;
268 end;
270 pused_unit = ^tused_unit;
271 tused_unit = object(tlinkedlist_item)
272 unitid : word;
273 name : pstring;
274 checksum,
275 interface_checksum : longint;
276 loaded : boolean;
277 in_uses,
278 in_interface,
279 is_stab_written : boolean;
280 u : pmodule;
281 constructor init(_u : pmodule;intface:boolean);
282 constructor init_to_load(const n:string;c,intfc:longint;intface:boolean);
283 destructor done;virtual;
284 end;
286 pdependent_unit = ^tdependent_unit;
287 tdependent_unit = object(tlinkedlist_item)
288 u : pmodule;
289 constructor init(_u : pmodule);
290 end;
293 main_module : pmodule; { Main module of the program }
294 current_module : pmodule; { Current module which is compiled or loaded }
295 compiled_module : pmodule; { Current module which is compiled }
296 current_ppu : pppufile; { Current ppufile which is read }
297 global_unit_count : word;
298 usedunits : tlinkedlist; { Used units for this program }
299 loaded_units : tlinkedlist; { All loaded units }
300 SmartLinkOFiles : TStringContainer; { List of .o files which are generated,
301 used to delete them after linking }
303 function get_source_file(moduleindex,fileindex : word) : pinputfile;
306 implementation
308 uses
309 {$ifdef Delphi}
310 dmisc,
311 {$else Delphi}
312 dos,
313 {$endif Delphi}
314 verbose,systems,
315 symtable,scanner{$IFDEF NEWST},symtablt{$ENDIF};
317 {****************************************************************************
318 TINPUTFILE
319 ****************************************************************************}
321 constructor tinputfile.init(const fn:string);
323 p:dirstr;
324 n:namestr;
325 e:extstr;
326 begin
327 FSplit(fn,p,n,e);
328 name:=stringdup(n+e);
329 path:=stringdup(p);
330 next:=nil;
331 { file info }
332 is_macro:=false;
333 endoffile:=false;
334 closed:=true;
335 buf:=nil;
336 bufstart:=0;
337 bufsize:=0;
338 maxbufsize:=InputFileBufSize;
339 { save fields }
340 saveinputpointer:=nil;
341 saveline_no:=0;
342 savelastlinepos:=0;
343 { indexing refs }
344 ref_next:=nil;
345 ref_count:=0;
346 ref_index:=0;
347 { line buffer }
348 linebuf:=nil;
349 maxlinebuf:=0;
350 end;
353 destructor tinputfile.done;
354 begin
355 if not closed then
356 close;
357 stringdispose(path);
358 stringdispose(name);
359 { free memory }
360 if assigned(linebuf) then
361 freemem(linebuf,maxlinebuf shl 2);
362 end;
365 procedure tinputfile.setpos(l:longint);
366 begin
367 bufstart:=l;
368 end;
371 procedure tinputfile.seekbuf(fpos:longint);
372 begin
373 if closed then
374 exit;
375 fileseek(fpos);
376 bufstart:=fpos;
377 bufsize:=0;
378 end;
381 procedure tinputfile.readbuf;
382 begin
383 if is_macro then
384 endoffile:=true;
385 if closed then
386 exit;
387 inc(bufstart,bufsize);
388 bufsize:=fileread(buf^,maxbufsize-1);
389 buf[bufsize]:=#0;
390 endoffile:=fileeof;
391 end;
394 function tinputfile.open:boolean;
395 begin
396 open:=false;
397 if not closed then
398 Close;
399 if not fileopen(path^+name^) then
400 exit;
401 { file }
402 endoffile:=false;
403 closed:=false;
404 Getmem(buf,MaxBufsize);
405 bufstart:=0;
406 bufsize:=0;
407 open:=true;
408 end;
411 procedure tinputfile.close;
412 begin
413 if is_macro then
414 begin
415 if assigned(buf) then
416 Freemem(buf,maxbufsize);
417 buf:=nil;
418 {is_macro:=false;
419 still needed for dispose in scanner PM }
420 closed:=true;
421 exit;
422 end;
423 if not closed then
424 begin
425 if fileclose then;
426 closed:=true;
427 end;
428 if assigned(buf) then
429 begin
430 Freemem(buf,maxbufsize);
431 buf:=nil;
432 end;
433 bufstart:=0;
434 end;
437 procedure tinputfile.tempclose;
438 begin
439 if is_macro then
440 exit;
441 if not closed then
442 begin
443 if fileclose then;
444 Freemem(buf,maxbufsize);
445 buf:=nil;
446 closed:=true;
447 end;
448 end;
450 function tinputfile.tempopen:boolean;
451 begin
452 tempopen:=false;
453 if is_macro then
454 begin
455 { seek buffer postion to bufstart }
456 if bufstart>0 then
457 begin
458 move(buf[bufstart],buf[0],bufsize-bufstart+1);
459 bufstart:=0;
460 end;
461 tempopen:=true;
462 exit;
463 end;
464 if not closed then
465 exit;
466 if not fileopen(path^+name^) then
467 exit;
468 closed:=false;
469 { get new mem }
470 Getmem(buf,maxbufsize);
471 { restore state }
472 fileseek(BufStart);
473 bufsize:=0;
474 readbuf;
475 tempopen:=true;
476 end;
479 procedure tinputfile.setmacro(p:pchar;len:longint);
480 begin
481 { create new buffer }
482 getmem(buf,len+1);
483 move(p^,buf^,len);
484 buf[len]:=#0;
485 { reset }
486 bufstart:=0;
487 bufsize:=len;
488 maxbufsize:=len+1;
489 is_macro:=true;
490 endoffile:=true;
491 closed:=true;
492 end;
495 procedure tinputfile.setline(line,linepos:longint);
497 oldlinebuf : plongintarr;
498 begin
499 if line<1 then
500 exit;
501 while (line>=maxlinebuf) do
502 begin
503 oldlinebuf:=linebuf;
504 { create new linebuf and move old info }
505 getmem(linebuf,(maxlinebuf+linebufincrease) shl 2);
506 if assigned(oldlinebuf) then
507 begin
508 move(oldlinebuf^,linebuf^,maxlinebuf shl 2);
509 freemem(oldlinebuf,maxlinebuf shl 2);
510 end;
511 fillchar(linebuf^[maxlinebuf],linebufincrease shl 2,0);
512 inc(maxlinebuf,linebufincrease);
513 end;
514 linebuf^[line]:=linepos;
515 end;
518 function tinputfile.getlinestr(l:longint):string;
520 c : char;
522 fpos : longint;
523 p : pchar;
524 begin
525 getlinestr:='';
526 if l<maxlinebuf then
527 begin
528 fpos:=linebuf^[l];
529 { fpos is set negativ if the line was already written }
530 { but we still know the correct value }
531 if fpos<0 then
532 fpos:=-fpos+1;
533 if closed then
534 open;
535 { in current buf ? }
536 if (fpos<bufstart) or (fpos>bufstart+bufsize) then
537 begin
538 seekbuf(fpos);
539 readbuf;
540 end;
541 { the begin is in the buf now simply read until #13,#10 }
542 i:=0;
543 p:=@buf[fpos-bufstart];
544 repeat
545 c:=p^;
546 if c=#0 then
547 begin
548 if endoffile then
549 break;
550 readbuf;
551 p:=buf;
552 c:=p^;
553 end;
554 if c in [#10,#13] then
555 break;
556 inc(i);
557 getlinestr[i]:=c;
558 inc(longint(p));
559 until (i=255);
560 {$ifndef TP}
561 {$ifopt H+}
562 setlength(getlinestr,i);
563 {$else}
564 getlinestr[0]:=chr(i);
565 {$endif}
566 {$else}
567 getlinestr[0]:=chr(i);
568 {$endif}
569 end;
570 end;
573 function tinputfile.fileopen(const filename: string): boolean;
574 begin
575 abstract;
576 fileopen:=false;
577 end;
580 function tinputfile.fileseek(pos: longint): boolean;
581 begin
582 abstract;
583 fileseek:=false;
584 end;
587 function tinputfile.fileread(var databuf; maxsize: longint): longint;
588 begin
589 abstract;
590 fileread:=0;
591 end;
594 function tinputfile.fileeof: boolean;
595 begin
596 abstract;
597 fileeof:=false;
598 end;
601 function tinputfile.fileclose: boolean;
602 begin
603 abstract;
604 fileclose:=false;
605 end;
608 {****************************************************************************
609 TDOSINPUTFILE
610 ****************************************************************************}
612 function tdosinputfile.fileopen(const filename: string): boolean;
614 ofm : byte;
615 begin
616 ofm:=filemode;
617 filemode:=0;
618 Assign(f,filename);
619 {$I-}
620 reset(f,1);
621 {$I+}
622 filemode:=ofm;
623 fileopen:=(ioresult=0);
624 end;
627 function tdosinputfile.fileseek(pos: longint): boolean;
628 begin
629 {$I-}
630 seek(f,Pos);
631 {$I+}
632 fileseek:=(ioresult=0);
633 end;
636 function tdosinputfile.fileread(var databuf; maxsize: longint): longint;
637 var w: {$ifdef TP}word{$else}longint{$endif};
638 begin
639 blockread(f,databuf,maxsize,w);
640 fileread:=w;
641 end;
644 function tdosinputfile.fileeof: boolean;
645 begin
646 fileeof:=eof(f);
647 end;
650 function tdosinputfile.fileclose: boolean;
651 begin
652 {$I-}
653 system.close(f);
654 {$I+}
655 fileclose:=(ioresult=0);
656 end;
659 {****************************************************************************
660 TFILEMANAGER
661 ****************************************************************************}
663 constructor tfilemanager.init;
664 begin
665 files:=nil;
666 last_ref_index:=0;
667 cacheindex:=0;
668 cacheinputfile:=nil;
669 end;
672 destructor tfilemanager.done;
674 hp : pinputfile;
675 begin
676 hp:=files;
677 while assigned(hp) do
678 begin
679 files:=files^.ref_next;
680 dispose(hp,done);
681 hp:=files;
682 end;
683 last_ref_index:=0;
684 end;
687 procedure tfilemanager.register_file(f : pinputfile);
688 begin
689 { don't register macro's }
690 if f^.is_macro then
691 exit;
692 inc(last_ref_index);
693 f^.ref_next:=files;
694 f^.ref_index:=last_ref_index;
695 files:=f;
696 { update cache }
697 cacheindex:=last_ref_index;
698 cacheinputfile:=f;
699 {$ifdef FPC}
700 {$ifdef heaptrc}
701 writeln(stderr,f^.name^,' index ',current_module^.unit_index*100000+f^.ref_index);
702 {$endif heaptrc}
703 {$endif FPC}
704 end;
707 { this procedure is necessary after loading the
708 sources files from a PPU file PM }
709 procedure tfilemanager.inverse_register_indexes;
711 f : pinputfile;
712 begin
713 f:=files;
714 while assigned(f) do
715 begin
716 f^.ref_index:=last_ref_index-f^.ref_index+1;
717 f:=f^.ref_next;
718 end;
719 { reset cache }
720 cacheindex:=0;
721 cacheinputfile:=nil;
722 end;
726 function tfilemanager.get_file(l :longint) : pinputfile;
728 ff : pinputfile;
729 begin
730 { check cache }
731 if (l=cacheindex) and assigned(cacheinputfile) then
732 begin
733 get_file:=cacheinputfile;
734 exit;
735 end;
736 ff:=files;
737 while assigned(ff) and (ff^.ref_index<>l) do
738 ff:=ff^.ref_next;
739 get_file:=ff;
740 end;
743 function tfilemanager.get_file_name(l :longint):string;
745 hp : pinputfile;
746 begin
747 hp:=get_file(l);
748 if assigned(hp) then
749 get_file_name:=hp^.name^
750 else
751 get_file_name:='';
752 end;
755 function tfilemanager.get_file_path(l :longint):string;
757 hp : pinputfile;
758 begin
759 hp:=get_file(l);
760 if assigned(hp) then
761 get_file_path:=hp^.path^
762 else
763 get_file_path:='';
764 end;
767 function get_source_file(moduleindex,fileindex : word) : pinputfile;
769 hp : pmodule;
770 f : pinputfile;
771 begin
772 hp:=pmodule(loaded_units.first);
773 while assigned(hp) and (hp^.unit_index<>moduleindex) do
774 hp:=pmodule(hp^.next);
775 get_source_file:=nil;
776 if not assigned(hp) then
777 exit;
778 f:=pinputfile(hp^.sourcefiles^.files);
779 while assigned(f) do
780 begin
781 if f^.ref_index=fileindex then
782 begin
783 get_source_file:=f;
784 exit;
785 end;
786 f:=pinputfile(f^.ref_next);
787 end;
788 end;
791 {****************************************************************************
792 TLinkContainerItem
793 ****************************************************************************}
795 {$IFDEF NEWST}
796 constructor TLinkItem.Init(const s:string;m:longint);
797 begin
798 inherited Init;
799 data:=stringdup(s);
800 needlink:=m;
801 end;
804 destructor TLinkItem.Done;
805 begin
806 stringdispose(data);
807 end;
808 {$ELSE}
809 constructor TLinkContainerItem.Init(const s:string;m:longint);
810 begin
811 inherited Init;
812 data:=stringdup(s);
813 needlink:=m;
814 end;
817 destructor TLinkContainerItem.Done;
818 begin
819 stringdispose(data);
820 end;
821 {$ENDIF NEWST}
824 {****************************************************************************
825 TLinkContainer
826 ****************************************************************************}
828 {$IFNDEF NEWST}
829 constructor TLinkContainer.Init;
830 begin
831 inherited init;
832 end;
835 procedure TLinkContainer.insert(const s : string;m:longint);
837 newnode : plinkcontaineritem;
838 begin
839 {if find(s) then
840 exit; }
841 new(newnode,init(s,m));
842 inherited insert(newnode);
843 end;
846 function TLinkContainer.get(var m:longint) : string;
848 p : plinkcontaineritem;
849 begin
850 p:=plinkcontaineritem(inherited get);
851 if p=nil then
852 begin
853 get:='';
854 m:=0;
855 exit;
856 end;
857 get:=p^.data^;
858 m:=p^.needlink;
859 dispose(p,done);
860 end;
863 function TLinkContainer.getusemask(mask:longint) : string;
865 p : plinkcontaineritem;
866 found : boolean;
867 begin
868 found:=false;
869 repeat
870 p:=plinkcontaineritem(inherited get);
871 if p=nil then
872 begin
873 getusemask:='';
874 exit;
875 end;
876 getusemask:=p^.data^;
877 found:=(p^.needlink and mask)<>0;
878 dispose(p,done);
879 until found;
880 end;
883 function TLinkContainer.find(const s:string):boolean;
885 newnode : plinkcontaineritem;
886 begin
887 find:=false;
888 newnode:=plinkcontaineritem(root);
889 while assigned(newnode) do
890 begin
891 if newnode^.data^=s then
892 begin
893 find:=true;
894 exit;
895 end;
896 newnode:=plinkcontaineritem(newnode^.next);
897 end;
898 end;
899 {$ENDIF NEWST}
903 {****************************************************************************
904 TMODULE
905 ****************************************************************************}
907 procedure tmodule.setfilename(const fn:string;allowoutput:boolean);
909 p : dirstr;
910 n : NameStr;
911 e : ExtStr;
912 begin
913 stringdispose(objfilename);
914 stringdispose(asmfilename);
915 stringdispose(ppufilename);
916 stringdispose(staticlibfilename);
917 stringdispose(sharedlibfilename);
918 stringdispose(exefilename);
919 stringdispose(outputpath);
920 stringdispose(path);
921 { Create names }
922 fsplit(fn,p,n,e);
923 n:=FixFileName(n);
924 { set path }
925 path:=stringdup(FixPath(p,false));
926 { obj,asm,ppu names }
927 p:=path^;
928 if AllowOutput then
929 begin
930 if (OutputUnitDir<>'') then
931 p:=OutputUnitDir
932 else
933 if (OutputExeDir<>'') then
934 p:=OutputExeDir;
935 end;
936 outputpath:=stringdup(p);
937 objfilename:=stringdup(p+n+target_info.objext);
938 asmfilename:=stringdup(p+n+target_info.asmext);
939 ppufilename:=stringdup(p+n+target_info.unitext);
940 { lib and exe could be loaded with a file specified with -o }
941 if AllowOutput and (OutputFile<>'') and (compile_level=1) then
942 n:=OutputFile;
943 staticlibfilename:=stringdup(p+target_os.libprefix+n+target_os.staticlibext);
944 if target_info.target=target_i386_WIN32 then
945 sharedlibfilename:=stringdup(p+n+target_os.sharedlibext)
946 else
947 sharedlibfilename:=stringdup(p+target_os.libprefix+n+target_os.sharedlibext);
948 { output dir of exe can be specified separatly }
949 if AllowOutput and (OutputExeDir<>'') then
950 p:=OutputExeDir
951 else
952 p:=path^;
953 exefilename:=stringdup(p+n+target_info.exeext);
954 end;
957 function tmodule.openppu:boolean;
959 objfiletime,
960 ppufiletime,
961 asmfiletime : longint;
962 begin
963 openppu:=false;
964 Message1(unit_t_ppu_loading,ppufilename^);
965 { Get ppufile time (also check if the file exists) }
966 ppufiletime:=getnamedfiletime(ppufilename^);
967 if ppufiletime=-1 then
968 exit;
969 { Open the ppufile }
970 Message1(unit_u_ppu_name,ppufilename^);
971 ppufile:=new(pppufile,init(ppufilename^));
972 ppufile^.change_endian:=source_os.endian<>target_os.endian;
973 if not ppufile^.open then
974 begin
975 dispose(ppufile,done);
976 ppufile:=nil;
977 Message(unit_u_ppu_file_too_short);
978 exit;
979 end;
980 { check for a valid PPU file }
981 if not ppufile^.CheckPPUId then
982 begin
983 dispose(ppufile,done);
984 ppufile:=nil;
985 Message(unit_u_ppu_invalid_header);
986 exit;
987 end;
988 { check for allowed PPU versions }
989 if not (ppufile^.GetPPUVersion = CurrentPPUVersion) then
990 begin
991 Message1(unit_u_ppu_invalid_version,tostr(ppufile^.GetPPUVersion));
992 dispose(ppufile,done);
993 ppufile:=nil;
994 exit;
995 end;
996 { check the target processor }
997 if ttargetcpu(ppufile^.header.cpu)<>target_cpu then
998 begin
999 Message(unit_u_ppu_invalid_processor);
1000 dispose(ppufile,done);
1001 ppufile:=nil;
1002 exit;
1003 end;
1004 { check target }
1005 if ttarget(ppufile^.header.target)<>target_info.target then
1006 begin
1007 Message(unit_u_ppu_invalid_target);
1008 dispose(ppufile,done);
1009 ppufile:=nil;
1010 exit;
1011 end;
1012 { Load values to be access easier }
1013 flags:=ppufile^.header.flags;
1014 crc:=ppufile^.header.checksum;
1015 interface_crc:=ppufile^.header.interface_checksum;
1016 { Show Debug info }
1017 Message1(unit_u_ppu_time,filetimestring(ppufiletime));
1018 Message1(unit_u_ppu_flags,tostr(flags));
1019 Message1(unit_u_ppu_crc,tostr(ppufile^.header.checksum));
1020 Message1(unit_u_ppu_crc,tostr(ppufile^.header.interface_checksum)+' (intfc)');
1021 { check the object and assembler file to see if we need only to
1022 assemble, only if it's not in a library }
1023 do_compile:=false;
1024 if (flags and uf_in_library)=0 then
1025 begin
1026 if (flags and uf_smart_linked)<>0 then
1027 begin
1028 objfiletime:=getnamedfiletime(staticlibfilename^);
1029 Message2(unit_u_check_time,staticlibfilename^,filetimestring(objfiletime));
1030 if (ppufiletime<0) or (objfiletime<0) or (ppufiletime>objfiletime) then
1031 begin
1032 recompile_reason:=rr_libolder;
1033 Message(unit_u_recompile_staticlib_is_older);
1034 do_compile:=true;
1035 dispose(ppufile,done);
1036 ppufile:=nil;
1037 exit;
1038 end;
1039 end;
1040 if (flags and uf_static_linked)<>0 then
1041 begin
1042 { the objectfile should be newer than the ppu file }
1043 objfiletime:=getnamedfiletime(objfilename^);
1044 Message2(unit_u_check_time,objfilename^,filetimestring(objfiletime));
1045 if (ppufiletime<0) or (objfiletime<0) or (ppufiletime>objfiletime) then
1046 begin
1047 { check if assembler file is older than ppu file }
1048 asmfileTime:=GetNamedFileTime(asmfilename^);
1049 Message2(unit_u_check_time,asmfilename^,filetimestring(asmfiletime));
1050 if (asmfiletime<0) or (ppufiletime>asmfiletime) then
1051 begin
1052 Message(unit_u_recompile_obj_and_asm_older);
1053 recompile_reason:=rr_objolder;
1054 do_compile:=true;
1055 dispose(ppufile,done);
1056 ppufile:=nil;
1057 exit;
1059 else
1060 begin
1061 Message(unit_u_recompile_obj_older_than_asm);
1062 if not(cs_asm_extern in aktglobalswitches) then
1063 begin
1064 do_compile:=true;
1065 recompile_reason:=rr_asmolder;
1066 dispose(ppufile,done);
1067 ppufile:=nil;
1068 exit;
1069 end;
1070 end;
1071 end;
1072 end;
1073 end;
1074 openppu:=true;
1075 end;
1078 function tmodule.search_unit(const n : string;onlysource:boolean):boolean;
1080 singlepathstring,
1081 filename : string;
1083 Function UnitExists(const ext:string):boolean;
1084 begin
1085 Message1(unit_t_unitsearch,Singlepathstring+filename+ext);
1086 UnitExists:=FileExists(Singlepathstring+FileName+ext);
1087 end;
1089 Function PPUSearchPath(const s:string):boolean;
1091 found : boolean;
1092 begin
1093 Found:=false;
1094 singlepathstring:=FixPath(s,false);
1095 { Check for PPU file }
1096 Found:=UnitExists(target_info.unitext);
1097 if Found then
1098 Begin
1099 SetFileName(SinglePathString+FileName,false);
1100 Found:=OpenPPU;
1101 End;
1102 PPUSearchPath:=Found;
1103 end;
1105 Function SourceSearchPath(const s:string):boolean;
1107 found : boolean;
1108 ext : string[8];
1109 begin
1110 Found:=false;
1111 singlepathstring:=FixPath(s,false);
1112 { Check for Sources }
1113 ppufile:=nil;
1114 do_compile:=true;
1115 recompile_reason:=rr_noppu;
1116 {Check for .pp file}
1117 Found:=UnitExists(target_os.sourceext);
1118 if Found then
1119 Ext:=target_os.sourceext
1120 else
1121 begin
1122 {Check for .pas}
1123 Found:=UnitExists(target_os.pasext);
1124 if Found then
1125 Ext:=target_os.pasext;
1126 end;
1127 stringdispose(mainsource);
1128 if Found then
1129 begin
1130 sources_avail:=true;
1131 {Load Filenames when found}
1132 mainsource:=StringDup(SinglePathString+FileName+Ext);
1133 SetFileName(SinglePathString+FileName,false);
1135 else
1136 sources_avail:=false;
1137 SourceSearchPath:=Found;
1138 end;
1140 Function SearchPath(const s:string):boolean;
1142 found : boolean;
1143 begin
1144 { First check for a ppu, then for the source }
1145 found:=false;
1146 if not onlysource then
1147 found:=PPUSearchPath(s);
1148 if not found then
1149 found:=SourceSearchPath(s);
1150 SearchPath:=found;
1151 end;
1153 Function SearchPathList(list:TSearchPathList):boolean;
1155 hp : PStringQueueItem;
1156 found : boolean;
1157 begin
1158 found:=false;
1159 hp:=list.First;
1160 while assigned(hp) do
1161 begin
1162 found:=SearchPath(hp^.data^);
1163 if found then
1164 break;
1165 hp:=hp^.next;
1166 end;
1167 SearchPathList:=found;
1168 end;
1171 fnd : boolean;
1172 begin
1173 filename:=FixFileName(n);
1174 { try to find unit
1175 1. look for ppu in cwd
1176 2. look for ppu in outputpath if set, this is tp7 compatible (PFV)
1177 3. look for source in cwd
1178 4. local unit pathlist
1179 5. global unit pathlist }
1180 fnd:=false;
1181 if not onlysource then
1182 begin
1183 fnd:=PPUSearchPath('.');
1184 if (not fnd) and (current_module^.outputpath^<>'') then
1185 fnd:=PPUSearchPath(current_module^.outputpath^);
1186 end;
1187 if (not fnd) then
1188 fnd:=SourceSearchPath('.');
1189 if (not fnd) then
1190 fnd:=SearchPathList(current_module^.LocalUnitSearchPath);
1191 if (not fnd) then
1192 fnd:=SearchPathList(UnitSearchPath);
1194 { try to find a file with the first 8 chars of the modulename, like
1195 dos }
1196 if (not fnd) and (length(filename)>8) then
1197 begin
1198 filename:=copy(filename,1,8);
1199 fnd:=SearchPath('.');
1200 if (not fnd) then
1201 fnd:=SearchPathList(current_module^.LocalUnitSearchPath);
1202 if not fnd then
1203 fnd:=SearchPathList(UnitSearchPath);
1204 end;
1205 search_unit:=fnd;
1206 end;
1210 procedure tmodule.reset;
1212 pm : pdependent_unit;
1213 begin
1214 if assigned(scanner) then
1215 pscannerfile(scanner)^.invalid:=true;
1216 if assigned(globalsymtable) then
1217 begin
1218 dispose(punitsymtable(globalsymtable),done);
1219 globalsymtable:=nil;
1220 end;
1221 if assigned(localsymtable) then
1222 begin
1223 dispose(punitsymtable(localsymtable),done);
1224 localsymtable:=nil;
1225 end;
1226 if assigned(map) then
1227 begin
1228 dispose(map);
1229 map:=nil;
1230 end;
1231 if assigned(ppufile) then
1232 begin
1233 dispose(ppufile,done);
1234 ppufile:=nil;
1235 end;
1236 sourcefiles^.done;
1237 sourcefiles^.init;
1238 imports^.done;
1239 imports^.init;
1240 _exports^.done;
1241 _exports^.init;
1242 used_units.done;
1243 used_units.init;
1244 { all units that depend on this one must be recompiled ! }
1245 pm:=pdependent_unit(dependent_units.first);
1246 while assigned(pm) do
1247 begin
1248 if pm^.u^.in_second_compile then
1249 Comment(v_debug,'No reload already in second compile: '+pm^.u^.modulename^)
1250 else
1251 begin
1252 pm^.u^.do_reload:=true;
1253 Comment(v_debug,'Reloading '+pm^.u^.modulename^+' needed because '+modulename^+' is reloaded');
1254 end;
1255 pm:=pdependent_unit(pm^.next);
1256 end;
1257 dependent_units.done;
1258 dependent_units.init;
1259 resourcefiles.done;
1260 resourcefiles.init;
1261 linkunitofiles.done;
1262 linkunitofiles.init{$IFDEF NEWST}(8,4){$ENDIF};
1263 linkunitstaticlibs.done;
1264 linkunitstaticlibs.init{$IFDEF NEWST}(8,4){$ENDIF};
1265 linkunitsharedlibs.done;
1266 linkunitsharedlibs.init{$IFDEF NEWST}(8,4){$ENDIF};
1267 linkotherofiles.done;
1268 linkotherofiles.init{$IFDEF NEWST}(8,4){$ENDIF};
1269 linkotherstaticlibs.done;
1270 linkotherstaticlibs.init{$IFDEF NEWST}(8,4){$ENDIF};
1271 linkothersharedlibs.done;
1272 linkothersharedlibs.init{$IFDEF NEWST}(8,4){$ENDIF};
1273 uses_imports:=false;
1274 do_assemble:=false;
1275 do_compile:=false;
1276 { sources_avail:=true;
1277 should not be changed PM }
1278 compiled:=false;
1279 in_implementation:=false;
1280 in_global:=true;
1281 {loaded_from:=nil;
1282 should not be changed PFV }
1283 flags:=0;
1284 crc:=0;
1285 interface_crc:=0;
1286 unitcount:=1;
1287 recompile_reason:=rr_unknown;
1288 end;
1291 constructor tmodule.init(const s:string;_is_unit:boolean);
1293 p : dirstr;
1294 n : namestr;
1295 e : extstr;
1296 begin
1297 FSplit(s,p,n,e);
1298 { Programs have the name program to don't conflict with dup id's }
1299 if _is_unit then
1300 {$ifdef UNITALIASES}
1301 modulename:=stringdup(GetUnitAlias(Upper(n)))
1302 {$else}
1303 modulename:=stringdup(Upper(n))
1304 {$endif}
1305 else
1306 modulename:=stringdup('PROGRAM');
1307 mainsource:=stringdup(s);
1308 ppufilename:=nil;
1309 objfilename:=nil;
1310 asmfilename:=nil;
1311 staticlibfilename:=nil;
1312 sharedlibfilename:=nil;
1313 exefilename:=nil;
1314 { Dos has the famous 8.3 limit :( }
1315 {$ifdef SHORTASMPREFIX}
1316 asmprefix:=stringdup(FixFileName('as'));
1317 {$else}
1318 asmprefix:=stringdup(FixFileName(n));
1319 {$endif}
1320 outputpath:=nil;
1321 path:=nil;
1322 setfilename(p+n,true);
1323 localunitsearchpath.init;
1324 localobjectsearchpath.init;
1325 localincludesearchpath.init;
1326 locallibrarysearchpath.init;
1327 used_units.init;
1328 dependent_units.init;
1329 new(sourcefiles,init);
1330 resourcefiles.init;
1331 linkunitofiles.init{$IFDEF NEWST}(8,4){$ENDIF};
1332 linkunitstaticlibs.init{$IFDEF NEWST}(8,4){$ENDIF};
1333 linkunitsharedlibs.init{$IFDEF NEWST}(8,4){$ENDIF};
1334 linkotherofiles.init{$IFDEF NEWST}(8,4){$ENDIF};
1335 linkotherstaticlibs.init{$IFDEF NEWST}(8,4){$ENDIF};
1336 linkothersharedlibs.init{$IFDEF NEWST}(8,4){$ENDIF};
1337 ppufile:=nil;
1338 scanner:=nil;
1339 map:=nil;
1340 globalsymtable:=nil;
1341 localsymtable:=nil;
1342 loaded_from:=nil;
1343 flags:=0;
1344 crc:=0;
1345 interface_crc:=0;
1346 do_reload:=false;
1347 unitcount:=1;
1348 inc(global_unit_count);
1349 unit_index:=global_unit_count;
1350 do_assemble:=false;
1351 do_compile:=false;
1352 sources_avail:=true;
1353 sources_checked:=false;
1354 compiled:=false;
1355 recompile_reason:=rr_unknown;
1356 in_second_load:=false;
1357 in_compile:=false;
1358 in_second_compile:=false;
1359 in_implementation:=false;
1360 in_global:=true;
1361 is_unit:=_is_unit;
1362 islibrary:=false;
1363 uses_imports:=false;
1364 imports:=new(plinkedlist,init);
1365 _exports:=new(plinkedlist,init);
1366 { search the PPU file if it is an unit }
1367 if is_unit then
1368 begin
1369 search_unit(modulename^,false);
1370 { it the sources_available is changed then we know that
1371 the sources aren't available }
1372 if not sources_avail then
1373 sources_checked:=true;
1374 end;
1375 end;
1378 destructor tmodule.done;
1379 {$ifdef MEMDEBUG}
1381 d : tmemdebug;
1382 {$endif}
1383 begin
1384 if assigned(map) then
1385 dispose(map);
1386 if assigned(ppufile) then
1387 dispose(ppufile,done);
1388 ppufile:=nil;
1389 if assigned(imports) then
1390 dispose(imports,done);
1391 imports:=nil;
1392 if assigned(_exports) then
1393 dispose(_exports,done);
1394 _exports:=nil;
1395 if assigned(scanner) then
1396 pscannerfile(scanner)^.invalid:=true;
1397 if assigned(sourcefiles) then
1398 dispose(sourcefiles,done);
1399 sourcefiles:=nil;
1400 used_units.done;
1401 dependent_units.done;
1402 resourcefiles.done;
1403 linkunitofiles.done;
1404 linkunitstaticlibs.done;
1405 linkunitsharedlibs.done;
1406 linkotherofiles.done;
1407 linkotherstaticlibs.done;
1408 linkothersharedlibs.done;
1409 stringdispose(objfilename);
1410 stringdispose(asmfilename);
1411 stringdispose(ppufilename);
1412 stringdispose(staticlibfilename);
1413 stringdispose(sharedlibfilename);
1414 stringdispose(exefilename);
1415 stringdispose(outputpath);
1416 stringdispose(path);
1417 stringdispose(modulename);
1418 stringdispose(mainsource);
1419 stringdispose(asmprefix);
1420 localunitsearchpath.done;
1421 localobjectsearchpath.done;
1422 localincludesearchpath.done;
1423 locallibrarysearchpath.done;
1424 {$ifdef MEMDEBUG}
1425 d.init('symtable');
1426 {$endif}
1427 if assigned(globalsymtable) then
1428 dispose(punitsymtable(globalsymtable),done);
1429 globalsymtable:=nil;
1430 if assigned(localsymtable) then
1431 dispose(punitsymtable(localsymtable),done);
1432 localsymtable:=nil;
1433 {$ifdef MEMDEBUG}
1434 d.done;
1435 {$endif}
1436 inherited done;
1437 end;
1440 {****************************************************************************
1441 TUSED_UNIT
1442 ****************************************************************************}
1444 constructor tused_unit.init(_u : pmodule;intface:boolean);
1445 begin
1446 u:=_u;
1447 in_interface:=intface;
1448 in_uses:=false;
1449 is_stab_written:=false;
1450 loaded:=true;
1451 name:=stringdup(_u^.modulename^);
1452 checksum:=_u^.crc;
1453 interface_checksum:=_u^.interface_crc;
1454 unitid:=0;
1455 end;
1458 constructor tused_unit.init_to_load(const n:string;c,intfc:longint;intface:boolean);
1459 begin
1460 u:=nil;
1461 in_interface:=intface;
1462 in_uses:=false;
1463 is_stab_written:=false;
1464 loaded:=false;
1465 name:=stringdup(n);
1466 checksum:=c;
1467 interface_checksum:=intfc;
1468 unitid:=0;
1469 end;
1472 destructor tused_unit.done;
1473 begin
1474 stringdispose(name);
1475 inherited done;
1476 end;
1479 {****************************************************************************
1480 TDENPENDENT_UNIT
1481 ****************************************************************************}
1483 constructor tdependent_unit.init(_u : pmodule);
1484 begin
1485 u:=_u;
1486 end;
1488 end.
1490 $Log$
1491 Revision 1.1 2002/02/19 08:22:20 sasu
1492 Initial revision
1494 Revision 1.1.2.3 2000/09/26 08:48:09 pierre
1495 * close ppu files if recompiling
1497 Revision 1.1.2.2 2000/08/13 08:59:18 peter
1498 * fixed fileseek() typo
1500 Revision 1.1.2.1 2000/08/12 15:29:52 peter
1501 * patch from Gabor for IDE to support memory stream reading
1503 Revision 1.1 2000/07/13 06:29:50 michael
1504 + Initial import
1506 Revision 1.119 2000/07/03 21:08:54 pierre
1507 * fix for bug 1025
1509 Revision 1.118 2000/06/15 18:10:11 peter
1510 * first look for ppu in cwd and outputpath and after that for source
1511 in cwd
1512 * fixpath() for not linux makes path now lowercase so comparing paths
1513 with different cases (sometimes a drive letter could be
1514 uppercased) gives the expected results
1515 * sources_checked flag if there was already a full search for sources
1516 which aren't found, so another scan isn't done when checking for the
1517 sources only when recompile is needed
1519 Revision 1.117 2000/02/28 17:23:56 daniel
1520 * Current work of symtable integration committed. The symtable can be
1521 activated by defining 'newst', but doesn't compile yet. Changes in type
1522 checking and oop are completed. What is left is to write a new
1523 symtablestack and adapt the parser to use it.
1525 Revision 1.116 2000/02/24 18:41:38 peter
1526 * removed warnings/notes
1528 Revision 1.115 2000/02/10 16:00:23 peter
1529 * dont' check for ppl files as they aren't used atm.
1531 Revision 1.114 2000/02/09 13:22:52 peter
1532 * log truncated
1534 Revision 1.113 2000/01/11 09:52:06 peter
1535 * fixed placing of .sl directories
1536 * use -b again for base-file selection
1537 * fixed group writing for linux with smartlinking
1539 Revision 1.112 2000/01/07 01:14:27 peter
1540 * updated copyright to 2000
1542 Revision 1.111 1999/12/08 01:01:11 peter
1543 * fixed circular unit reference checking. loaded_from was reset after
1544 reseting a unit, so no loaded_from info was available anymore.
1546 Revision 1.110 1999/11/16 23:39:04 peter
1547 * use outputexedir for link.res location
1549 Revision 1.109 1999/11/12 11:03:50 peter
1550 * searchpaths changed to stringqueue object
1552 Revision 1.108 1999/11/06 14:34:20 peter
1553 * truncated log to 20 revs
1555 Revision 1.107 1999/11/04 23:13:25 peter
1556 * moved unit alias support into ifdef
1558 Revision 1.106 1999/11/04 10:54:02 peter
1559 + -Ua<oldname>=<newname> unit alias support
1561 Revision 1.105 1999/10/28 13:14:00 pierre
1562 * allow doubles in TLinkContainer needed for double libraries
1564 Revision 1.104 1999/09/27 23:40:12 peter
1565 * fixed macro within macro endless-loop
1567 Revision 1.103 1999/09/16 08:00:50 pierre
1568 + compiled_module to avoid wrong file info when load PPU files
1570 Revision 1.102 1999/08/31 15:51:10 pierre
1571 * in_second_compile cleaned up, in_compile and in_second_load added
1573 Revision 1.101 1999/08/27 10:43:20 pierre
1574 + interface CRC check with ifdef Test_double_checksum added
1576 Revision 1.100 1999/08/24 13:14:01 peter
1577 * MEMDEBUG to see the sizes of asmlist,asmsymbols,symtables