1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
10 -- Copyright (C) 1992-2002 Free Software Foundation, Inc. --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
21 -- MA 02111-1307, USA. --
23 -- GNAT was originally developed by the GNAT team at New York University. --
24 -- Extensive contributions were provided by Ada Core Technologies Inc. --
26 ------------------------------------------------------------------------------
29 with ALI
.Util
; use ALI
.Util
;
30 with Binderr
; use Binderr
;
31 with Butil
; use Butil
;
32 with Fname
; use Fname
;
33 with Gnatvsn
; use Gnatvsn
;
34 with GNAT
.OS_Lib
; use GNAT
.OS_Lib
;
35 with Namet
; use Namet
;
37 with Osint
; use Osint
;
38 with Osint
.L
; use Osint
.L
;
39 with Output
; use Output
;
40 with Targparm
; use Targparm
;
41 with Types
; use Types
;
45 Max_Column
: constant := 80;
48 OK
, -- matching timestamp
49 Checksum_OK
, -- only matching checksum
50 Not_Found
, -- file not found on source PATH
51 Not_Same
, -- neither checksum nor timestamp matching
52 Not_First_On_PATH
); -- matching file hidden by Not_Same file on path
55 type Dir_Ref
is access Dir_Data
;
57 type Dir_Data
is record
58 Value
: String_Access
;
63 First_Source_Dir
: Dir_Ref
;
64 Last_Source_Dir
: Dir_Ref
;
65 -- The list of source directories from the command line.
66 -- These directories are added using Osint.Add_Src_Search_Dir
67 -- after those of the GNAT Project File, if any.
69 First_Lib_Dir
: Dir_Ref
;
70 Last_Lib_Dir
: Dir_Ref
;
71 -- The list of object directories from the command line.
72 -- These directories are added using Osint.Add_Lib_Search_Dir
73 -- after those of the GNAT Project File, if any.
75 Main_File
: File_Name_Type
;
76 Ali_File
: File_Name_Type
;
78 Text
: Text_Buffer_Ptr
;
83 Too_Long
: Boolean := False;
84 -- When True, lines are too long for multi-column output and each
85 -- item of information is on a different line.
87 Selective_Output
: Boolean := False;
88 Print_Usage
: Boolean := False;
89 Print_Unit
: Boolean := True;
90 Print_Source
: Boolean := True;
91 Print_Object
: Boolean := True;
92 -- Flags controlling the form of the outpout
94 Dependable
: Boolean := False; -- flag -d
95 Also_Predef
: Boolean := False;
99 Source_Start
: Integer;
100 Source_End
: Integer;
101 Object_Start
: Integer;
102 Object_End
: Integer;
103 -- Various column starts and ends
105 Spaces
: constant String (1 .. Max_Column
) := (others => ' ');
107 -----------------------
108 -- Local Subprograms --
109 -----------------------
111 procedure Add_Lib_Dir
(Dir
: String; And_Save
: Boolean);
112 -- Add an object directory, using Osint.Add_Lib_Search_Dir
113 -- if And_Save is False or keeping in the list First_Lib_Dir,
114 -- Last_Lib_Dir if And_Save is True.
116 procedure Add_Source_Dir
(Dir
: String; And_Save
: Boolean);
117 -- Add a source directory, using Osint.Add_Src_Search_Dir
118 -- if And_Save is False or keeping in the list First_Source_Dir,
119 -- Last_Source_Dir if And_Save is True.
121 procedure Find_General_Layout
;
122 -- Determine the structure of the output (multi columns or not, etc)
124 procedure Find_Status
125 (FS
: in out File_Name_Type
;
126 Stamp
: Time_Stamp_Type
;
128 Status
: out File_Status
);
129 -- Determine the file status (Status) of the file represented by FS
130 -- with the expected Stamp and checksum given as argument. FS will be
131 -- updated to the full file name if available.
133 function Corresponding_Sdep_Entry
(A
: ALI_Id
; U
: Unit_Id
) return Sdep_Id
;
134 -- Give the Sdep entry corresponding to the unit U in ali record A.
136 procedure Output_Object
(O
: File_Name_Type
);
137 -- Print out the name of the object when requested
139 procedure Output_Source
(Sdep_I
: Sdep_Id
);
140 -- Print out the name and status of the source corresponding to this
143 procedure Output_Status
(FS
: File_Status
; Verbose
: Boolean);
144 -- Print out FS either in a coded form if verbose is false or in an
145 -- expanded form otherwise.
147 procedure Output_Unit
(U_Id
: Unit_Id
);
148 -- Print out information on the unit when requested
150 procedure Reset_Print
;
151 -- Reset Print flags properly when selective output is chosen
153 procedure Scan_Ls_Arg
(Argv
: String; And_Save
: Boolean);
154 -- Scan and process lser specific arguments. Argv is a single argument.
157 -- Print usage message.
163 procedure Add_Lib_Dir
(Dir
: String; And_Save
: Boolean) is
166 if First_Lib_Dir
= null then
169 (Value => new String'(Dir
),
171 Last_Lib_Dir
:= First_Lib_Dir
;
176 (Value => new String'(Dir
),
178 Last_Lib_Dir
:= Last_Lib_Dir
.Next
;
182 Add_Lib_Search_Dir
(Dir
);
190 procedure Add_Source_Dir
(Dir
: String; And_Save
: Boolean) is
193 if First_Source_Dir
= null then
196 (Value => new String'(Dir
),
198 Last_Source_Dir
:= First_Source_Dir
;
201 Last_Source_Dir
.Next
:=
203 (Value => new String'(Dir
),
205 Last_Source_Dir
:= Last_Source_Dir
.Next
;
209 Add_Src_Search_Dir
(Dir
);
213 ------------------------------
214 -- Corresponding_Sdep_Entry --
215 ------------------------------
217 function Corresponding_Sdep_Entry
223 for D
in ALIs
.Table
(A
).First_Sdep
.. ALIs
.Table
(A
).Last_Sdep
loop
224 if Sdep
.Table
(D
).Sfile
= Units
.Table
(U
).Sfile
then
229 Error_Msg_Name_1
:= Units
.Table
(U
).Uname
;
230 Error_Msg_Name_2
:= ALIs
.Table
(A
).Afile
;
232 Error_Msg
("wrong ALI format, can't find dependency line for & in %");
233 Exit_Program
(E_Fatal
);
234 end Corresponding_Sdep_Entry
;
236 -------------------------
237 -- Find_General_Layout --
238 -------------------------
240 procedure Find_General_Layout
is
241 Max_Unit_Length
: Integer := 11;
242 Max_Src_Length
: Integer := 11;
243 Max_Obj_Length
: Integer := 11;
249 -- Compute maximum of each column
251 for Id
in ALIs
.First
.. ALIs
.Last
loop
253 Get_Name_String
(Units
.Table
(ALIs
.Table
(Id
).First_Unit
).Uname
);
254 if Also_Predef
or else not Is_Internal_Unit
then
258 Max_Unit_Length
:= Integer'Max (Max_Unit_Length
, Len
);
262 FS
:= Full_Source_Name
(ALIs
.Table
(Id
).Sfile
);
265 Get_Name_String
(ALIs
.Table
(Id
).Sfile
);
266 Name_Len
:= Name_Len
+ 13;
268 Get_Name_String
(FS
);
271 Max_Src_Length
:= Integer'Max (Max_Src_Length
, Name_Len
+ 1);
275 Get_Name_String
(ALIs
.Table
(Id
).Ofile_Full_Name
);
276 Max_Obj_Length
:= Integer'Max (Max_Obj_Length
, Name_Len
+ 1);
281 -- Verify is output is not wider than maximum number of columns
283 Too_Long
:= Verbose_Mode
or else
284 (Max_Unit_Length
+ Max_Src_Length
+ Max_Obj_Length
) > Max_Column
;
286 -- Set start and end of columns.
289 Object_End
:= Object_Start
- 1;
292 Object_End
:= Object_Start
+ Max_Obj_Length
;
295 Unit_Start
:= Object_End
+ 1;
296 Unit_End
:= Unit_Start
- 1;
299 Unit_End
:= Unit_Start
+ Max_Unit_Length
;
302 Source_Start
:= Unit_End
+ 1;
304 if Source_Start
> Spaces
'Last then
305 Source_Start
:= Spaces
'Last;
308 Source_End
:= Source_Start
- 1;
311 Source_End
:= Source_Start
+ Max_Src_Length
;
313 end Find_General_Layout
;
319 procedure Find_Status
320 (FS
: in out File_Name_Type
;
321 Stamp
: Time_Stamp_Type
;
323 Status
: out File_Status
)
325 Tmp1
: File_Name_Type
;
326 Tmp2
: File_Name_Type
;
329 Tmp1
:= Full_Source_Name
(FS
);
331 if Tmp1
= No_File
then
334 elsif File_Stamp
(Tmp1
) = Stamp
then
338 elsif Checksums_Match
(Get_File_Checksum
(FS
), Checksum
) then
340 Status
:= Checksum_OK
;
343 Tmp2
:= Matching_Full_Source_Name
(FS
, Stamp
);
345 if Tmp2
= No_File
then
350 Status
:= Not_First_On_PATH
;
360 procedure Output_Object
(O
: File_Name_Type
) is
361 Object_Name
: String_Access
;
366 Object_Name
:= To_Host_File_Spec
(Name_Buffer
(1 .. Name_Len
));
367 Write_Str
(Object_Name
.all);
369 if Print_Source
or else Print_Unit
then
375 (Object_Start
+ Object_Name
'Length .. Object_End
));
385 procedure Output_Source
(Sdep_I
: Sdep_Id
) is
386 Stamp
: constant Time_Stamp_Type
:= Sdep
.Table
(Sdep_I
).Stamp
;
387 Checksum
: constant Word
:= Sdep
.Table
(Sdep_I
).Checksum
;
388 FS
: File_Name_Type
:= Sdep
.Table
(Sdep_I
).Sfile
;
389 Status
: File_Status
;
390 Object_Name
: String_Access
;
394 Find_Status
(FS
, Stamp
, Checksum
, Status
);
395 Get_Name_String
(FS
);
397 Object_Name
:= To_Host_File_Spec
(Name_Buffer
(1 .. Name_Len
));
400 Write_Str
(" Source => ");
401 Write_Str
(Object_Name
.all);
405 (Spaces
(Source_Start
+ Object_Name
'Length .. Source_End
));
408 Output_Status
(Status
, Verbose
=> True);
413 if not Selective_Output
then
414 Output_Status
(Status
, Verbose
=> False);
417 Write_Str
(Object_Name
.all);
426 procedure Output_Status
(FS
: File_Status
; Verbose
: Boolean) is
431 Write_Str
(" unchanged");
434 Write_Str
(" slightly modified");
437 Write_Str
(" file not found");
440 Write_Str
(" modified");
442 when Not_First_On_PATH
=>
443 Write_Str
(" unchanged version not first on PATH");
460 when Not_First_On_PATH
=>
470 procedure Output_Unit
(U_Id
: Unit_Id
) is
472 U
: Unit_Record
renames Units
.Table
(U_Id
);
476 Get_Name_String
(U
.Uname
);
477 Kind
:= Name_Buffer
(Name_Len
);
478 Name_Len
:= Name_Len
- 2;
480 if not Verbose_Mode
then
481 Write_Str
(Name_Buffer
(1 .. Name_Len
));
484 Write_Str
("Unit => ");
485 Write_Eol
; Write_Str
(" Name => ");
486 Write_Str
(Name_Buffer
(1 .. Name_Len
));
487 Write_Eol
; Write_Str
(" Kind => ");
489 if Units
.Table
(U_Id
).Unit_Kind
= 'p' then
490 Write_Str
("package ");
492 Write_Str
("subprogram ");
512 Write_Eol
; Write_Str
(" Flags =>");
515 Write_Str
(" Preelaborable");
519 Write_Str
(" No_Elab_Code");
526 if U
.Elaborate_Body
then
527 Write_Str
(" Elaborate Body");
530 if U
.Remote_Types
then
531 Write_Str
(" Remote_Types");
534 if U
.Shared_Passive
then
535 Write_Str
(" Shared_Passive");
539 Write_Str
(" Predefined");
543 Write_Str
(" Remote_Call_Interface");
550 Write_Eol
; Write_Str
(" ");
552 Write_Str
(Spaces
(Unit_Start
+ Name_Len
+ 1 .. Unit_End
));
562 procedure Reset_Print
is
564 if not Selective_Output
then
565 Selective_Output
:= True;
566 Print_Source
:= False;
567 Print_Object
:= False;
576 procedure Scan_Ls_Arg
(Argv
: String; And_Save
: Boolean) is
578 pragma Assert
(Argv
'First = 1);
580 if Argv
'Length = 0 then
584 if Argv
(1) = '-' then
586 if Argv
'Length = 1 then
587 Fail
("switch character cannot be followed by a blank");
589 -- Processing for -I-
591 elsif Argv
(2 .. Argv
'Last) = "I-" then
592 Opt
.Look_In_Primary_Dir
:= False;
594 -- Forbid -?- or -??- where ? is any character
596 elsif (Argv
'Length = 3 and then Argv
(3) = '-')
597 or else (Argv
'Length = 4 and then Argv
(4) = '-')
599 Fail
("Trailing ""-"" at the end of ", Argv
, " forbidden.");
601 -- Processing for -Idir
603 elsif Argv
(2) = 'I' then
604 Add_Source_Dir
(Argv
(3 .. Argv
'Last), And_Save
);
605 Add_Lib_Dir
(Argv
(3 .. Argv
'Last), And_Save
);
607 -- Processing for -aIdir (to gcc this is like a -I switch)
609 elsif Argv
'Length >= 3 and then Argv
(2 .. 3) = "aI" then
610 Add_Source_Dir
(Argv
(4 .. Argv
'Last), And_Save
);
612 -- Processing for -aOdir
614 elsif Argv
'Length >= 3 and then Argv
(2 .. 3) = "aO" then
615 Add_Lib_Dir
(Argv
(4 .. Argv
'Last), And_Save
);
617 -- Processing for -aLdir (to gnatbind this is like a -aO switch)
619 elsif Argv
'Length >= 3 and then Argv
(2 .. 3) = "aL" then
620 Add_Lib_Dir
(Argv
(4 .. Argv
'Last), And_Save
);
622 -- Processing for -nostdinc
624 elsif Argv
(2 .. Argv
'Last) = "nostdinc" then
625 Opt
.No_Stdinc
:= True;
627 -- Processing for one character switches
629 elsif Argv
'Length = 2 then
631 when 'a' => Also_Predef
:= True;
632 when 'h' => Print_Usage
:= True;
633 when 'u' => Reset_Print
; Print_Unit
:= True;
634 when 's' => Reset_Print
; Print_Source
:= True;
635 when 'o' => Reset_Print
; Print_Object
:= True;
636 when 'v' => Verbose_Mode
:= True;
637 when 'd' => Dependable
:= True;
642 -- Processing for --RTS=path
644 elsif Argv
(1 .. 5) = "--RTS" then
646 if Argv
(6) /= '=' or else
648 and then Argv
'Length = 6)
650 Osint
.Fail
("missing path for --RTS");
653 -- Valid --RTS switch
655 Opt
.No_Stdinc
:= True;
656 Opt
.RTS_Switch
:= True;
659 Src_Path_Name
: String_Ptr
:=
662 (Argv
(7 .. Argv
'Last), Include
));
663 Lib_Path_Name
: String_Ptr
:=
666 (Argv
(7 .. Argv
'Last), Objects
));
669 if Src_Path_Name
/= null
670 and then Lib_Path_Name
/= null
672 Add_Search_Dirs
(Src_Path_Name
, Include
);
673 Add_Search_Dirs
(Lib_Path_Name
, Objects
);
675 elsif Src_Path_Name
= null
676 and then Lib_Path_Name
= null
678 Osint
.Fail
("RTS path not valid: missing " &
679 "adainclude and adalib directories");
681 elsif Src_Path_Name
= null then
682 Osint
.Fail
("RTS path not valid: missing " &
683 "adainclude directory");
685 elsif Lib_Path_Name
= null then
686 Osint
.Fail
("RTS path not valid: missing " &
693 -- If not a switch, it must be a file name
706 -- Start of processing for Usage
711 Write_Str
("Usage: ");
712 Osint
.Write_Program_Name
;
713 Write_Str
(" switches [list of object files]");
719 Write_Str
("switches:");
724 Write_Str
(" -a also output relevant predefined units");
729 Write_Str
(" -u output only relevant unit names");
734 Write_Str
(" -h output this help message");
739 Write_Str
(" -s output only relevant source names");
744 Write_Str
(" -o output only relevant object names");
749 Write_Str
(" -d output sources on which specified units depend");
754 Write_Str
(" -v verbose output, full path and unit information");
758 -- Line for -aI switch
760 Write_Str
(" -aIdir specify source files search path");
763 -- Line for -aO switch
765 Write_Str
(" -aOdir specify object files search path");
768 -- Line for -I switch
770 Write_Str
(" -Idir like -aIdir -aOdir");
773 -- Line for -I- switch
775 Write_Str
(" -I- do not look for sources & object files");
776 Write_Str
(" in the default directory");
779 -- Line for -nostdinc
781 Write_Str
(" -nostdinc do not look for source files");
782 Write_Str
(" in the system default directory");
787 Write_Str
(" --RTS=dir specify the default source and object search"
791 -- File Status explanation
794 Write_Str
(" file status can be:");
797 for ST
in File_Status
loop
799 Output_Status
(ST
, Verbose
=> False);
801 Output_Status
(ST
, Verbose
=> True);
807 -- Start of processing for Gnatls
811 -- Use low level argument routines to avoid dragging in the secondary stack
815 Scan_Args
: while Next_Arg
< Arg_Count
loop
817 Next_Argv
: String (1 .. Len_Arg
(Next_Arg
));
820 Fill_Arg
(Next_Argv
'Address, Next_Arg
);
821 Scan_Ls_Arg
(Next_Argv
, And_Save
=> True);
824 Next_Arg
:= Next_Arg
+ 1;
827 -- Add the source and object directories specified on the
828 -- command line, if any, to the searched directories.
830 while First_Source_Dir
/= null loop
831 Add_Src_Search_Dir
(First_Source_Dir
.Value
.all);
832 First_Source_Dir
:= First_Source_Dir
.Next
;
835 while First_Lib_Dir
/= null loop
836 Add_Lib_Search_Dir
(First_Lib_Dir
.Value
.all);
837 First_Lib_Dir
:= First_Lib_Dir
.Next
;
840 -- Finally, add the default directories and obtain target parameters
842 Osint
.Add_Default_Search_Dirs
;
846 Targparm
.Get_Target_Parameters
;
848 -- WARNING: the output of gnatls -v is used during the compilation
849 -- and installation of GLADE to recreate sdefault.adb and locate
850 -- the libgnat.a to use. Any change in the output of gnatls -v must
851 -- be synchronized with the GLADE Dist/config.sdefault shell script.
854 Write_Str
("GNATLS ");
856 if Targparm
.High_Integrity_Mode_On_Target
then
857 Write_Str
("Pro High Integrity ");
860 Write_Str
(Gnat_Version_String
);
861 Write_Str
(" Copyright 1997-2002 Free Software Foundation, Inc.");
864 Write_Str
("Source Search Path:");
867 for J
in 1 .. Nb_Dir_In_Src_Search_Path
loop
870 if Dir_In_Src_Search_Path
(J
)'Length = 0 then
871 Write_Str
("<Current_Directory>");
873 Write_Str
(To_Host_Dir_Spec
874 (Dir_In_Src_Search_Path
(J
).all, True).all);
882 Write_Str
("Object Search Path:");
885 for J
in 1 .. Nb_Dir_In_Obj_Search_Path
loop
888 if Dir_In_Obj_Search_Path
(J
)'Length = 0 then
889 Write_Str
("<Current_Directory>");
891 Write_Str
(To_Host_Dir_Spec
892 (Dir_In_Obj_Search_Path
(J
).all, True).all);
901 -- Output usage information when requested
907 if not More_Lib_Files
then
908 if not Print_Usage
and then not Verbose_Mode
then
912 Exit_Program
(E_Fatal
);
917 Initialize_ALI_Source
;
919 -- Print out all library for which no ALI files can be located
921 while More_Lib_Files
loop
922 Main_File
:= Next_Main_Lib_File
;
923 Ali_File
:= Full_Lib_File_Name
(Lib_File_Name
(Main_File
));
925 if Ali_File
= No_File
then
926 Write_Str
("Can't find library info for ");
927 Get_Decoded_Name_String
(Main_File
);
929 Write_Str
(Name_Buffer
(1 .. Name_Len
));
934 Ali_File
:= Strip_Directory
(Ali_File
);
936 if Get_Name_Table_Info
(Ali_File
) = 0 then
937 Text
:= Read_Library_Info
(Ali_File
, True);
940 (Ali_File
, Text
, Ignore_ED
=> False, Err
=> False);
947 for Id
in ALIs
.First
.. ALIs
.Last
loop
952 Get_Name_String
(Units
.Table
(ALIs
.Table
(Id
).First_Unit
).Uname
);
954 if Also_Predef
or else not Is_Internal_Unit
then
955 Output_Object
(ALIs
.Table
(Id
).Ofile_Full_Name
);
957 -- In verbose mode print all main units in the ALI file, otherwise
958 -- just print the first one to ease columnwise printout
961 Last_U
:= ALIs
.Table
(Id
).Last_Unit
;
963 Last_U
:= ALIs
.Table
(Id
).First_Unit
;
966 for U
in ALIs
.Table
(Id
).First_Unit
.. Last_U
loop
967 if U
/= ALIs
.Table
(Id
).First_Unit
968 and then Selective_Output
976 -- Output source now, unless if it will be done as part of
977 -- outputing dependencies.
979 if not (Dependable
and then Print_Source
) then
980 Output_Source
(Corresponding_Sdep_Entry
(Id
, U
));
984 -- Print out list of dependable units
986 if Dependable
and then Print_Source
then
988 Write_Str
("depends upon");
997 ALIs
.Table
(Id
).First_Sdep
.. ALIs
.Table
(Id
).Last_Sdep
1000 or else not Is_Internal_File_Name
(Sdep
.Table
(D
).Sfile
)
1002 if Verbose_Mode
then
1012 Write_Str
(Spaces
(1 .. Source_Start
- 2));
1025 -- All done. Set proper exit status.
1028 Exit_Program
(E_Success
);