1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 1992-2005 Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 2, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, USA. --
22 -- GNAT was originally developed by the GNAT team at New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc. --
25 ------------------------------------------------------------------------------
27 with Debug
; use Debug
;
28 with Binderr
; use Binderr
;
30 with Namet
; use Namet
;
32 with Output
; use Output
;
33 with Osint
; use Osint
;
34 with Scans
; use Scans
;
37 with Snames
; use Snames
;
40 package body ALI
.Util
is
42 -- Empty procedures needed to instantiate Scng. Error procedures are
43 -- empty, because we don't want to report any errors when computing
48 procedure Error_Msg
(Msg
: String; Flag_Location
: Source_Ptr
);
50 procedure Error_Msg_S
(Msg
: String);
52 procedure Error_Msg_SC
(Msg
: String);
54 procedure Error_Msg_SP
(Msg
: String);
56 procedure Obsolescent_Check
(S
: Source_Ptr
);
58 -- Instantiation of Styleg, needed to instantiate Scng
60 package Style
is new Styleg
61 (Error_Msg
, Error_Msg_S
, Error_Msg_SC
, Error_Msg_SP
);
63 -- A Scanner is needed to get checksum of a source (procedure
64 -- Get_File_Checksum).
66 package Scanner
is new Scng
67 (Post_Scan
, Error_Msg
, Error_Msg_S
, Error_Msg_SC
, Error_Msg_SP
,
68 Obsolescent_Check
, Style
);
70 type Header_Num
is range 0 .. 1_000
;
72 function Hash
(F
: File_Name_Type
) return Header_Num
;
73 -- Function used to compute hash of ALI file name
75 package Interfaces
is new Simple_HTable
(
76 Header_Num
=> Header_Num
,
79 Key
=> File_Name_Type
,
87 function Checksums_Match
(Checksum1
, Checksum2
: Word
) return Boolean is
89 return Checksum1
= Checksum2
and then Checksum1
/= Checksum_Error
;
96 procedure Error_Msg
(Msg
: String; Flag_Location
: Source_Ptr
) is
97 pragma Warnings
(Off
, Msg
);
98 pragma Warnings
(Off
, Flag_Location
);
107 procedure Error_Msg_S
(Msg
: String) is
108 pragma Warnings
(Off
, Msg
);
117 procedure Error_Msg_SC
(Msg
: String) is
118 pragma Warnings
(Off
, Msg
);
127 procedure Error_Msg_SP
(Msg
: String) is
128 pragma Warnings
(Off
, Msg
);
133 -----------------------
134 -- Get_File_Checksum --
135 -----------------------
137 function Get_File_Checksum
(Fname
: Name_Id
) return Word
is
139 Source_Index
: Source_File_Index
;
141 Full_Name
:= Find_File
(Fname
, Osint
.Source
);
143 -- If we cannot find the file, then return an impossible checksum,
144 -- impossible becaues checksums have the high order bit zero, so
145 -- that checksums do not match.
147 if Full_Name
= No_File
then
148 return Checksum_Error
;
151 Source_Index
:= Sinput
.C
.Load_File
(Get_Name_String
(Full_Name
));
153 if Source_Index
= No_Source_File
then
154 return Checksum_Error
;
157 Scanner
.Initialize_Scanner
(Types
.No_Unit
, Source_Index
);
159 -- Make sure that the project language reserved words are not
160 -- recognized as reserved words, but as identifiers. The byte info for
161 -- those names have been set if we are in gnatmake.
163 Set_Name_Table_Byte
(Name_Project
, 0);
164 Set_Name_Table_Byte
(Name_Extends
, 0);
165 Set_Name_Table_Byte
(Name_External
, 0);
167 -- Scan the complete file to compute its checksum
171 exit when Token
= Tok_EOF
;
174 return Scans
.Checksum
;
175 end Get_File_Checksum
;
181 function Hash
(F
: File_Name_Type
) return Header_Num
is
183 return Header_Num
(Int
(F
) rem Header_Num
'Range_Length);
186 ---------------------------
187 -- Initialize_ALI_Source --
188 ---------------------------
190 procedure Initialize_ALI_Source
is
192 -- When (re)initializing ALI data structures the ALI user expects to
193 -- get a fresh set of data structures. Thus we first need to erase the
194 -- marks put in the name table by the previous set of ALI routine calls.
195 -- This loop is empty and harmless the first time in.
197 for J
in Source
.First
.. Source
.Last
loop
198 Set_Name_Table_Info
(Source
.Table
(J
).Sfile
, 0);
199 Source
.Table
(J
).Source_Found
:= False;
204 end Initialize_ALI_Source
;
206 -----------------------
207 -- Obsolescent_Check --
208 -----------------------
210 procedure Obsolescent_Check
(S
: Source_Ptr
) is
211 pragma Warnings
(Off
, S
);
214 end Obsolescent_Check
;
220 procedure Post_Scan
is
229 procedure Read_ALI
(Id
: ALI_Id
) is
230 Afile
: File_Name_Type
;
231 Text
: Text_Buffer_Ptr
;
235 -- Process all dependent units
237 for U
in ALIs
.Table
(Id
).First_Unit
.. ALIs
.Table
(Id
).Last_Unit
loop
239 W
in Units
.Table
(U
).First_With
.. Units
.Table
(U
).Last_With
241 Afile
:= Withs
.Table
(W
).Afile
;
243 -- Only process if not a generic (Afile /= No_File) and if
244 -- file has not been processed already.
247 and then Get_Name_Table_Info
(Afile
) = 0
249 Text
:= Read_Library_Info
(Afile
);
251 -- Return with an error if source cannot be found and if this
252 -- is not a library generic (now we can, but does not have to
253 -- compile library generics)
256 if Generic_Separately_Compiled
(Withs
.Table
(W
).Sfile
) then
257 Error_Msg_Name_1
:= Afile
;
258 Error_Msg_Name_2
:= Withs
.Table
(W
).Sfile
;
259 Error_Msg
("% not found, % must be compiled");
260 Set_Name_Table_Info
(Afile
, Int
(No_Unit_Id
));
264 goto Skip_Library_Generics
;
268 -- Enter in ALIs table
274 Ignore_ED
=> Force_RM_Elaboration_Order
,
279 if ALIs
.Table
(Idread
).Compile_Errors
then
280 Error_Msg_Name_1
:= Withs
.Table
(W
).Sfile
;
281 Error_Msg
("% had errors, must be fixed, and recompiled");
282 Set_Name_Table_Info
(Afile
, Int
(No_Unit_Id
));
284 elsif ALIs
.Table
(Idread
).No_Object
then
285 Error_Msg_Name_1
:= Withs
.Table
(W
).Sfile
;
286 Error_Msg
("% must be recompiled");
287 Set_Name_Table_Info
(Afile
, Int
(No_Unit_Id
));
290 -- If the Unit is an Interface to a Stand-Alone Library,
291 -- set the Interface flag in the Withs table, so that its
292 -- dependant are not considered for elaboration order.
294 if ALIs
.Table
(Idread
).SAL_Interface
then
295 Withs
.Table
(W
).SAL_Interface
:= True;
296 Interface_Library_Unit
:= True;
298 -- Set the entry in the Interfaces hash table, so that other
299 -- units that import this unit will set the flag in their
300 -- entry in the Withs table.
302 Interfaces
.Set
(Afile
, True);
305 -- Otherwise, recurse to get new dependents
310 <<Skip_Library_Generics
>> null;
312 -- If the ALI file has already been processed and is an interface,
313 -- set the flag in the entry of the Withs table.
315 elsif Interface_Library_Unit
and then Interfaces
.Get
(Afile
) then
316 Withs
.Table
(W
).SAL_Interface
:= True;
322 ----------------------
323 -- Set_Source_Table --
324 ----------------------
326 procedure Set_Source_Table
(A
: ALI_Id
) is
329 Stamp
: Time_Stamp_Type
;
333 ALIs
.Table
(A
).First_Sdep
.. ALIs
.Table
(A
).Last_Sdep
335 F
:= Sdep
.Table
(D
).Sfile
;
339 -- If this is the first time we are seeing this source file,
340 -- then make a new entry in the source table.
342 if Get_Name_Table_Info
(F
) = 0 then
343 Source
.Increment_Last
;
345 Set_Name_Table_Info
(F
, Int
(S
));
346 Source
.Table
(S
).Sfile
:= F
;
347 Source
.Table
(S
).All_Timestamps_Match
:= True;
349 -- Initialize checksum fields
351 Source
.Table
(S
).Checksum
:= Sdep
.Table
(D
).Checksum
;
352 Source
.Table
(S
).All_Checksums_Match
:= True;
354 -- In check source files mode, try to get time stamp from file
356 if Opt
.Check_Source_Files
then
357 Stamp
:= Source_File_Stamp
(F
);
359 -- If we got the stamp, then set the stamp in the source
360 -- table entry and mark it as set from the source so that
361 -- it does not get subsequently changed.
363 if Stamp
(Stamp
'First) /= ' ' then
364 Source
.Table
(S
).Stamp
:= Stamp
;
365 Source
.Table
(S
).Source_Found
:= True;
367 -- If we could not find the file, then the stamp is set
368 -- from the dependency table entry (to be possibly reset
369 -- if we find a later stamp in subsequent processing)
372 Source
.Table
(S
).Stamp
:= Sdep
.Table
(D
).Stamp
;
373 Source
.Table
(S
).Source_Found
:= False;
375 -- In All_Sources mode, flag error of file not found
377 if Opt
.All_Sources
then
378 Error_Msg_Name_1
:= F
;
379 Error_Msg
("cannot locate %");
383 -- First time for this source file, but Check_Source_Files
384 -- is off, so simply initialize the stamp from the Sdep entry
387 Source
.Table
(S
).Source_Found
:= False;
388 Source
.Table
(S
).Stamp
:= Sdep
.Table
(D
).Stamp
;
391 -- Here if this is not the first time for this source file,
392 -- so that the source table entry is already constructed.
395 S
:= Source_Id
(Get_Name_Table_Info
(F
));
397 -- Update checksum flag
399 if not Checksums_Match
400 (Sdep
.Table
(D
).Checksum
, Source
.Table
(S
).Checksum
)
402 Source
.Table
(S
).All_Checksums_Match
:= False;
405 -- Check for time stamp mismatch
407 if Sdep
.Table
(D
).Stamp
/= Source
.Table
(S
).Stamp
then
408 Source
.Table
(S
).All_Timestamps_Match
:= False;
410 -- When we have a time stamp mismatch, we go look for the
411 -- source file even if Check_Source_Files is false, since
412 -- if we find it, then we can use it to resolve which of the
413 -- two timestamps in the ALI files is likely to be correct.
415 if not Check_Source_Files
then
416 Stamp
:= Source_File_Stamp
(F
);
418 if Stamp
(Stamp
'First) /= ' ' then
419 Source
.Table
(S
).Stamp
:= Stamp
;
420 Source
.Table
(S
).Source_Found
:= True;
424 -- If the stamp in the source table entry was set from the
425 -- source file, then we do not change it (the stamp in the
426 -- source file is always taken as the "right" one).
428 if Source
.Table
(S
).Source_Found
then
431 -- Otherwise, we have no source file available, so we guess
432 -- that the later of the two timestamps is the right one.
433 -- Note that this guess only affects which error messages
434 -- are issued later on, not correct functionality.
437 if Sdep
.Table
(D
).Stamp
> Source
.Table
(S
).Stamp
then
438 Source
.Table
(S
).Stamp
:= Sdep
.Table
(D
).Stamp
;
444 -- Set the checksum value in the source table
446 S
:= Source_Id
(Get_Name_Table_Info
(F
));
447 Source
.Table
(S
).Checksum
:= Sdep
.Table
(D
).Checksum
;
451 end Set_Source_Table
;
453 ----------------------
454 -- Set_Source_Table --
455 ----------------------
457 procedure Set_Source_Table
is
459 for A
in ALIs
.First
.. ALIs
.Last
loop
460 Set_Source_Table
(A
);
462 end Set_Source_Table
;
464 -------------------------
465 -- Time_Stamp_Mismatch --
466 -------------------------
468 function Time_Stamp_Mismatch
470 Read_Only
: Boolean := False)
471 return File_Name_Type
474 -- Source file Id for the current Sdep entry
477 for D
in ALIs
.Table
(A
).First_Sdep
.. ALIs
.Table
(A
).Last_Sdep
loop
478 Src
:= Source_Id
(Get_Name_Table_Info
(Sdep
.Table
(D
).Sfile
));
480 if Opt
.Minimal_Recompilation
481 and then Sdep
.Table
(D
).Stamp
/= Source
.Table
(Src
).Stamp
483 -- If minimal recompilation is in action, replace the stamp
484 -- of the source file in the table if checksums match.
486 -- ??? It is probably worth updating the ALI file with a new
487 -- field to avoid recomputing it each time.
490 (Get_File_Checksum
(Sdep
.Table
(D
).Sfile
),
491 Source
.Table
(Src
).Checksum
)
493 Sdep
.Table
(D
).Stamp
:= Source
.Table
(Src
).Stamp
;
498 if (not Read_Only
) or else Source
.Table
(Src
).Source_Found
then
499 if not Source
.Table
(Src
).Source_Found
500 or else Sdep
.Table
(D
).Stamp
/= Source
.Table
(Src
).Stamp
502 -- If -t debug flag set, output time stamp found/expected
504 if Source
.Table
(Src
).Source_Found
and Debug_Flag_T
then
505 Write_Str
("Source: """);
506 Get_Name_String
(Sdep
.Table
(D
).Sfile
);
507 Write_Str
(Name_Buffer
(1 .. Name_Len
));
510 Write_Str
(" time stamp expected: ");
511 Write_Line
(String (Sdep
.Table
(D
).Stamp
));
513 Write_Str
(" time stamp found: ");
514 Write_Line
(String (Source
.Table
(Src
).Stamp
));
517 -- Return the source file
519 return Source
.Table
(Src
).Sfile
;
525 end Time_Stamp_Mismatch
;