OSDN Git Service

2012-01-30 Robert Dewar <dewar@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / prj.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                                  P R J                                   --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 2001-2012, Free Software Foundation, Inc.         --
10 --                                                                          --
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 3,  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 COPYING3.  If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license.          --
20 --                                                                          --
21 -- GNAT was originally developed  by the GNAT team at  New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
23 --                                                                          --
24 ------------------------------------------------------------------------------
25
26 with Debug;
27 with Opt;
28 with Osint;    use Osint;
29 with Output;   use Output;
30 with Prj.Attr;
31 with Prj.Com;
32 with Prj.Err;  use Prj.Err;
33 with Snames;   use Snames;
34 with Uintp;    use Uintp;
35
36 with Ada.Characters.Handling;    use Ada.Characters.Handling;
37 with Ada.Containers.Ordered_Sets;
38 with Ada.Unchecked_Deallocation;
39
40 with GNAT.Case_Util;            use GNAT.Case_Util;
41 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
42 with GNAT.HTable;
43
44 package body Prj is
45
46    type Restricted_Lang;
47    type Restricted_Lang_Access is access Restricted_Lang;
48    type Restricted_Lang is record
49       Name : Name_Id;
50       Next : Restricted_Lang_Access;
51    end record;
52
53    Restricted_Languages : Restricted_Lang_Access := null;
54    --  When null, all languages are allowed, otherwise only the languages in
55    --  the list are allowed.
56
57    Object_Suffix : constant String := Get_Target_Object_Suffix.all;
58    --  File suffix for object files
59
60    Initial_Buffer_Size : constant := 100;
61    --  Initial size for extensible buffer used in Add_To_Buffer
62
63    The_Empty_String : Name_Id := No_Name;
64
65    Debug_Level : Integer := 0;
66    --  Current indentation level for debug traces
67
68    type Cst_String_Access is access constant String;
69
70    All_Lower_Case_Image : aliased constant String := "lowercase";
71    All_Upper_Case_Image : aliased constant String := "UPPERCASE";
72    Mixed_Case_Image     : aliased constant String := "MixedCase";
73
74    The_Casing_Images : constant array (Known_Casing) of Cst_String_Access :=
75                          (All_Lower_Case => All_Lower_Case_Image'Access,
76                           All_Upper_Case => All_Upper_Case_Image'Access,
77                           Mixed_Case     => Mixed_Case_Image'Access);
78
79    procedure Free (Project : in out Project_Id);
80    --  Free memory allocated for Project
81
82    procedure Free_List (Languages : in out Language_Ptr);
83    procedure Free_List (Source : in out Source_Id);
84    procedure Free_List (Languages : in out Language_List);
85    --  Free memory allocated for the list of languages or sources
86
87    procedure Reset_Units_In_Table (Table : in out Units_Htable.Instance);
88    --  Resets all Units to No_Unit_Index Unit.File_Names (Spec).Unit &
89    --  Unit.File_Names (Impl).Unit in the given table.
90
91    procedure Free_Units (Table : in out Units_Htable.Instance);
92    --  Free memory allocated for unit information in the project
93
94    procedure Language_Changed (Iter : in out Source_Iterator);
95    procedure Project_Changed (Iter : in out Source_Iterator);
96    --  Called when a new project or language was selected for this iterator
97
98    function Contains_ALI_Files (Dir : Path_Name_Type) return Boolean;
99    --  Return True if there is at least one ALI file in the directory Dir
100
101    -----------------------------
102    -- Add_Restricted_Language --
103    -----------------------------
104
105    procedure Add_Restricted_Language (Name : String) is
106       N : String (1 .. Name'Length) := Name;
107    begin
108       To_Lower (N);
109       Name_Len := 0;
110       Add_Str_To_Name_Buffer (N);
111       Restricted_Languages :=
112         new Restricted_Lang'(Name => Name_Find, Next => Restricted_Languages);
113    end Add_Restricted_Language;
114
115    -------------------
116    -- Add_To_Buffer --
117    -------------------
118
119    procedure Add_To_Buffer
120      (S    : String;
121       To   : in out String_Access;
122       Last : in out Natural)
123    is
124    begin
125       if To = null then
126          To := new String (1 .. Initial_Buffer_Size);
127          Last := 0;
128       end if;
129
130       --  If Buffer is too small, double its size
131
132       while Last + S'Length > To'Last loop
133          declare
134             New_Buffer : constant  String_Access :=
135                            new String (1 .. 2 * Last);
136
137          begin
138             New_Buffer (1 .. Last) := To (1 .. Last);
139             Free (To);
140             To := New_Buffer;
141          end;
142       end loop;
143
144       To (Last + 1 .. Last + S'Length) := S;
145       Last := Last + S'Length;
146    end Add_To_Buffer;
147
148    ---------------------------------
149    -- Current_Object_Path_File_Of --
150    ---------------------------------
151
152    function Current_Object_Path_File_Of
153      (Shared : Shared_Project_Tree_Data_Access) return Path_Name_Type
154    is
155    begin
156       return Shared.Private_Part.Current_Object_Path_File;
157    end Current_Object_Path_File_Of;
158
159    ---------------------------------
160    -- Current_Source_Path_File_Of --
161    ---------------------------------
162
163    function Current_Source_Path_File_Of
164      (Shared : Shared_Project_Tree_Data_Access)
165       return Path_Name_Type is
166    begin
167       return Shared.Private_Part.Current_Source_Path_File;
168    end Current_Source_Path_File_Of;
169
170    ---------------------------
171    -- Delete_Temporary_File --
172    ---------------------------
173
174    procedure Delete_Temporary_File
175      (Shared : Shared_Project_Tree_Data_Access := null;
176       Path   : Path_Name_Type)
177    is
178       Dont_Care : Boolean;
179       pragma Warnings (Off, Dont_Care);
180
181    begin
182       if not Debug.Debug_Flag_N then
183          if Current_Verbosity = High then
184             Write_Line ("Removing temp file: " & Get_Name_String (Path));
185          end if;
186
187          Delete_File (Get_Name_String (Path), Dont_Care);
188
189          if Shared /= null then
190             for Index in
191               1 .. Temp_Files_Table.Last (Shared.Private_Part.Temp_Files)
192             loop
193                if Shared.Private_Part.Temp_Files.Table (Index) = Path then
194                   Shared.Private_Part.Temp_Files.Table (Index) := No_Path;
195                end if;
196             end loop;
197          end if;
198       end if;
199    end Delete_Temporary_File;
200
201    ------------------------------
202    -- Delete_Temp_Config_Files --
203    ------------------------------
204
205    procedure Delete_Temp_Config_Files (Project_Tree : Project_Tree_Ref) is
206       Success : Boolean;
207       pragma Warnings (Off, Success);
208
209       Proj : Project_List;
210
211    begin
212       if not Debug.Debug_Flag_N then
213          if Project_Tree /= null then
214             Proj := Project_Tree.Projects;
215             while Proj /= null loop
216                if Proj.Project.Config_File_Temp then
217                   Delete_Temporary_File
218                     (Project_Tree.Shared, Proj.Project.Config_File_Name);
219
220                   --  Make sure that we don't have a config file for this
221                   --  project, in case there are several mains. In this case,
222                   --  we will recreate another config file: we cannot reuse the
223                   --  one that we just deleted!
224
225                   Proj.Project.Config_Checked   := False;
226                   Proj.Project.Config_File_Name := No_Path;
227                   Proj.Project.Config_File_Temp := False;
228                end if;
229
230                Proj := Proj.Next;
231             end loop;
232          end if;
233       end if;
234    end Delete_Temp_Config_Files;
235
236    ---------------------------
237    -- Delete_All_Temp_Files --
238    ---------------------------
239
240    procedure Delete_All_Temp_Files
241      (Shared : Shared_Project_Tree_Data_Access)
242    is
243       Dont_Care : Boolean;
244       pragma Warnings (Off, Dont_Care);
245
246       Path : Path_Name_Type;
247
248    begin
249       if not Debug.Debug_Flag_N then
250          for Index in
251            1 .. Temp_Files_Table.Last (Shared.Private_Part.Temp_Files)
252          loop
253             Path := Shared.Private_Part.Temp_Files.Table (Index);
254
255             if Path /= No_Path then
256                if Current_Verbosity = High then
257                   Write_Line ("Removing temp file: "
258                               & Get_Name_String (Path));
259                end if;
260
261                Delete_File (Get_Name_String (Path), Dont_Care);
262             end if;
263          end loop;
264
265          Temp_Files_Table.Free (Shared.Private_Part.Temp_Files);
266          Temp_Files_Table.Init (Shared.Private_Part.Temp_Files);
267       end if;
268
269       --  If any of the environment variables ADA_PRJ_INCLUDE_FILE or
270       --  ADA_PRJ_OBJECTS_FILE has been set, then reset their value to
271       --  the empty string. On VMS, this has the effect of deassigning
272       --  the logical names.
273
274       if Shared.Private_Part.Current_Source_Path_File /= No_Path then
275          Setenv (Project_Include_Path_File, "");
276       end if;
277
278       if Shared.Private_Part.Current_Object_Path_File /= No_Path then
279          Setenv (Project_Objects_Path_File, "");
280       end if;
281    end Delete_All_Temp_Files;
282
283    ---------------------
284    -- Dependency_Name --
285    ---------------------
286
287    function Dependency_Name
288      (Source_File_Name : File_Name_Type;
289       Dependency       : Dependency_File_Kind) return File_Name_Type
290    is
291    begin
292       case Dependency is
293          when None =>
294             return No_File;
295
296          when Makefile =>
297             return Extend_Name (Source_File_Name, Makefile_Dependency_Suffix);
298
299          when ALI_File =>
300             return Extend_Name (Source_File_Name, ALI_Dependency_Suffix);
301       end case;
302    end Dependency_Name;
303
304    ----------------
305    -- Empty_File --
306    ----------------
307
308    function Empty_File return File_Name_Type is
309    begin
310       return File_Name_Type (The_Empty_String);
311    end Empty_File;
312
313    -------------------
314    -- Empty_Project --
315    -------------------
316
317    function Empty_Project
318      (Qualifier : Project_Qualifier) return Project_Data
319    is
320    begin
321       Prj.Initialize (Tree => No_Project_Tree);
322
323       declare
324          Data : Project_Data (Qualifier => Qualifier);
325
326       begin
327          --  Only the fields for which no default value could be provided in
328          --  prj.ads are initialized below.
329
330          Data.Config := Default_Project_Config;
331          return Data;
332       end;
333    end Empty_Project;
334
335    ------------------
336    -- Empty_String --
337    ------------------
338
339    function Empty_String return Name_Id is
340    begin
341       return The_Empty_String;
342    end Empty_String;
343
344    ------------
345    -- Expect --
346    ------------
347
348    procedure Expect (The_Token : Token_Type; Token_Image : String) is
349    begin
350       if Token /= The_Token then
351
352          --  ??? Should pass user flags here instead
353
354          Error_Msg (Gnatmake_Flags, Token_Image & " expected", Token_Ptr);
355       end if;
356    end Expect;
357
358    -----------------
359    -- Extend_Name --
360    -----------------
361
362    function Extend_Name
363      (File        : File_Name_Type;
364       With_Suffix : String) return File_Name_Type
365    is
366       Last : Positive;
367
368    begin
369       Get_Name_String (File);
370       Last := Name_Len + 1;
371
372       while Name_Len /= 0 and then Name_Buffer (Name_Len) /= '.' loop
373          Name_Len := Name_Len - 1;
374       end loop;
375
376       if Name_Len <= 1 then
377          Name_Len := Last;
378       end if;
379
380       for J in With_Suffix'Range loop
381          Name_Buffer (Name_Len) := With_Suffix (J);
382          Name_Len := Name_Len + 1;
383       end loop;
384
385       Name_Len := Name_Len - 1;
386       return Name_Find;
387    end Extend_Name;
388
389    -------------------------
390    -- Is_Allowed_Language --
391    -------------------------
392
393    function Is_Allowed_Language (Name : Name_Id) return Boolean is
394       R    : Restricted_Lang_Access := Restricted_Languages;
395       Lang : constant String := Get_Name_String (Name);
396
397    begin
398       if R = null then
399          return True;
400
401       else
402          while R /= null loop
403             if Get_Name_String (R.Name) = Lang then
404                return True;
405             end if;
406
407             R := R.Next;
408          end loop;
409
410          return False;
411       end if;
412    end Is_Allowed_Language;
413
414    ---------------------
415    -- Project_Changed --
416    ---------------------
417
418    procedure Project_Changed (Iter : in out Source_Iterator) is
419    begin
420       if Iter.Project /= null then
421          Iter.Language := Iter.Project.Project.Languages;
422          Language_Changed (Iter);
423       end if;
424    end Project_Changed;
425
426    ----------------------
427    -- Language_Changed --
428    ----------------------
429
430    procedure Language_Changed (Iter : in out Source_Iterator) is
431    begin
432       Iter.Current := No_Source;
433
434       if Iter.Language_Name /= No_Name then
435          while Iter.Language /= null
436            and then Iter.Language.Name /= Iter.Language_Name
437          loop
438             Iter.Language := Iter.Language.Next;
439          end loop;
440       end if;
441
442       --  If there is no matching language in this project, move to next
443
444       if Iter.Language = No_Language_Index then
445          if Iter.All_Projects then
446             loop
447                Iter.Project := Iter.Project.Next;
448                exit when Iter.Project = null
449                  or else Iter.Encapsulated_Libs
450                  or else not Iter.Project.From_Encapsulated_Lib;
451             end loop;
452
453             Project_Changed (Iter);
454          else
455             Iter.Project := null;
456          end if;
457
458       else
459          Iter.Current := Iter.Language.First_Source;
460
461          if Iter.Current = No_Source then
462             Iter.Language := Iter.Language.Next;
463             Language_Changed (Iter);
464          end if;
465       end if;
466    end Language_Changed;
467
468    ---------------------
469    -- For_Each_Source --
470    ---------------------
471
472    function For_Each_Source
473      (In_Tree           : Project_Tree_Ref;
474       Project           : Project_Id := No_Project;
475       Language          : Name_Id := No_Name;
476       Encapsulated_Libs : Boolean := True) return Source_Iterator
477    is
478       Iter : Source_Iterator;
479    begin
480       Iter := Source_Iterator'
481         (In_Tree           => In_Tree,
482          Project           => In_Tree.Projects,
483          All_Projects      => Project = No_Project,
484          Language_Name     => Language,
485          Language          => No_Language_Index,
486          Current           => No_Source,
487          Encapsulated_Libs => Encapsulated_Libs);
488
489       if Project /= null then
490          while Iter.Project /= null
491            and then Iter.Project.Project /= Project
492          loop
493             Iter.Project := Iter.Project.Next;
494          end loop;
495
496       else
497          while not Iter.Encapsulated_Libs
498            and then Iter.Project.From_Encapsulated_Lib
499          loop
500             Iter.Project := Iter.Project.Next;
501          end loop;
502       end if;
503
504       Project_Changed (Iter);
505
506       return Iter;
507    end For_Each_Source;
508
509    -------------
510    -- Element --
511    -------------
512
513    function Element (Iter : Source_Iterator) return Source_Id is
514    begin
515       return Iter.Current;
516    end Element;
517
518    ----------
519    -- Next --
520    ----------
521
522    procedure Next (Iter : in out Source_Iterator) is
523    begin
524       Iter.Current := Iter.Current.Next_In_Lang;
525       if Iter.Current = No_Source then
526          Iter.Language := Iter.Language.Next;
527          Language_Changed (Iter);
528       end if;
529    end Next;
530
531    --------------------------------
532    -- For_Every_Project_Imported --
533    --------------------------------
534
535    procedure For_Every_Project_Imported_Context
536      (By                 : Project_Id;
537       Tree               : Project_Tree_Ref;
538       With_State         : in out State;
539       Include_Aggregated : Boolean := True;
540       Imported_First     : Boolean := False)
541    is
542       use Project_Boolean_Htable;
543
544       procedure Recursive_Check_Context
545         (Project               : Project_Id;
546          Tree                  : Project_Tree_Ref;
547          In_Aggregate_Lib      : Boolean;
548          From_Encapsulated_Lib : Boolean);
549       --  Recursively handle the project tree creating a new context for
550       --  keeping track about already handled projects.
551
552       -----------------------------
553       -- Recursive_Check_Context --
554       -----------------------------
555
556       procedure Recursive_Check_Context
557         (Project               : Project_Id;
558          Tree                  : Project_Tree_Ref;
559          In_Aggregate_Lib      : Boolean;
560          From_Encapsulated_Lib : Boolean)
561       is
562          package Name_Id_Set is
563            new Ada.Containers.Ordered_Sets (Element_Type => Name_Id);
564
565          Seen_Name : Name_Id_Set.Set;
566          --  This set is needed to ensure that we do not haandle the same
567          --  project twice in the context of aggregate libraries.
568
569          procedure Recursive_Check
570            (Project               : Project_Id;
571             Tree                  : Project_Tree_Ref;
572             In_Aggregate_Lib      : Boolean;
573             From_Encapsulated_Lib : Boolean);
574          --  Check if project has already been seen. If not, mark it as Seen,
575          --  Call Action, and check all its imported and aggregated projects.
576
577          ---------------------
578          -- Recursive_Check --
579          ---------------------
580
581          procedure Recursive_Check
582            (Project               : Project_Id;
583             Tree                  : Project_Tree_Ref;
584             In_Aggregate_Lib      : Boolean;
585             From_Encapsulated_Lib : Boolean)
586          is
587             List : Project_List;
588             T    : Project_Tree_Ref;
589
590          begin
591             if not Seen_Name.Contains (Project.Name) then
592
593                --  Even if a project is aggregated multiple times in an
594                --  aggregated library, we will only return it once.
595
596                Seen_Name.Include (Project.Name);
597
598                if not Imported_First then
599                   Action
600                     (Project,
601                      Tree,
602                      Project_Context'(In_Aggregate_Lib, From_Encapsulated_Lib),
603                      With_State);
604                end if;
605
606                --  Visit all extended projects
607
608                if Project.Extends /= No_Project then
609                   Recursive_Check
610                     (Project.Extends, Tree,
611                      In_Aggregate_Lib, From_Encapsulated_Lib);
612                end if;
613
614                --  Visit all imported projects
615
616                List := Project.Imported_Projects;
617                while List /= null loop
618                   Recursive_Check
619                     (List.Project, Tree,
620                      In_Aggregate_Lib,
621                      From_Encapsulated_Lib
622                        or else Project.Standalone_Library = Encapsulated);
623                   List := List.Next;
624                end loop;
625
626                --  Visit all aggregated projects
627
628                if Include_Aggregated
629                  and then Project.Qualifier in Aggregate_Project
630                then
631                   declare
632                      Agg : Aggregated_Project_List;
633
634                   begin
635                      Agg := Project.Aggregated_Projects;
636                      while Agg /= null loop
637                         pragma Assert (Agg.Project /= No_Project);
638
639                         --  For aggregated libraries, the tree must be the one
640                         --  of the aggregate library.
641
642                         if Project.Qualifier = Aggregate_Library then
643                            T := Tree;
644                            Recursive_Check
645                              (Agg.Project, T,
646                               True,
647                               From_Encapsulated_Lib
648                                 or else
649                                   Project.Standalone_Library = Encapsulated);
650
651                         else
652                            T := Agg.Tree;
653
654                            --  Use a new context as we want to returns the same
655                            --  project in different project tree for aggregated
656                            --  projects.
657
658                            Recursive_Check_Context
659                              (Agg.Project, T, False, False);
660                         end if;
661
662                         Agg := Agg.Next;
663                      end loop;
664                   end;
665                end if;
666
667                if Imported_First then
668                   Action
669                     (Project,
670                      Tree,
671                      Project_Context'(In_Aggregate_Lib, From_Encapsulated_Lib),
672                      With_State);
673                end if;
674             end if;
675          end Recursive_Check;
676
677       --  Start of processing for Recursive_Check_Context
678
679       begin
680          Recursive_Check
681            (Project, Tree, In_Aggregate_Lib, From_Encapsulated_Lib);
682       end Recursive_Check_Context;
683
684    --  Start of processing for For_Every_Project_Imported
685
686    begin
687       Recursive_Check_Context
688         (Project               => By,
689          Tree                  => Tree,
690          In_Aggregate_Lib      => False,
691          From_Encapsulated_Lib => False);
692    end For_Every_Project_Imported_Context;
693
694    procedure For_Every_Project_Imported
695      (By                 : Project_Id;
696       Tree               : Project_Tree_Ref;
697       With_State         : in out State;
698       Include_Aggregated : Boolean := True;
699       Imported_First     : Boolean := False)
700    is
701       procedure Internal
702         (Project    : Project_Id;
703          Tree       : Project_Tree_Ref;
704          Context    : Project_Context;
705          With_State : in out State);
706       --  Action wrapper for handling the context
707
708       --------------
709       -- Internal --
710       --------------
711
712       procedure Internal
713         (Project    : Project_Id;
714          Tree       : Project_Tree_Ref;
715          Context    : Project_Context;
716          With_State : in out State)
717       is
718          pragma Unreferenced (Context);
719       begin
720          Action (Project, Tree, With_State);
721       end Internal;
722
723       procedure For_Projects is
724         new For_Every_Project_Imported_Context (State, Internal);
725
726    begin
727       For_Projects (By, Tree, With_State, Include_Aggregated, Imported_First);
728    end For_Every_Project_Imported;
729
730    -----------------
731    -- Find_Source --
732    -----------------
733
734    function Find_Source
735      (In_Tree          : Project_Tree_Ref;
736       Project          : Project_Id;
737       In_Imported_Only : Boolean := False;
738       In_Extended_Only : Boolean := False;
739       Base_Name        : File_Name_Type;
740       Index            : Int := 0) return Source_Id
741    is
742       Result : Source_Id  := No_Source;
743
744       procedure Look_For_Sources
745         (Proj : Project_Id;
746          Tree : Project_Tree_Ref;
747          Src  : in out Source_Id);
748       --  Look for Base_Name in the sources of Proj
749
750       ----------------------
751       -- Look_For_Sources --
752       ----------------------
753
754       procedure Look_For_Sources
755         (Proj : Project_Id;
756          Tree : Project_Tree_Ref;
757          Src  : in out Source_Id)
758       is
759          Iterator : Source_Iterator;
760
761       begin
762          Iterator := For_Each_Source (In_Tree => Tree, Project => Proj);
763          while Element (Iterator) /= No_Source loop
764             if Element (Iterator).File = Base_Name
765               and then (Index = 0 or else Element (Iterator).Index = Index)
766             then
767                Src := Element (Iterator);
768
769                --  If the source has been excluded, continue looking. We will
770                --  get the excluded source only if there is no other source
771                --  with the same base name that is not locally removed.
772
773                if not Element (Iterator).Locally_Removed then
774                   return;
775                end if;
776             end if;
777
778             Next (Iterator);
779          end loop;
780       end Look_For_Sources;
781
782       procedure For_Imported_Projects is new For_Every_Project_Imported
783         (State => Source_Id, Action => Look_For_Sources);
784
785       Proj : Project_Id;
786
787    --  Start of processing for Find_Source
788
789    begin
790       if In_Extended_Only then
791          Proj := Project;
792          while Proj /= No_Project loop
793             Look_For_Sources (Proj, In_Tree, Result);
794             exit when Result /= No_Source;
795
796             Proj := Proj.Extends;
797          end loop;
798
799       elsif In_Imported_Only then
800          Look_For_Sources (Project, In_Tree, Result);
801
802          if Result = No_Source then
803             For_Imported_Projects
804               (By                 => Project,
805                Tree               => In_Tree,
806                Include_Aggregated => False,
807                With_State         => Result);
808          end if;
809
810       else
811          Look_For_Sources (No_Project, In_Tree, Result);
812       end if;
813
814       return Result;
815    end Find_Source;
816
817    ----------
818    -- Hash --
819    ----------
820
821    function Hash is new GNAT.HTable.Hash (Header_Num => Header_Num);
822    --  Used in implementation of other functions Hash below
823
824    function Hash (Name : File_Name_Type) return Header_Num is
825    begin
826       return Hash (Get_Name_String (Name));
827    end Hash;
828
829    function Hash (Name : Name_Id) return Header_Num is
830    begin
831       return Hash (Get_Name_String (Name));
832    end Hash;
833
834    function Hash (Name : Path_Name_Type) return Header_Num is
835    begin
836       return Hash (Get_Name_String (Name));
837    end Hash;
838
839    function Hash (Project : Project_Id) return Header_Num is
840    begin
841       if Project = No_Project then
842          return Header_Num'First;
843       else
844          return Hash (Get_Name_String (Project.Name));
845       end if;
846    end Hash;
847
848    -----------
849    -- Image --
850    -----------
851
852    function Image (The_Casing : Casing_Type) return String is
853    begin
854       return The_Casing_Images (The_Casing).all;
855    end Image;
856
857    -----------------------------
858    -- Is_Standard_GNAT_Naming --
859    -----------------------------
860
861    function Is_Standard_GNAT_Naming
862      (Naming : Lang_Naming_Data) return Boolean
863    is
864    begin
865       return Get_Name_String (Naming.Spec_Suffix) = ".ads"
866         and then Get_Name_String (Naming.Body_Suffix) = ".adb"
867         and then Get_Name_String (Naming.Dot_Replacement) = "-";
868    end Is_Standard_GNAT_Naming;
869
870    ----------------
871    -- Initialize --
872    ----------------
873
874    procedure Initialize (Tree : Project_Tree_Ref) is
875    begin
876       if The_Empty_String = No_Name then
877          Uintp.Initialize;
878          Name_Len := 0;
879          The_Empty_String := Name_Find;
880
881          Prj.Attr.Initialize;
882
883          --  Make sure that new reserved words after Ada 95 may be used as
884          --  identifiers.
885
886          Opt.Ada_Version := Opt.Ada_95;
887
888          Set_Name_Table_Byte (Name_Project,  Token_Type'Pos (Tok_Project));
889          Set_Name_Table_Byte (Name_Extends,  Token_Type'Pos (Tok_Extends));
890          Set_Name_Table_Byte (Name_External, Token_Type'Pos (Tok_External));
891          Set_Name_Table_Byte
892            (Name_External_As_List, Token_Type'Pos (Tok_External_As_List));
893       end if;
894
895       if Tree /= No_Project_Tree then
896          Reset (Tree);
897       end if;
898    end Initialize;
899
900    ------------------
901    -- Is_Extending --
902    ------------------
903
904    function Is_Extending
905      (Extending : Project_Id;
906       Extended  : Project_Id) return Boolean
907    is
908       Proj : Project_Id;
909
910    begin
911       Proj := Extending;
912       while Proj /= No_Project loop
913          if Proj = Extended then
914             return True;
915          end if;
916
917          Proj := Proj.Extends;
918       end loop;
919
920       return False;
921    end Is_Extending;
922
923    -----------------
924    -- Object_Name --
925    -----------------
926
927    function Object_Name
928      (Source_File_Name   : File_Name_Type;
929       Object_File_Suffix : Name_Id := No_Name) return File_Name_Type
930    is
931    begin
932       if Object_File_Suffix = No_Name then
933          return Extend_Name
934            (Source_File_Name, Object_Suffix);
935       else
936          return Extend_Name
937            (Source_File_Name, Get_Name_String (Object_File_Suffix));
938       end if;
939    end Object_Name;
940
941    function Object_Name
942      (Source_File_Name   : File_Name_Type;
943       Source_Index       : Int;
944       Index_Separator    : Character;
945       Object_File_Suffix : Name_Id := No_Name) return File_Name_Type
946    is
947       Index_Img : constant String := Source_Index'Img;
948       Last      : Natural;
949
950    begin
951       Get_Name_String (Source_File_Name);
952
953       Last := Name_Len;
954       while Last > 1 and then Name_Buffer (Last) /= '.' loop
955          Last := Last - 1;
956       end loop;
957
958       if Last > 1 then
959          Name_Len := Last - 1;
960       end if;
961
962       Add_Char_To_Name_Buffer (Index_Separator);
963       Add_Str_To_Name_Buffer (Index_Img (2 .. Index_Img'Last));
964
965       if Object_File_Suffix = No_Name then
966          Add_Str_To_Name_Buffer (Object_Suffix);
967       else
968          Add_Str_To_Name_Buffer (Get_Name_String (Object_File_Suffix));
969       end if;
970
971       return Name_Find;
972    end Object_Name;
973
974    ----------------------
975    -- Record_Temp_File --
976    ----------------------
977
978    procedure Record_Temp_File
979      (Shared : Shared_Project_Tree_Data_Access;
980       Path   : Path_Name_Type)
981    is
982    begin
983       Temp_Files_Table.Append (Shared.Private_Part.Temp_Files, Path);
984    end Record_Temp_File;
985
986    ----------
987    -- Free --
988    ----------
989
990    procedure Free (List : in out Aggregated_Project_List) is
991       procedure Unchecked_Free is new Ada.Unchecked_Deallocation
992         (Aggregated_Project, Aggregated_Project_List);
993       Tmp : Aggregated_Project_List;
994    begin
995       while List /= null loop
996          Tmp := List.Next;
997
998          Free (List.Tree);
999
1000          Unchecked_Free (List);
1001          List := Tmp;
1002       end loop;
1003    end Free;
1004
1005    ----------------------------
1006    -- Add_Aggregated_Project --
1007    ----------------------------
1008
1009    procedure Add_Aggregated_Project
1010      (Project : Project_Id; Path : Path_Name_Type) is
1011    begin
1012       Project.Aggregated_Projects := new Aggregated_Project'
1013         (Path    => Path,
1014          Project => No_Project,
1015          Tree    => null,
1016          Next    => Project.Aggregated_Projects);
1017    end Add_Aggregated_Project;
1018
1019    ----------
1020    -- Free --
1021    ----------
1022
1023    procedure Free (Project : in out Project_Id) is
1024       procedure Unchecked_Free is new Ada.Unchecked_Deallocation
1025         (Project_Data, Project_Id);
1026
1027    begin
1028       if Project /= null then
1029          Free (Project.Ada_Include_Path);
1030          Free (Project.Objects_Path);
1031          Free (Project.Ada_Objects_Path);
1032          Free_List (Project.Imported_Projects, Free_Project => False);
1033          Free_List (Project.All_Imported_Projects, Free_Project => False);
1034          Free_List (Project.Languages);
1035
1036          case Project.Qualifier is
1037             when Aggregate | Aggregate_Library =>
1038                Free (Project.Aggregated_Projects);
1039
1040             when others =>
1041                null;
1042          end case;
1043
1044          Unchecked_Free (Project);
1045       end if;
1046    end Free;
1047
1048    ---------------
1049    -- Free_List --
1050    ---------------
1051
1052    procedure Free_List (Languages : in out Language_List) is
1053       procedure Unchecked_Free is new Ada.Unchecked_Deallocation
1054         (Language_List_Element, Language_List);
1055       Tmp : Language_List;
1056    begin
1057       while Languages /= null loop
1058          Tmp := Languages.Next;
1059          Unchecked_Free (Languages);
1060          Languages := Tmp;
1061       end loop;
1062    end Free_List;
1063
1064    ---------------
1065    -- Free_List --
1066    ---------------
1067
1068    procedure Free_List (Source : in out Source_Id) is
1069       procedure Unchecked_Free is new
1070         Ada.Unchecked_Deallocation (Source_Data, Source_Id);
1071
1072       Tmp : Source_Id;
1073
1074    begin
1075       while Source /= No_Source loop
1076          Tmp := Source.Next_In_Lang;
1077          Free_List (Source.Alternate_Languages);
1078
1079          if Source.Unit /= null
1080            and then Source.Kind in Spec_Or_Body
1081          then
1082             Source.Unit.File_Names (Source.Kind) := null;
1083          end if;
1084
1085          Unchecked_Free (Source);
1086          Source := Tmp;
1087       end loop;
1088    end Free_List;
1089
1090    ---------------
1091    -- Free_List --
1092    ---------------
1093
1094    procedure Free_List
1095      (List         : in out Project_List;
1096       Free_Project : Boolean)
1097    is
1098       procedure Unchecked_Free is new
1099         Ada.Unchecked_Deallocation (Project_List_Element, Project_List);
1100
1101       Tmp : Project_List;
1102
1103    begin
1104       while List /= null loop
1105          Tmp := List.Next;
1106
1107          if Free_Project then
1108             Free (List.Project);
1109          end if;
1110
1111          Unchecked_Free (List);
1112          List := Tmp;
1113       end loop;
1114    end Free_List;
1115
1116    ---------------
1117    -- Free_List --
1118    ---------------
1119
1120    procedure Free_List (Languages : in out Language_Ptr) is
1121       procedure Unchecked_Free is new
1122         Ada.Unchecked_Deallocation (Language_Data, Language_Ptr);
1123
1124       Tmp : Language_Ptr;
1125
1126    begin
1127       while Languages /= null loop
1128          Tmp := Languages.Next;
1129          Free_List (Languages.First_Source);
1130          Unchecked_Free (Languages);
1131          Languages := Tmp;
1132       end loop;
1133    end Free_List;
1134
1135    --------------------------
1136    -- Reset_Units_In_Table --
1137    --------------------------
1138
1139    procedure Reset_Units_In_Table (Table : in out Units_Htable.Instance) is
1140       Unit : Unit_Index;
1141
1142    begin
1143       Unit := Units_Htable.Get_First (Table);
1144       while Unit /= No_Unit_Index loop
1145          if Unit.File_Names (Spec) /= null then
1146             Unit.File_Names (Spec).Unit := No_Unit_Index;
1147          end if;
1148
1149          if Unit.File_Names (Impl) /= null then
1150             Unit.File_Names (Impl).Unit := No_Unit_Index;
1151          end if;
1152
1153          Unit := Units_Htable.Get_Next (Table);
1154       end loop;
1155    end Reset_Units_In_Table;
1156
1157    ----------------
1158    -- Free_Units --
1159    ----------------
1160
1161    procedure Free_Units (Table : in out Units_Htable.Instance) is
1162       procedure Unchecked_Free is new
1163         Ada.Unchecked_Deallocation (Unit_Data, Unit_Index);
1164
1165       Unit : Unit_Index;
1166
1167    begin
1168       Unit := Units_Htable.Get_First (Table);
1169       while Unit /= No_Unit_Index loop
1170
1171          --  We cannot reset Unit.File_Names (Impl or Spec).Unit here as
1172          --  Source_Data buffer is freed by the following instruction
1173          --  Free_List (Tree.Projects, Free_Project => True);
1174
1175          Unchecked_Free (Unit);
1176          Unit := Units_Htable.Get_Next (Table);
1177       end loop;
1178
1179       Units_Htable.Reset (Table);
1180    end Free_Units;
1181
1182    ----------
1183    -- Free --
1184    ----------
1185
1186    procedure Free (Tree : in out Project_Tree_Ref) is
1187       procedure Unchecked_Free is new
1188         Ada.Unchecked_Deallocation
1189           (Project_Tree_Data, Project_Tree_Ref);
1190
1191       procedure Unchecked_Free is new
1192         Ada.Unchecked_Deallocation
1193           (Project_Tree_Appdata'Class, Project_Tree_Appdata_Access);
1194
1195    begin
1196       if Tree /= null then
1197          if Tree.Is_Root_Tree then
1198             Name_List_Table.Free        (Tree.Shared.Name_Lists);
1199             Number_List_Table.Free      (Tree.Shared.Number_Lists);
1200             String_Element_Table.Free   (Tree.Shared.String_Elements);
1201             Variable_Element_Table.Free (Tree.Shared.Variable_Elements);
1202             Array_Element_Table.Free    (Tree.Shared.Array_Elements);
1203             Array_Table.Free            (Tree.Shared.Arrays);
1204             Package_Table.Free          (Tree.Shared.Packages);
1205             Temp_Files_Table.Free       (Tree.Shared.Private_Part.Temp_Files);
1206          end if;
1207
1208          if Tree.Appdata /= null then
1209             Free (Tree.Appdata.all);
1210             Unchecked_Free (Tree.Appdata);
1211          end if;
1212
1213          Source_Paths_Htable.Reset (Tree.Source_Paths_HT);
1214          Source_Files_Htable.Reset (Tree.Source_Files_HT);
1215
1216          Reset_Units_In_Table (Tree.Units_HT);
1217          Free_List (Tree.Projects, Free_Project => True);
1218          Free_Units (Tree.Units_HT);
1219
1220          Unchecked_Free (Tree);
1221       end if;
1222    end Free;
1223
1224    -----------
1225    -- Reset --
1226    -----------
1227
1228    procedure Reset (Tree : Project_Tree_Ref) is
1229    begin
1230       --  Visible tables
1231
1232       if Tree.Is_Root_Tree then
1233
1234          --  We cannot use 'Access here:
1235          --    "illegal attribute for discriminant-dependent component"
1236          --  However, we know this is valid since Shared and Shared_Data have
1237          --  the same lifetime and will always exist concurrently.
1238
1239          Tree.Shared := Tree.Shared_Data'Unrestricted_Access;
1240          Name_List_Table.Init        (Tree.Shared.Name_Lists);
1241          Number_List_Table.Init      (Tree.Shared.Number_Lists);
1242          String_Element_Table.Init   (Tree.Shared.String_Elements);
1243          Variable_Element_Table.Init (Tree.Shared.Variable_Elements);
1244          Array_Element_Table.Init    (Tree.Shared.Array_Elements);
1245          Array_Table.Init            (Tree.Shared.Arrays);
1246          Package_Table.Init          (Tree.Shared.Packages);
1247
1248          --  Private part table
1249
1250          Temp_Files_Table.Init (Tree.Shared.Private_Part.Temp_Files);
1251
1252          Tree.Shared.Private_Part.Current_Source_Path_File := No_Path;
1253          Tree.Shared.Private_Part.Current_Object_Path_File := No_Path;
1254       end if;
1255
1256       Source_Paths_Htable.Reset    (Tree.Source_Paths_HT);
1257       Source_Files_Htable.Reset    (Tree.Source_Files_HT);
1258       Replaced_Source_HTable.Reset (Tree.Replaced_Sources);
1259
1260       Tree.Replaced_Source_Number := 0;
1261
1262       Reset_Units_In_Table (Tree.Units_HT);
1263       Free_List (Tree.Projects, Free_Project => True);
1264       Free_Units (Tree.Units_HT);
1265    end Reset;
1266
1267    -------------------------------------
1268    -- Set_Current_Object_Path_File_Of --
1269    -------------------------------------
1270
1271    procedure Set_Current_Object_Path_File_Of
1272      (Shared : Shared_Project_Tree_Data_Access;
1273       To     : Path_Name_Type)
1274    is
1275    begin
1276       Shared.Private_Part.Current_Object_Path_File := To;
1277    end Set_Current_Object_Path_File_Of;
1278
1279    -------------------------------------
1280    -- Set_Current_Source_Path_File_Of --
1281    -------------------------------------
1282
1283    procedure Set_Current_Source_Path_File_Of
1284      (Shared : Shared_Project_Tree_Data_Access;
1285       To     : Path_Name_Type)
1286    is
1287    begin
1288       Shared.Private_Part.Current_Source_Path_File := To;
1289    end Set_Current_Source_Path_File_Of;
1290
1291    -----------------------
1292    -- Set_Path_File_Var --
1293    -----------------------
1294
1295    procedure Set_Path_File_Var (Name : String; Value : String) is
1296       Host_Spec : String_Access := To_Host_File_Spec (Value);
1297    begin
1298       if Host_Spec = null then
1299          Prj.Com.Fail
1300            ("could not convert file name """ & Value & """ to host spec");
1301       else
1302          Setenv (Name, Host_Spec.all);
1303          Free (Host_Spec);
1304       end if;
1305    end Set_Path_File_Var;
1306
1307    -------------------
1308    -- Switches_Name --
1309    -------------------
1310
1311    function Switches_Name
1312      (Source_File_Name : File_Name_Type) return File_Name_Type
1313    is
1314    begin
1315       return Extend_Name (Source_File_Name, Switches_Dependency_Suffix);
1316    end Switches_Name;
1317
1318    -----------
1319    -- Value --
1320    -----------
1321
1322    function Value (Image : String) return Casing_Type is
1323    begin
1324       for Casing in The_Casing_Images'Range loop
1325          if To_Lower (Image) = To_Lower (The_Casing_Images (Casing).all) then
1326             return Casing;
1327          end if;
1328       end loop;
1329
1330       raise Constraint_Error;
1331    end Value;
1332
1333    ---------------------
1334    -- Has_Ada_Sources --
1335    ---------------------
1336
1337    function Has_Ada_Sources (Data : Project_Id) return Boolean is
1338       Lang : Language_Ptr;
1339
1340    begin
1341       Lang := Data.Languages;
1342       while Lang /= No_Language_Index loop
1343          if Lang.Name = Name_Ada then
1344             return Lang.First_Source /= No_Source;
1345          end if;
1346          Lang := Lang.Next;
1347       end loop;
1348
1349       return False;
1350    end Has_Ada_Sources;
1351
1352    ------------------------
1353    -- Contains_ALI_Files --
1354    ------------------------
1355
1356    function Contains_ALI_Files (Dir : Path_Name_Type) return Boolean is
1357       Dir_Name : constant String := Get_Name_String (Dir);
1358       Direct   : Dir_Type;
1359       Name     : String (1 .. 1_000);
1360       Last     : Natural;
1361       Result   : Boolean := False;
1362
1363    begin
1364       Open (Direct, Dir_Name);
1365
1366       --  For each file in the directory, check if it is an ALI file
1367
1368       loop
1369          Read (Direct, Name, Last);
1370          exit when Last = 0;
1371          Canonical_Case_File_Name (Name (1 .. Last));
1372          Result := Last >= 5 and then Name (Last - 3 .. Last) = ".ali";
1373          exit when Result;
1374       end loop;
1375
1376       Close (Direct);
1377       return Result;
1378
1379    exception
1380       --  If there is any problem, close the directory if open and return True.
1381       --  The library directory will be added to the path.
1382
1383       when others =>
1384          if Is_Open (Direct) then
1385             Close (Direct);
1386          end if;
1387
1388          return True;
1389    end Contains_ALI_Files;
1390
1391    --------------------------
1392    -- Get_Object_Directory --
1393    --------------------------
1394
1395    function Get_Object_Directory
1396      (Project             : Project_Id;
1397       Including_Libraries : Boolean;
1398       Only_If_Ada         : Boolean := False) return Path_Name_Type
1399    is
1400    begin
1401       if (Project.Library and then Including_Libraries)
1402         or else
1403           (Project.Object_Directory /= No_Path_Information
1404             and then (not Including_Libraries or else not Project.Library))
1405       then
1406          --  For a library project, add the library ALI directory if there is
1407          --  no object directory or if the library ALI directory contains ALI
1408          --  files; otherwise add the object directory.
1409
1410          if Project.Library then
1411             if Project.Object_Directory = No_Path_Information
1412               or else Contains_ALI_Files (Project.Library_ALI_Dir.Display_Name)
1413             then
1414                return Project.Library_ALI_Dir.Display_Name;
1415             else
1416                return Project.Object_Directory.Display_Name;
1417             end if;
1418
1419             --  For a non-library project, add object directory if it is not a
1420             --  virtual project, and if there are Ada sources in the project or
1421             --  one of the projects it extends. If there are no Ada sources,
1422             --  adding the object directory could disrupt the order of the
1423             --  object dirs in the path.
1424
1425          elsif not Project.Virtual then
1426             declare
1427                Add_Object_Dir : Boolean;
1428                Prj            : Project_Id;
1429
1430             begin
1431                Add_Object_Dir := not Only_If_Ada;
1432                Prj := Project;
1433                while not Add_Object_Dir and then Prj /= No_Project loop
1434                   if Has_Ada_Sources (Prj) then
1435                      Add_Object_Dir := True;
1436                   else
1437                      Prj := Prj.Extends;
1438                   end if;
1439                end loop;
1440
1441                if Add_Object_Dir then
1442                   return Project.Object_Directory.Display_Name;
1443                end if;
1444             end;
1445          end if;
1446       end if;
1447
1448       return No_Path;
1449    end Get_Object_Directory;
1450
1451    -----------------------------------
1452    -- Ultimate_Extending_Project_Of --
1453    -----------------------------------
1454
1455    function Ultimate_Extending_Project_Of
1456      (Proj : Project_Id) return Project_Id
1457    is
1458       Prj : Project_Id;
1459
1460    begin
1461       Prj := Proj;
1462       while Prj /= null and then Prj.Extended_By /= No_Project loop
1463          Prj := Prj.Extended_By;
1464       end loop;
1465
1466       return Prj;
1467    end Ultimate_Extending_Project_Of;
1468
1469    -----------------------------------
1470    -- Compute_All_Imported_Projects --
1471    -----------------------------------
1472
1473    procedure Compute_All_Imported_Projects
1474      (Root_Project : Project_Id;
1475       Tree         : Project_Tree_Ref)
1476    is
1477       procedure Analyze_Tree
1478         (Local_Root : Project_Id;
1479          Local_Tree : Project_Tree_Ref);
1480       --  Process Project and all its aggregated project to analyze their own
1481       --  imported projects.
1482
1483       ------------------
1484       -- Analyze_Tree --
1485       ------------------
1486
1487       procedure Analyze_Tree
1488         (Local_Root : Project_Id;
1489          Local_Tree : Project_Tree_Ref)
1490       is
1491          pragma Unreferenced (Local_Root);
1492
1493          Project : Project_Id;
1494
1495          procedure Recursive_Add
1496            (Prj     : Project_Id;
1497             Tree    : Project_Tree_Ref;
1498             Context : Project_Context;
1499             Dummy   : in out Boolean);
1500          --  Recursively add the projects imported by project Project, but not
1501          --  those that are extended.
1502
1503          -------------------
1504          -- Recursive_Add --
1505          -------------------
1506
1507          procedure Recursive_Add
1508            (Prj     : Project_Id;
1509             Tree    : Project_Tree_Ref;
1510             Context : Project_Context;
1511             Dummy   : in out Boolean)
1512          is
1513             pragma Unreferenced (Dummy, Tree);
1514
1515             List : Project_List;
1516             Prj2 : Project_Id;
1517
1518          begin
1519             --  A project is not importing itself
1520
1521             Prj2 := Ultimate_Extending_Project_Of (Prj);
1522
1523             if Project /= Prj2 then
1524
1525                --  Check that the project is not already in the list. We know
1526                --  the one passed to Recursive_Add have never been visited
1527                --  before, but the one passed it are the extended projects.
1528
1529                List := Project.All_Imported_Projects;
1530                while List /= null loop
1531                   if List.Project = Prj2 then
1532                      return;
1533                   end if;
1534
1535                   List := List.Next;
1536                end loop;
1537
1538                --  Add it to the list
1539
1540                Project.All_Imported_Projects :=
1541                  new Project_List_Element'
1542                    (Project               => Prj2,
1543                     From_Encapsulated_Lib => Context.From_Encapsulated_Lib,
1544                     Next                  => Project.All_Imported_Projects);
1545             end if;
1546          end Recursive_Add;
1547
1548          procedure For_All_Projects is
1549            new For_Every_Project_Imported_Context (Boolean, Recursive_Add);
1550
1551          Dummy : Boolean := False;
1552          List  : Project_List;
1553
1554       begin
1555          List := Local_Tree.Projects;
1556          while List /= null loop
1557             Project := List.Project;
1558             Free_List
1559               (Project.All_Imported_Projects, Free_Project => False);
1560             For_All_Projects
1561               (Project, Local_Tree, Dummy, Include_Aggregated => False);
1562             List := List.Next;
1563          end loop;
1564       end Analyze_Tree;
1565
1566       procedure For_Aggregates is
1567         new For_Project_And_Aggregated (Analyze_Tree);
1568
1569    --  Start of processing for Compute_All_Imported_Projects
1570
1571    begin
1572       For_Aggregates (Root_Project, Tree);
1573    end Compute_All_Imported_Projects;
1574
1575    -------------------
1576    -- Is_Compilable --
1577    -------------------
1578
1579    function Is_Compilable (Source : Source_Id) return Boolean is
1580    begin
1581       case Source.Compilable is
1582          when Unknown =>
1583             if Source.Language.Config.Compiler_Driver /= No_File
1584               and then
1585                 Length_Of_Name (Source.Language.Config.Compiler_Driver) /= 0
1586               and then not Source.Locally_Removed
1587               and then (Source.Language.Config.Kind /= File_Based
1588                          or else Source.Kind /= Spec)
1589             then
1590                --  Do not modify Source.Compilable before the source record
1591                --  has been initialized.
1592
1593                if Source.Source_TS /= Empty_Time_Stamp then
1594                   Source.Compilable := Yes;
1595                end if;
1596
1597                return True;
1598
1599             else
1600                if Source.Source_TS /= Empty_Time_Stamp then
1601                   Source.Compilable := No;
1602                end if;
1603
1604                return False;
1605             end if;
1606
1607          when Yes =>
1608             return True;
1609
1610          when No =>
1611             return False;
1612       end case;
1613    end Is_Compilable;
1614
1615    ------------------------------
1616    -- Object_To_Global_Archive --
1617    ------------------------------
1618
1619    function Object_To_Global_Archive (Source : Source_Id) return Boolean is
1620    begin
1621       return Source.Language.Config.Kind = File_Based
1622         and then Source.Kind = Impl
1623         and then Source.Language.Config.Objects_Linked
1624         and then Is_Compilable (Source)
1625         and then Source.Language.Config.Object_Generated;
1626    end Object_To_Global_Archive;
1627
1628    ----------------------------
1629    -- Get_Language_From_Name --
1630    ----------------------------
1631
1632    function Get_Language_From_Name
1633      (Project : Project_Id;
1634       Name    : String) return Language_Ptr
1635    is
1636       N      : Name_Id;
1637       Result : Language_Ptr;
1638
1639    begin
1640       Name_Len := Name'Length;
1641       Name_Buffer (1 .. Name_Len) := Name;
1642       To_Lower (Name_Buffer (1 .. Name_Len));
1643       N := Name_Find;
1644
1645       Result := Project.Languages;
1646       while Result /= No_Language_Index loop
1647          if Result.Name = N then
1648             return Result;
1649          end if;
1650
1651          Result := Result.Next;
1652       end loop;
1653
1654       return No_Language_Index;
1655    end Get_Language_From_Name;
1656
1657    ----------------
1658    -- Other_Part --
1659    ----------------
1660
1661    function Other_Part (Source : Source_Id) return Source_Id is
1662    begin
1663       if Source.Unit /= No_Unit_Index then
1664          case Source.Kind is
1665             when Impl =>
1666                return Source.Unit.File_Names (Spec);
1667             when Spec =>
1668                return Source.Unit.File_Names (Impl);
1669             when Sep =>
1670                return No_Source;
1671          end case;
1672       else
1673          return No_Source;
1674       end if;
1675    end Other_Part;
1676
1677    ------------------
1678    -- Create_Flags --
1679    ------------------
1680
1681    function Create_Flags
1682      (Report_Error               : Error_Handler;
1683       When_No_Sources            : Error_Warning;
1684       Require_Sources_Other_Lang : Boolean       := True;
1685       Allow_Duplicate_Basenames  : Boolean       := True;
1686       Compiler_Driver_Mandatory  : Boolean       := False;
1687       Error_On_Unknown_Language  : Boolean       := True;
1688       Require_Obj_Dirs           : Error_Warning := Error;
1689       Allow_Invalid_External     : Error_Warning := Error;
1690       Missing_Source_Files       : Error_Warning := Error;
1691       Ignore_Missing_With        : Boolean       := False)
1692       return Processing_Flags
1693    is
1694    begin
1695       return Processing_Flags'
1696         (Report_Error               => Report_Error,
1697          When_No_Sources            => When_No_Sources,
1698          Require_Sources_Other_Lang => Require_Sources_Other_Lang,
1699          Allow_Duplicate_Basenames  => Allow_Duplicate_Basenames,
1700          Error_On_Unknown_Language  => Error_On_Unknown_Language,
1701          Compiler_Driver_Mandatory  => Compiler_Driver_Mandatory,
1702          Require_Obj_Dirs           => Require_Obj_Dirs,
1703          Allow_Invalid_External     => Allow_Invalid_External,
1704          Missing_Source_Files       => Missing_Source_Files,
1705          Ignore_Missing_With        => Ignore_Missing_With);
1706    end Create_Flags;
1707
1708    ------------
1709    -- Length --
1710    ------------
1711
1712    function Length
1713      (Table : Name_List_Table.Instance;
1714       List  : Name_List_Index) return Natural
1715    is
1716       Count : Natural := 0;
1717       Tmp   : Name_List_Index;
1718
1719    begin
1720       Tmp := List;
1721       while Tmp /= No_Name_List loop
1722          Count := Count + 1;
1723          Tmp := Table.Table (Tmp).Next;
1724       end loop;
1725
1726       return Count;
1727    end Length;
1728
1729    ------------------
1730    -- Debug_Output --
1731    ------------------
1732
1733    procedure Debug_Output (Str : String) is
1734    begin
1735       if Current_Verbosity > Default then
1736          Set_Standard_Error;
1737          Write_Line ((1 .. Debug_Level * 2 => ' ') & Str);
1738          Set_Standard_Output;
1739       end if;
1740    end Debug_Output;
1741
1742    ------------------
1743    -- Debug_Indent --
1744    ------------------
1745
1746    procedure Debug_Indent is
1747    begin
1748       if Current_Verbosity = High then
1749          Set_Standard_Error;
1750          Write_Str ((1 .. Debug_Level * 2 => ' '));
1751          Set_Standard_Output;
1752       end if;
1753    end Debug_Indent;
1754
1755    ------------------
1756    -- Debug_Output --
1757    ------------------
1758
1759    procedure Debug_Output (Str : String; Str2 : Name_Id) is
1760    begin
1761       if Current_Verbosity = High then
1762          Debug_Indent;
1763          Set_Standard_Error;
1764          Write_Str (Str);
1765
1766          if Str2 = No_Name then
1767             Write_Line (" <no_name>");
1768          else
1769             Write_Line (" """ & Get_Name_String (Str2) & '"');
1770          end if;
1771
1772          Set_Standard_Output;
1773       end if;
1774    end Debug_Output;
1775
1776    ---------------------------
1777    -- Debug_Increase_Indent --
1778    ---------------------------
1779
1780    procedure Debug_Increase_Indent
1781      (Str : String := ""; Str2 : Name_Id := No_Name)
1782    is
1783    begin
1784       if Str2 /= No_Name then
1785          Debug_Output (Str, Str2);
1786       else
1787          Debug_Output (Str);
1788       end if;
1789       Debug_Level := Debug_Level + 1;
1790    end Debug_Increase_Indent;
1791
1792    ---------------------------
1793    -- Debug_Decrease_Indent --
1794    ---------------------------
1795
1796    procedure Debug_Decrease_Indent (Str : String := "") is
1797    begin
1798       if Debug_Level > 0 then
1799          Debug_Level := Debug_Level - 1;
1800       end if;
1801
1802       if Str /= "" then
1803          Debug_Output (Str);
1804       end if;
1805    end Debug_Decrease_Indent;
1806
1807    ----------------
1808    -- Debug_Name --
1809    ----------------
1810
1811    function Debug_Name (Tree : Project_Tree_Ref) return Name_Id is
1812       P : Project_List;
1813
1814    begin
1815       Name_Len := 0;
1816       Add_Str_To_Name_Buffer ("Tree [");
1817
1818       P := Tree.Projects;
1819       while P /= null loop
1820          if P /= Tree.Projects then
1821             Add_Char_To_Name_Buffer (',');
1822          end if;
1823
1824          Add_Str_To_Name_Buffer (Get_Name_String (P.Project.Name));
1825
1826          P := P.Next;
1827       end loop;
1828
1829       Add_Char_To_Name_Buffer (']');
1830
1831       return Name_Find;
1832    end Debug_Name;
1833
1834    ----------
1835    -- Free --
1836    ----------
1837
1838    procedure Free (Tree : in out Project_Tree_Appdata) is
1839       pragma Unreferenced (Tree);
1840    begin
1841       null;
1842    end Free;
1843
1844    --------------------------------
1845    -- For_Project_And_Aggregated --
1846    --------------------------------
1847
1848    procedure For_Project_And_Aggregated
1849      (Root_Project : Project_Id;
1850       Root_Tree    : Project_Tree_Ref)
1851    is
1852       Agg : Aggregated_Project_List;
1853
1854    begin
1855       Action (Root_Project, Root_Tree);
1856
1857       if Root_Project.Qualifier in Aggregate_Project then
1858          Agg := Root_Project.Aggregated_Projects;
1859          while Agg /= null loop
1860             For_Project_And_Aggregated (Agg.Project, Agg.Tree);
1861             Agg := Agg.Next;
1862          end loop;
1863       end if;
1864    end For_Project_And_Aggregated;
1865
1866 --  Package initialization for Prj
1867
1868 begin
1869    --  Make sure that the standard config and user project file extensions are
1870    --  compatible with canonical case file naming.
1871
1872    Canonical_Case_File_Name (Config_Project_File_Extension);
1873    Canonical_Case_File_Name (Project_File_Extension);
1874 end Prj;