OSDN Git Service

f4226c21c6f27498c1cbf9ba77473390ebabe11f
[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 (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 or
648                                 Project.Standalone_Library = Encapsulated);
649
650                         else
651                            T := Agg.Tree;
652
653                            --  Use a new context as we want to returns the same
654                            --  project in different project tree for aggregated
655                            --  projects.
656
657                            Recursive_Check_Context
658                              (Agg.Project, T, False, False);
659                         end if;
660
661                         Agg := Agg.Next;
662                      end loop;
663                   end;
664                end if;
665
666                if Imported_First then
667                   Action
668                     (Project,
669                      Tree,
670                      Project_Context'(In_Aggregate_Lib, From_Encapsulated_Lib),
671                      With_State);
672                end if;
673             end if;
674          end Recursive_Check;
675
676       --  Start of processing for Recursive_Check_Context
677
678       begin
679          Recursive_Check
680            (Project, Tree, In_Aggregate_Lib, From_Encapsulated_Lib);
681       end Recursive_Check_Context;
682
683    --  Start of processing for For_Every_Project_Imported
684
685    begin
686       Recursive_Check_Context
687         (Project               => By,
688          Tree                  => Tree,
689          In_Aggregate_Lib      => False,
690          From_Encapsulated_Lib => False);
691    end For_Every_Project_Imported_Context;
692
693    procedure For_Every_Project_Imported
694      (By                 : Project_Id;
695       Tree               : Project_Tree_Ref;
696       With_State         : in out State;
697       Include_Aggregated : Boolean := True;
698       Imported_First     : Boolean := False)
699    is
700       procedure Internal
701         (Project    : Project_Id;
702          Tree       : Project_Tree_Ref;
703          Context    : Project_Context;
704          With_State : in out State);
705       --  Action wrapper for handling the context
706
707       --------------
708       -- Internal --
709       --------------
710
711       procedure Internal
712         (Project    : Project_Id;
713          Tree       : Project_Tree_Ref;
714          Context    : Project_Context;
715          With_State : in out State)
716       is
717          pragma Unreferenced (Context);
718       begin
719          Action (Project, Tree, With_State);
720       end Internal;
721
722       procedure For_Projects is
723         new For_Every_Project_Imported_Context (State, Internal);
724
725    begin
726       For_Projects (By, Tree, With_State, Include_Aggregated, Imported_First);
727    end For_Every_Project_Imported;
728
729    -----------------
730    -- Find_Source --
731    -----------------
732
733    function Find_Source
734      (In_Tree          : Project_Tree_Ref;
735       Project          : Project_Id;
736       In_Imported_Only : Boolean := False;
737       In_Extended_Only : Boolean := False;
738       Base_Name        : File_Name_Type;
739       Index            : Int := 0) return Source_Id
740    is
741       Result : Source_Id  := No_Source;
742
743       procedure Look_For_Sources
744         (Proj : Project_Id;
745          Tree : Project_Tree_Ref;
746          Src  : in out Source_Id);
747       --  Look for Base_Name in the sources of Proj
748
749       ----------------------
750       -- Look_For_Sources --
751       ----------------------
752
753       procedure Look_For_Sources
754         (Proj : Project_Id;
755          Tree : Project_Tree_Ref;
756          Src  : in out Source_Id)
757       is
758          Iterator : Source_Iterator;
759
760       begin
761          Iterator := For_Each_Source (In_Tree => Tree, Project => Proj);
762          while Element (Iterator) /= No_Source loop
763             if Element (Iterator).File = Base_Name
764               and then (Index = 0 or else Element (Iterator).Index = Index)
765             then
766                Src := Element (Iterator);
767
768                --  If the source has been excluded, continue looking. We will
769                --  get the excluded source only if there is no other source
770                --  with the same base name that is not locally removed.
771
772                if not Element (Iterator).Locally_Removed then
773                   return;
774                end if;
775             end if;
776
777             Next (Iterator);
778          end loop;
779       end Look_For_Sources;
780
781       procedure For_Imported_Projects is new For_Every_Project_Imported
782         (State => Source_Id, Action => Look_For_Sources);
783
784       Proj : Project_Id;
785
786    --  Start of processing for Find_Source
787
788    begin
789       if In_Extended_Only then
790          Proj := Project;
791          while Proj /= No_Project loop
792             Look_For_Sources (Proj, In_Tree, Result);
793             exit when Result /= No_Source;
794
795             Proj := Proj.Extends;
796          end loop;
797
798       elsif In_Imported_Only then
799          Look_For_Sources (Project, In_Tree, Result);
800
801          if Result = No_Source then
802             For_Imported_Projects
803               (By                 => Project,
804                Tree               => In_Tree,
805                Include_Aggregated => False,
806                With_State         => Result);
807          end if;
808
809       else
810          Look_For_Sources (No_Project, In_Tree, Result);
811       end if;
812
813       return Result;
814    end Find_Source;
815
816    ----------
817    -- Hash --
818    ----------
819
820    function Hash is new GNAT.HTable.Hash (Header_Num => Header_Num);
821    --  Used in implementation of other functions Hash below
822
823    function Hash (Name : File_Name_Type) return Header_Num is
824    begin
825       return Hash (Get_Name_String (Name));
826    end Hash;
827
828    function Hash (Name : Name_Id) return Header_Num is
829    begin
830       return Hash (Get_Name_String (Name));
831    end Hash;
832
833    function Hash (Name : Path_Name_Type) return Header_Num is
834    begin
835       return Hash (Get_Name_String (Name));
836    end Hash;
837
838    function Hash (Project : Project_Id) return Header_Num is
839    begin
840       if Project = No_Project then
841          return Header_Num'First;
842       else
843          return Hash (Get_Name_String (Project.Name));
844       end if;
845    end Hash;
846
847    -----------
848    -- Image --
849    -----------
850
851    function Image (The_Casing : Casing_Type) return String is
852    begin
853       return The_Casing_Images (The_Casing).all;
854    end Image;
855
856    -----------------------------
857    -- Is_Standard_GNAT_Naming --
858    -----------------------------
859
860    function Is_Standard_GNAT_Naming
861      (Naming : Lang_Naming_Data) return Boolean
862    is
863    begin
864       return Get_Name_String (Naming.Spec_Suffix) = ".ads"
865         and then Get_Name_String (Naming.Body_Suffix) = ".adb"
866         and then Get_Name_String (Naming.Dot_Replacement) = "-";
867    end Is_Standard_GNAT_Naming;
868
869    ----------------
870    -- Initialize --
871    ----------------
872
873    procedure Initialize (Tree : Project_Tree_Ref) is
874    begin
875       if The_Empty_String = No_Name then
876          Uintp.Initialize;
877          Name_Len := 0;
878          The_Empty_String := Name_Find;
879
880          Prj.Attr.Initialize;
881
882          --  Make sure that new reserved words after Ada 95 may be used as
883          --  identifiers.
884
885          Opt.Ada_Version := Opt.Ada_95;
886
887          Set_Name_Table_Byte (Name_Project,  Token_Type'Pos (Tok_Project));
888          Set_Name_Table_Byte (Name_Extends,  Token_Type'Pos (Tok_Extends));
889          Set_Name_Table_Byte (Name_External, Token_Type'Pos (Tok_External));
890          Set_Name_Table_Byte
891            (Name_External_As_List, Token_Type'Pos (Tok_External_As_List));
892       end if;
893
894       if Tree /= No_Project_Tree then
895          Reset (Tree);
896       end if;
897    end Initialize;
898
899    ------------------
900    -- Is_Extending --
901    ------------------
902
903    function Is_Extending
904      (Extending : Project_Id;
905       Extended  : Project_Id) return Boolean
906    is
907       Proj : Project_Id;
908
909    begin
910       Proj := Extending;
911       while Proj /= No_Project loop
912          if Proj = Extended then
913             return True;
914          end if;
915
916          Proj := Proj.Extends;
917       end loop;
918
919       return False;
920    end Is_Extending;
921
922    -----------------
923    -- Object_Name --
924    -----------------
925
926    function Object_Name
927      (Source_File_Name   : File_Name_Type;
928       Object_File_Suffix : Name_Id := No_Name) return File_Name_Type
929    is
930    begin
931       if Object_File_Suffix = No_Name then
932          return Extend_Name
933            (Source_File_Name, Object_Suffix);
934       else
935          return Extend_Name
936            (Source_File_Name, Get_Name_String (Object_File_Suffix));
937       end if;
938    end Object_Name;
939
940    function Object_Name
941      (Source_File_Name   : File_Name_Type;
942       Source_Index       : Int;
943       Index_Separator    : Character;
944       Object_File_Suffix : Name_Id := No_Name) return File_Name_Type
945    is
946       Index_Img : constant String := Source_Index'Img;
947       Last      : Natural;
948
949    begin
950       Get_Name_String (Source_File_Name);
951
952       Last := Name_Len;
953       while Last > 1 and then Name_Buffer (Last) /= '.' loop
954          Last := Last - 1;
955       end loop;
956
957       if Last > 1 then
958          Name_Len := Last - 1;
959       end if;
960
961       Add_Char_To_Name_Buffer (Index_Separator);
962       Add_Str_To_Name_Buffer (Index_Img (2 .. Index_Img'Last));
963
964       if Object_File_Suffix = No_Name then
965          Add_Str_To_Name_Buffer (Object_Suffix);
966       else
967          Add_Str_To_Name_Buffer (Get_Name_String (Object_File_Suffix));
968       end if;
969
970       return Name_Find;
971    end Object_Name;
972
973    ----------------------
974    -- Record_Temp_File --
975    ----------------------
976
977    procedure Record_Temp_File
978      (Shared : Shared_Project_Tree_Data_Access;
979       Path   : Path_Name_Type)
980    is
981    begin
982       Temp_Files_Table.Append (Shared.Private_Part.Temp_Files, Path);
983    end Record_Temp_File;
984
985    ----------
986    -- Free --
987    ----------
988
989    procedure Free (List : in out Aggregated_Project_List) is
990       procedure Unchecked_Free is new Ada.Unchecked_Deallocation
991         (Aggregated_Project, Aggregated_Project_List);
992       Tmp : Aggregated_Project_List;
993    begin
994       while List /= null loop
995          Tmp := List.Next;
996
997          Free (List.Tree);
998
999          Unchecked_Free (List);
1000          List := Tmp;
1001       end loop;
1002    end Free;
1003
1004    ----------------------------
1005    -- Add_Aggregated_Project --
1006    ----------------------------
1007
1008    procedure Add_Aggregated_Project
1009      (Project : Project_Id; Path : Path_Name_Type) is
1010    begin
1011       Project.Aggregated_Projects := new Aggregated_Project'
1012         (Path    => Path,
1013          Project => No_Project,
1014          Tree    => null,
1015          Next    => Project.Aggregated_Projects);
1016    end Add_Aggregated_Project;
1017
1018    ----------
1019    -- Free --
1020    ----------
1021
1022    procedure Free (Project : in out Project_Id) is
1023       procedure Unchecked_Free is new Ada.Unchecked_Deallocation
1024         (Project_Data, Project_Id);
1025
1026    begin
1027       if Project /= null then
1028          Free (Project.Ada_Include_Path);
1029          Free (Project.Objects_Path);
1030          Free (Project.Ada_Objects_Path);
1031          Free_List (Project.Imported_Projects, Free_Project => False);
1032          Free_List (Project.All_Imported_Projects, Free_Project => False);
1033          Free_List (Project.Languages);
1034
1035          case Project.Qualifier is
1036             when Aggregate | Aggregate_Library =>
1037                Free (Project.Aggregated_Projects);
1038
1039             when others =>
1040                null;
1041          end case;
1042
1043          Unchecked_Free (Project);
1044       end if;
1045    end Free;
1046
1047    ---------------
1048    -- Free_List --
1049    ---------------
1050
1051    procedure Free_List (Languages : in out Language_List) is
1052       procedure Unchecked_Free is new Ada.Unchecked_Deallocation
1053         (Language_List_Element, Language_List);
1054       Tmp : Language_List;
1055    begin
1056       while Languages /= null loop
1057          Tmp := Languages.Next;
1058          Unchecked_Free (Languages);
1059          Languages := Tmp;
1060       end loop;
1061    end Free_List;
1062
1063    ---------------
1064    -- Free_List --
1065    ---------------
1066
1067    procedure Free_List (Source : in out Source_Id) is
1068       procedure Unchecked_Free is new
1069         Ada.Unchecked_Deallocation (Source_Data, Source_Id);
1070
1071       Tmp : Source_Id;
1072
1073    begin
1074       while Source /= No_Source loop
1075          Tmp := Source.Next_In_Lang;
1076          Free_List (Source.Alternate_Languages);
1077
1078          if Source.Unit /= null
1079            and then Source.Kind in Spec_Or_Body
1080          then
1081             Source.Unit.File_Names (Source.Kind) := null;
1082          end if;
1083
1084          Unchecked_Free (Source);
1085          Source := Tmp;
1086       end loop;
1087    end Free_List;
1088
1089    ---------------
1090    -- Free_List --
1091    ---------------
1092
1093    procedure Free_List
1094      (List         : in out Project_List;
1095       Free_Project : Boolean)
1096    is
1097       procedure Unchecked_Free is new
1098         Ada.Unchecked_Deallocation (Project_List_Element, Project_List);
1099
1100       Tmp : Project_List;
1101
1102    begin
1103       while List /= null loop
1104          Tmp := List.Next;
1105
1106          if Free_Project then
1107             Free (List.Project);
1108          end if;
1109
1110          Unchecked_Free (List);
1111          List := Tmp;
1112       end loop;
1113    end Free_List;
1114
1115    ---------------
1116    -- Free_List --
1117    ---------------
1118
1119    procedure Free_List (Languages : in out Language_Ptr) is
1120       procedure Unchecked_Free is new
1121         Ada.Unchecked_Deallocation (Language_Data, Language_Ptr);
1122
1123       Tmp : Language_Ptr;
1124
1125    begin
1126       while Languages /= null loop
1127          Tmp := Languages.Next;
1128          Free_List (Languages.First_Source);
1129          Unchecked_Free (Languages);
1130          Languages := Tmp;
1131       end loop;
1132    end Free_List;
1133
1134    --------------------------
1135    -- Reset_Units_In_Table --
1136    --------------------------
1137
1138    procedure Reset_Units_In_Table (Table : in out Units_Htable.Instance) is
1139       Unit : Unit_Index;
1140
1141    begin
1142       Unit := Units_Htable.Get_First (Table);
1143       while Unit /= No_Unit_Index loop
1144          if Unit.File_Names (Spec) /= null then
1145             Unit.File_Names (Spec).Unit := No_Unit_Index;
1146          end if;
1147
1148          if Unit.File_Names (Impl) /= null then
1149             Unit.File_Names (Impl).Unit := No_Unit_Index;
1150          end if;
1151
1152          Unit := Units_Htable.Get_Next (Table);
1153       end loop;
1154    end Reset_Units_In_Table;
1155
1156    ----------------
1157    -- Free_Units --
1158    ----------------
1159
1160    procedure Free_Units (Table : in out Units_Htable.Instance) is
1161       procedure Unchecked_Free is new
1162         Ada.Unchecked_Deallocation (Unit_Data, Unit_Index);
1163
1164       Unit : Unit_Index;
1165
1166    begin
1167       Unit := Units_Htable.Get_First (Table);
1168       while Unit /= No_Unit_Index loop
1169
1170          --  We cannot reset Unit.File_Names (Impl or Spec).Unit here as
1171          --  Source_Data buffer is freed by the following instruction
1172          --  Free_List (Tree.Projects, Free_Project => True);
1173
1174          Unchecked_Free (Unit);
1175          Unit := Units_Htable.Get_Next (Table);
1176       end loop;
1177
1178       Units_Htable.Reset (Table);
1179    end Free_Units;
1180
1181    ----------
1182    -- Free --
1183    ----------
1184
1185    procedure Free (Tree : in out Project_Tree_Ref) is
1186       procedure Unchecked_Free is new
1187         Ada.Unchecked_Deallocation
1188           (Project_Tree_Data, Project_Tree_Ref);
1189
1190       procedure Unchecked_Free is new
1191         Ada.Unchecked_Deallocation
1192           (Project_Tree_Appdata'Class, Project_Tree_Appdata_Access);
1193
1194    begin
1195       if Tree /= null then
1196          if Tree.Is_Root_Tree then
1197             Name_List_Table.Free        (Tree.Shared.Name_Lists);
1198             Number_List_Table.Free      (Tree.Shared.Number_Lists);
1199             String_Element_Table.Free   (Tree.Shared.String_Elements);
1200             Variable_Element_Table.Free (Tree.Shared.Variable_Elements);
1201             Array_Element_Table.Free    (Tree.Shared.Array_Elements);
1202             Array_Table.Free            (Tree.Shared.Arrays);
1203             Package_Table.Free          (Tree.Shared.Packages);
1204             Temp_Files_Table.Free       (Tree.Shared.Private_Part.Temp_Files);
1205          end if;
1206
1207          if Tree.Appdata /= null then
1208             Free (Tree.Appdata.all);
1209             Unchecked_Free (Tree.Appdata);
1210          end if;
1211
1212          Source_Paths_Htable.Reset (Tree.Source_Paths_HT);
1213          Source_Files_Htable.Reset (Tree.Source_Files_HT);
1214
1215          Reset_Units_In_Table (Tree.Units_HT);
1216          Free_List (Tree.Projects, Free_Project => True);
1217          Free_Units (Tree.Units_HT);
1218
1219          Unchecked_Free (Tree);
1220       end if;
1221    end Free;
1222
1223    -----------
1224    -- Reset --
1225    -----------
1226
1227    procedure Reset (Tree : Project_Tree_Ref) is
1228    begin
1229       --  Visible tables
1230
1231       if Tree.Is_Root_Tree then
1232
1233          --  We cannot use 'Access here:
1234          --    "illegal attribute for discriminant-dependent component"
1235          --  However, we know this is valid since Shared and Shared_Data have
1236          --  the same lifetime and will always exist concurrently.
1237
1238          Tree.Shared := Tree.Shared_Data'Unrestricted_Access;
1239          Name_List_Table.Init        (Tree.Shared.Name_Lists);
1240          Number_List_Table.Init      (Tree.Shared.Number_Lists);
1241          String_Element_Table.Init   (Tree.Shared.String_Elements);
1242          Variable_Element_Table.Init (Tree.Shared.Variable_Elements);
1243          Array_Element_Table.Init    (Tree.Shared.Array_Elements);
1244          Array_Table.Init            (Tree.Shared.Arrays);
1245          Package_Table.Init          (Tree.Shared.Packages);
1246
1247          --  Private part table
1248
1249          Temp_Files_Table.Init (Tree.Shared.Private_Part.Temp_Files);
1250
1251          Tree.Shared.Private_Part.Current_Source_Path_File := No_Path;
1252          Tree.Shared.Private_Part.Current_Object_Path_File := No_Path;
1253       end if;
1254
1255       Source_Paths_Htable.Reset    (Tree.Source_Paths_HT);
1256       Source_Files_Htable.Reset    (Tree.Source_Files_HT);
1257       Replaced_Source_HTable.Reset (Tree.Replaced_Sources);
1258
1259       Tree.Replaced_Source_Number := 0;
1260
1261       Reset_Units_In_Table (Tree.Units_HT);
1262       Free_List (Tree.Projects, Free_Project => True);
1263       Free_Units (Tree.Units_HT);
1264    end Reset;
1265
1266    -------------------------------------
1267    -- Set_Current_Object_Path_File_Of --
1268    -------------------------------------
1269
1270    procedure Set_Current_Object_Path_File_Of
1271      (Shared : Shared_Project_Tree_Data_Access;
1272       To     : Path_Name_Type)
1273    is
1274    begin
1275       Shared.Private_Part.Current_Object_Path_File := To;
1276    end Set_Current_Object_Path_File_Of;
1277
1278    -------------------------------------
1279    -- Set_Current_Source_Path_File_Of --
1280    -------------------------------------
1281
1282    procedure Set_Current_Source_Path_File_Of
1283      (Shared : Shared_Project_Tree_Data_Access;
1284       To     : Path_Name_Type)
1285    is
1286    begin
1287       Shared.Private_Part.Current_Source_Path_File := To;
1288    end Set_Current_Source_Path_File_Of;
1289
1290    -----------------------
1291    -- Set_Path_File_Var --
1292    -----------------------
1293
1294    procedure Set_Path_File_Var (Name : String; Value : String) is
1295       Host_Spec : String_Access := To_Host_File_Spec (Value);
1296    begin
1297       if Host_Spec = null then
1298          Prj.Com.Fail
1299            ("could not convert file name """ & Value & """ to host spec");
1300       else
1301          Setenv (Name, Host_Spec.all);
1302          Free (Host_Spec);
1303       end if;
1304    end Set_Path_File_Var;
1305
1306    -------------------
1307    -- Switches_Name --
1308    -------------------
1309
1310    function Switches_Name
1311      (Source_File_Name : File_Name_Type) return File_Name_Type
1312    is
1313    begin
1314       return Extend_Name (Source_File_Name, Switches_Dependency_Suffix);
1315    end Switches_Name;
1316
1317    -----------
1318    -- Value --
1319    -----------
1320
1321    function Value (Image : String) return Casing_Type is
1322    begin
1323       for Casing in The_Casing_Images'Range loop
1324          if To_Lower (Image) = To_Lower (The_Casing_Images (Casing).all) then
1325             return Casing;
1326          end if;
1327       end loop;
1328
1329       raise Constraint_Error;
1330    end Value;
1331
1332    ---------------------
1333    -- Has_Ada_Sources --
1334    ---------------------
1335
1336    function Has_Ada_Sources (Data : Project_Id) return Boolean is
1337       Lang : Language_Ptr;
1338
1339    begin
1340       Lang := Data.Languages;
1341       while Lang /= No_Language_Index loop
1342          if Lang.Name = Name_Ada then
1343             return Lang.First_Source /= No_Source;
1344          end if;
1345          Lang := Lang.Next;
1346       end loop;
1347
1348       return False;
1349    end Has_Ada_Sources;
1350
1351    ------------------------
1352    -- Contains_ALI_Files --
1353    ------------------------
1354
1355    function Contains_ALI_Files (Dir : Path_Name_Type) return Boolean is
1356       Dir_Name : constant String := Get_Name_String (Dir);
1357       Direct   : Dir_Type;
1358       Name     : String (1 .. 1_000);
1359       Last     : Natural;
1360       Result   : Boolean := False;
1361
1362    begin
1363       Open (Direct, Dir_Name);
1364
1365       --  For each file in the directory, check if it is an ALI file
1366
1367       loop
1368          Read (Direct, Name, Last);
1369          exit when Last = 0;
1370          Canonical_Case_File_Name (Name (1 .. Last));
1371          Result := Last >= 5 and then Name (Last - 3 .. Last) = ".ali";
1372          exit when Result;
1373       end loop;
1374
1375       Close (Direct);
1376       return Result;
1377
1378    exception
1379       --  If there is any problem, close the directory if open and return True.
1380       --  The library directory will be added to the path.
1381
1382       when others =>
1383          if Is_Open (Direct) then
1384             Close (Direct);
1385          end if;
1386
1387          return True;
1388    end Contains_ALI_Files;
1389
1390    --------------------------
1391    -- Get_Object_Directory --
1392    --------------------------
1393
1394    function Get_Object_Directory
1395      (Project             : Project_Id;
1396       Including_Libraries : Boolean;
1397       Only_If_Ada         : Boolean := False) return Path_Name_Type
1398    is
1399    begin
1400       if (Project.Library and then Including_Libraries)
1401         or else
1402           (Project.Object_Directory /= No_Path_Information
1403             and then (not Including_Libraries or else not Project.Library))
1404       then
1405          --  For a library project, add the library ALI directory if there is
1406          --  no object directory or if the library ALI directory contains ALI
1407          --  files; otherwise add the object directory.
1408
1409          if Project.Library then
1410             if Project.Object_Directory = No_Path_Information
1411               or else Contains_ALI_Files (Project.Library_ALI_Dir.Display_Name)
1412             then
1413                return Project.Library_ALI_Dir.Display_Name;
1414             else
1415                return Project.Object_Directory.Display_Name;
1416             end if;
1417
1418             --  For a non-library project, add object directory if it is not a
1419             --  virtual project, and if there are Ada sources in the project or
1420             --  one of the projects it extends. If there are no Ada sources,
1421             --  adding the object directory could disrupt the order of the
1422             --  object dirs in the path.
1423
1424          elsif not Project.Virtual then
1425             declare
1426                Add_Object_Dir : Boolean;
1427                Prj            : Project_Id;
1428
1429             begin
1430                Add_Object_Dir := not Only_If_Ada;
1431                Prj := Project;
1432                while not Add_Object_Dir and then Prj /= No_Project loop
1433                   if Has_Ada_Sources (Prj) then
1434                      Add_Object_Dir := True;
1435                   else
1436                      Prj := Prj.Extends;
1437                   end if;
1438                end loop;
1439
1440                if Add_Object_Dir then
1441                   return Project.Object_Directory.Display_Name;
1442                end if;
1443             end;
1444          end if;
1445       end if;
1446
1447       return No_Path;
1448    end Get_Object_Directory;
1449
1450    -----------------------------------
1451    -- Ultimate_Extending_Project_Of --
1452    -----------------------------------
1453
1454    function Ultimate_Extending_Project_Of
1455      (Proj : Project_Id) return Project_Id
1456    is
1457       Prj : Project_Id;
1458
1459    begin
1460       Prj := Proj;
1461       while Prj /= null and then Prj.Extended_By /= No_Project loop
1462          Prj := Prj.Extended_By;
1463       end loop;
1464
1465       return Prj;
1466    end Ultimate_Extending_Project_Of;
1467
1468    -----------------------------------
1469    -- Compute_All_Imported_Projects --
1470    -----------------------------------
1471
1472    procedure Compute_All_Imported_Projects
1473      (Root_Project : Project_Id;
1474       Tree         : Project_Tree_Ref)
1475    is
1476       procedure Analyze_Tree
1477         (Local_Root : Project_Id;
1478          Local_Tree : Project_Tree_Ref);
1479       --  Process Project and all its aggregated project to analyze their own
1480       --  imported projects.
1481
1482       ------------------
1483       -- Analyze_Tree --
1484       ------------------
1485
1486       procedure Analyze_Tree
1487         (Local_Root : Project_Id;
1488          Local_Tree : Project_Tree_Ref)
1489       is
1490          pragma Unreferenced (Local_Root);
1491
1492          Project : Project_Id;
1493
1494          procedure Recursive_Add
1495            (Prj     : Project_Id;
1496             Tree    : Project_Tree_Ref;
1497             Context : Project_Context;
1498             Dummy   : in out Boolean);
1499          --  Recursively add the projects imported by project Project, but not
1500          --  those that are extended.
1501
1502          -------------------
1503          -- Recursive_Add --
1504          -------------------
1505
1506          procedure Recursive_Add
1507            (Prj     : Project_Id;
1508             Tree    : Project_Tree_Ref;
1509             Context : Project_Context;
1510             Dummy   : in out Boolean)
1511          is
1512             pragma Unreferenced (Dummy, Tree);
1513
1514             List : Project_List;
1515             Prj2 : Project_Id;
1516
1517          begin
1518             --  A project is not importing itself
1519
1520             Prj2 := Ultimate_Extending_Project_Of (Prj);
1521
1522             if Project /= Prj2 then
1523
1524                --  Check that the project is not already in the list. We know
1525                --  the one passed to Recursive_Add have never been visited
1526                --  before, but the one passed it are the extended projects.
1527
1528                List := Project.All_Imported_Projects;
1529                while List /= null loop
1530                   if List.Project = Prj2 then
1531                      return;
1532                   end if;
1533
1534                   List := List.Next;
1535                end loop;
1536
1537                --  Add it to the list
1538
1539                Project.All_Imported_Projects :=
1540                  new Project_List_Element'
1541                    (Project               => Prj2,
1542                     From_Encapsulated_Lib => Context.From_Encapsulated_Lib,
1543                     Next                  => Project.All_Imported_Projects);
1544             end if;
1545          end Recursive_Add;
1546
1547          procedure For_All_Projects is
1548            new For_Every_Project_Imported_Context (Boolean, Recursive_Add);
1549
1550          Dummy : Boolean := False;
1551          List  : Project_List;
1552
1553       begin
1554          List := Local_Tree.Projects;
1555          while List /= null loop
1556             Project := List.Project;
1557             Free_List
1558               (Project.All_Imported_Projects, Free_Project => False);
1559             For_All_Projects
1560               (Project, Local_Tree, Dummy, Include_Aggregated => False);
1561             List := List.Next;
1562          end loop;
1563       end Analyze_Tree;
1564
1565       procedure For_Aggregates is
1566         new For_Project_And_Aggregated (Analyze_Tree);
1567
1568    --  Start of processing for Compute_All_Imported_Projects
1569
1570    begin
1571       For_Aggregates (Root_Project, Tree);
1572    end Compute_All_Imported_Projects;
1573
1574    -------------------
1575    -- Is_Compilable --
1576    -------------------
1577
1578    function Is_Compilable (Source : Source_Id) return Boolean is
1579    begin
1580       case Source.Compilable is
1581          when Unknown =>
1582             if Source.Language.Config.Compiler_Driver /= No_File
1583               and then
1584                 Length_Of_Name (Source.Language.Config.Compiler_Driver) /= 0
1585               and then not Source.Locally_Removed
1586               and then (Source.Language.Config.Kind /= File_Based
1587                          or else Source.Kind /= Spec)
1588             then
1589                --  Do not modify Source.Compilable before the source record
1590                --  has been initialized.
1591
1592                if Source.Source_TS /= Empty_Time_Stamp then
1593                   Source.Compilable := Yes;
1594                end if;
1595
1596                return True;
1597
1598             else
1599                if Source.Source_TS /= Empty_Time_Stamp then
1600                   Source.Compilable := No;
1601                end if;
1602
1603                return False;
1604             end if;
1605
1606          when Yes =>
1607             return True;
1608
1609          when No =>
1610             return False;
1611       end case;
1612    end Is_Compilable;
1613
1614    ------------------------------
1615    -- Object_To_Global_Archive --
1616    ------------------------------
1617
1618    function Object_To_Global_Archive (Source : Source_Id) return Boolean is
1619    begin
1620       return Source.Language.Config.Kind = File_Based
1621         and then Source.Kind = Impl
1622         and then Source.Language.Config.Objects_Linked
1623         and then Is_Compilable (Source)
1624         and then Source.Language.Config.Object_Generated;
1625    end Object_To_Global_Archive;
1626
1627    ----------------------------
1628    -- Get_Language_From_Name --
1629    ----------------------------
1630
1631    function Get_Language_From_Name
1632      (Project : Project_Id;
1633       Name    : String) return Language_Ptr
1634    is
1635       N      : Name_Id;
1636       Result : Language_Ptr;
1637
1638    begin
1639       Name_Len := Name'Length;
1640       Name_Buffer (1 .. Name_Len) := Name;
1641       To_Lower (Name_Buffer (1 .. Name_Len));
1642       N := Name_Find;
1643
1644       Result := Project.Languages;
1645       while Result /= No_Language_Index loop
1646          if Result.Name = N then
1647             return Result;
1648          end if;
1649
1650          Result := Result.Next;
1651       end loop;
1652
1653       return No_Language_Index;
1654    end Get_Language_From_Name;
1655
1656    ----------------
1657    -- Other_Part --
1658    ----------------
1659
1660    function Other_Part (Source : Source_Id) return Source_Id is
1661    begin
1662       if Source.Unit /= No_Unit_Index then
1663          case Source.Kind is
1664             when Impl =>
1665                return Source.Unit.File_Names (Spec);
1666             when Spec =>
1667                return Source.Unit.File_Names (Impl);
1668             when Sep =>
1669                return No_Source;
1670          end case;
1671       else
1672          return No_Source;
1673       end if;
1674    end Other_Part;
1675
1676    ------------------
1677    -- Create_Flags --
1678    ------------------
1679
1680    function Create_Flags
1681      (Report_Error               : Error_Handler;
1682       When_No_Sources            : Error_Warning;
1683       Require_Sources_Other_Lang : Boolean       := True;
1684       Allow_Duplicate_Basenames  : Boolean       := True;
1685       Compiler_Driver_Mandatory  : Boolean       := False;
1686       Error_On_Unknown_Language  : Boolean       := True;
1687       Require_Obj_Dirs           : Error_Warning := Error;
1688       Allow_Invalid_External     : Error_Warning := Error;
1689       Missing_Source_Files       : Error_Warning := Error;
1690       Ignore_Missing_With        : Boolean       := False)
1691       return Processing_Flags
1692    is
1693    begin
1694       return Processing_Flags'
1695         (Report_Error               => Report_Error,
1696          When_No_Sources            => When_No_Sources,
1697          Require_Sources_Other_Lang => Require_Sources_Other_Lang,
1698          Allow_Duplicate_Basenames  => Allow_Duplicate_Basenames,
1699          Error_On_Unknown_Language  => Error_On_Unknown_Language,
1700          Compiler_Driver_Mandatory  => Compiler_Driver_Mandatory,
1701          Require_Obj_Dirs           => Require_Obj_Dirs,
1702          Allow_Invalid_External     => Allow_Invalid_External,
1703          Missing_Source_Files       => Missing_Source_Files,
1704          Ignore_Missing_With        => Ignore_Missing_With);
1705    end Create_Flags;
1706
1707    ------------
1708    -- Length --
1709    ------------
1710
1711    function Length
1712      (Table : Name_List_Table.Instance;
1713       List  : Name_List_Index) return Natural
1714    is
1715       Count : Natural := 0;
1716       Tmp   : Name_List_Index;
1717
1718    begin
1719       Tmp := List;
1720       while Tmp /= No_Name_List loop
1721          Count := Count + 1;
1722          Tmp := Table.Table (Tmp).Next;
1723       end loop;
1724
1725       return Count;
1726    end Length;
1727
1728    ------------------
1729    -- Debug_Output --
1730    ------------------
1731
1732    procedure Debug_Output (Str : String) is
1733    begin
1734       if Current_Verbosity > Default then
1735          Set_Standard_Error;
1736          Write_Line ((1 .. Debug_Level * 2 => ' ') & Str);
1737          Set_Standard_Output;
1738       end if;
1739    end Debug_Output;
1740
1741    ------------------
1742    -- Debug_Indent --
1743    ------------------
1744
1745    procedure Debug_Indent is
1746    begin
1747       if Current_Verbosity = High then
1748          Set_Standard_Error;
1749          Write_Str ((1 .. Debug_Level * 2 => ' '));
1750          Set_Standard_Output;
1751       end if;
1752    end Debug_Indent;
1753
1754    ------------------
1755    -- Debug_Output --
1756    ------------------
1757
1758    procedure Debug_Output (Str : String; Str2 : Name_Id) is
1759    begin
1760       if Current_Verbosity = High then
1761          Debug_Indent;
1762          Set_Standard_Error;
1763          Write_Str (Str);
1764
1765          if Str2 = No_Name then
1766             Write_Line (" <no_name>");
1767          else
1768             Write_Line (" """ & Get_Name_String (Str2) & '"');
1769          end if;
1770
1771          Set_Standard_Output;
1772       end if;
1773    end Debug_Output;
1774
1775    ---------------------------
1776    -- Debug_Increase_Indent --
1777    ---------------------------
1778
1779    procedure Debug_Increase_Indent
1780      (Str : String := ""; Str2 : Name_Id := No_Name)
1781    is
1782    begin
1783       if Str2 /= No_Name then
1784          Debug_Output (Str, Str2);
1785       else
1786          Debug_Output (Str);
1787       end if;
1788       Debug_Level := Debug_Level + 1;
1789    end Debug_Increase_Indent;
1790
1791    ---------------------------
1792    -- Debug_Decrease_Indent --
1793    ---------------------------
1794
1795    procedure Debug_Decrease_Indent (Str : String := "") is
1796    begin
1797       if Debug_Level > 0 then
1798          Debug_Level := Debug_Level - 1;
1799       end if;
1800
1801       if Str /= "" then
1802          Debug_Output (Str);
1803       end if;
1804    end Debug_Decrease_Indent;
1805
1806    ----------------
1807    -- Debug_Name --
1808    ----------------
1809
1810    function Debug_Name (Tree : Project_Tree_Ref) return Name_Id is
1811       P : Project_List;
1812
1813    begin
1814       Name_Len := 0;
1815       Add_Str_To_Name_Buffer ("Tree [");
1816
1817       P := Tree.Projects;
1818       while P /= null loop
1819          if P /= Tree.Projects then
1820             Add_Char_To_Name_Buffer (',');
1821          end if;
1822
1823          Add_Str_To_Name_Buffer (Get_Name_String (P.Project.Name));
1824
1825          P := P.Next;
1826       end loop;
1827
1828       Add_Char_To_Name_Buffer (']');
1829
1830       return Name_Find;
1831    end Debug_Name;
1832
1833    ----------
1834    -- Free --
1835    ----------
1836
1837    procedure Free (Tree : in out Project_Tree_Appdata) is
1838       pragma Unreferenced (Tree);
1839    begin
1840       null;
1841    end Free;
1842
1843    --------------------------------
1844    -- For_Project_And_Aggregated --
1845    --------------------------------
1846
1847    procedure For_Project_And_Aggregated
1848      (Root_Project : Project_Id;
1849       Root_Tree    : Project_Tree_Ref)
1850    is
1851       Agg : Aggregated_Project_List;
1852
1853    begin
1854       Action (Root_Project, Root_Tree);
1855
1856       if Root_Project.Qualifier in Aggregate_Project then
1857          Agg := Root_Project.Aggregated_Projects;
1858          while Agg /= null loop
1859             For_Project_And_Aggregated (Agg.Project, Agg.Tree);
1860             Agg := Agg.Next;
1861          end loop;
1862       end if;
1863    end For_Project_And_Aggregated;
1864
1865 --  Package initialization for Prj
1866
1867 begin
1868    --  Make sure that the standard config and user project file extensions are
1869    --  compatible with canonical case file naming.
1870
1871    Canonical_Case_File_Name (Config_Project_File_Extension);
1872    Canonical_Case_File_Name (Project_File_Extension);
1873 end Prj;