OSDN Git Service

2009-07-13 Robert Dewar <dewar@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / prj-env.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                              P R J . E N V                               --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 2001-2009, 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 Fmap;
27 with Opt;
28 with Osint;    use Osint;
29 with Output;   use Output;
30 with Prj.Com;  use Prj.Com;
31 with Tempdir;
32
33 package body Prj.Env is
34
35    -----------------------
36    -- Local Subprograms --
37    -----------------------
38
39    package Source_Path_Table is new GNAT.Dynamic_Tables
40      (Table_Component_Type => Name_Id,
41       Table_Index_Type     => Natural,
42       Table_Low_Bound      => 1,
43       Table_Initial        => 50,
44       Table_Increment      => 100);
45    --  A table to store the source dirs before creating the source path file
46
47    package Object_Path_Table is new GNAT.Dynamic_Tables
48      (Table_Component_Type => Path_Name_Type,
49       Table_Index_Type     => Natural,
50       Table_Low_Bound      => 1,
51       Table_Initial        => 50,
52       Table_Increment      => 100);
53    --  A table to store the object dirs, before creating the object path file
54
55    procedure Add_To_Path
56      (Source_Dirs : String_List_Id;
57       In_Tree     : Project_Tree_Ref;
58       Buffer      : in out String_Access;
59       Buffer_Last : in out Natural);
60    --  Add to Ada_Path_Buffer all the source directories in string list
61    --  Source_Dirs, if any.
62
63    procedure Add_To_Path
64      (Dir         : String;
65       Buffer      : in out String_Access;
66       Buffer_Last : in out Natural);
67    --  If Dir is not already in the global variable Ada_Path_Buffer, add it.
68    --  If Buffer_Last /= 0, prepend a Path_Separator character to Path.
69
70    procedure Add_To_Source_Path
71      (Source_Dirs  : String_List_Id;
72       In_Tree      : Project_Tree_Ref;
73       Source_Paths : in out Source_Path_Table.Instance);
74    --  Add to Ada_Path_B all the source directories in string list
75    --  Source_Dirs, if any. Increment Ada_Path_Length.
76
77    procedure Add_To_Object_Path
78      (Object_Dir   : Path_Name_Type;
79       Object_Paths : in out Object_Path_Table.Instance);
80    --  Add Object_Dir to object path table. Make sure it is not duplicate
81    --  and it is the last one in the current table.
82
83    procedure Set_Path_File_Var (Name : String; Value : String);
84    --  Call Setenv, after calling To_Host_File_Spec
85
86    function Ultimate_Extension_Of
87      (Project : Project_Id) return Project_Id;
88    --  Return a project that is either Project or an extended ancestor of
89    --  Project that itself is not extended.
90
91    procedure Create_Temp_File
92      (In_Tree   : Project_Tree_Ref;
93       Path_FD   : out File_Descriptor;
94       Path_Name : out Path_Name_Type;
95       File_Use  : String);
96    --  Create a temporary file, and fail with an error if it could not be
97    --  created.
98
99    ----------------------
100    -- Ada_Include_Path --
101    ----------------------
102
103    function Ada_Include_Path
104      (Project   : Project_Id;
105       In_Tree   : Project_Tree_Ref;
106       Recursive : Boolean := False) return String
107    is
108       Buffer      : String_Access;
109       Buffer_Last : Natural := 0;
110
111       procedure Add (Project : Project_Id; Dummy : in out Boolean);
112       --  Add source dirs of Project to the path
113
114       ---------
115       -- Add --
116       ---------
117
118       procedure Add (Project : Project_Id; Dummy : in out Boolean) is
119          pragma Unreferenced (Dummy);
120       begin
121          Add_To_Path (Project.Source_Dirs, In_Tree, Buffer, Buffer_Last);
122       end Add;
123
124       procedure For_All_Projects is
125         new For_Every_Project_Imported (Boolean, Add);
126
127       Dummy : Boolean := False;
128
129    --  Start of processing for Ada_Include_Path
130
131    begin
132       if Recursive then
133
134          --  If it is the first time we call this function for
135          --  this project, compute the source path
136
137          if Project.Ada_Include_Path = null then
138             Buffer := new String (1 .. 4096);
139             For_All_Projects (Project, Dummy);
140             Project.Ada_Include_Path := new String'(Buffer (1 .. Buffer_Last));
141             Free (Buffer);
142          end if;
143
144          return Project.Ada_Include_Path.all;
145
146       else
147          Buffer := new String (1 .. 4096);
148          Add_To_Path (Project.Source_Dirs, In_Tree, Buffer, Buffer_Last);
149
150          declare
151             Result : constant String := Buffer (1 .. Buffer_Last);
152          begin
153             Free (Buffer);
154             return Result;
155          end;
156       end if;
157    end Ada_Include_Path;
158
159    ----------------------
160    -- Ada_Objects_Path --
161    ----------------------
162
163    function Ada_Objects_Path
164      (Project             : Project_Id;
165       Including_Libraries : Boolean := True) return String_Access
166    is
167       Buffer      : String_Access;
168       Buffer_Last : Natural := 0;
169
170       procedure Add (Project : Project_Id; Dummy : in out Boolean);
171       --  Add all the object directories of a project to the path
172
173       ---------
174       -- Add --
175       ---------
176
177       procedure Add (Project : Project_Id; Dummy : in out Boolean) is
178          pragma Unreferenced (Dummy);
179          Path : constant Path_Name_Type :=
180                   Get_Object_Directory
181                     (Project,
182                      Including_Libraries => Including_Libraries,
183                      Only_If_Ada         => False);
184       begin
185          if Path /= No_Path then
186             Add_To_Path (Get_Name_String (Path), Buffer, Buffer_Last);
187          end if;
188       end Add;
189
190       procedure For_All_Projects is
191         new For_Every_Project_Imported (Boolean, Add);
192
193       Dummy : Boolean := False;
194
195    --  Start of processing for Ada_Objects_Path
196
197    begin
198       --  If it is the first time we call this function for
199       --  this project, compute the objects path
200
201       if Project.Ada_Objects_Path = null then
202          Buffer := new String (1 .. 4096);
203          For_All_Projects (Project, Dummy);
204
205          Project.Ada_Objects_Path := new String'(Buffer (1 .. Buffer_Last));
206          Free (Buffer);
207       end if;
208
209       return Project.Ada_Objects_Path;
210    end Ada_Objects_Path;
211
212    ------------------------
213    -- Add_To_Object_Path --
214    ------------------------
215
216    procedure Add_To_Object_Path
217      (Object_Dir   : Path_Name_Type;
218       Object_Paths : in out Object_Path_Table.Instance)
219    is
220    begin
221       --  Check if the directory is already in the table
222
223       for Index in Object_Path_Table.First ..
224                    Object_Path_Table.Last (Object_Paths)
225       loop
226
227          --  If it is, remove it, and add it as the last one
228
229          if Object_Paths.Table (Index) = Object_Dir then
230             for Index2 in Index + 1 ..
231                           Object_Path_Table.Last (Object_Paths)
232             loop
233                Object_Paths.Table (Index2 - 1) := Object_Paths.Table (Index2);
234             end loop;
235
236             Object_Paths.Table
237               (Object_Path_Table.Last (Object_Paths)) := Object_Dir;
238             return;
239          end if;
240       end loop;
241
242       --  The directory is not already in the table, add it
243
244       Object_Path_Table.Append (Object_Paths, Object_Dir);
245    end Add_To_Object_Path;
246
247    -----------------
248    -- Add_To_Path --
249    -----------------
250
251    procedure Add_To_Path
252      (Source_Dirs : String_List_Id;
253       In_Tree     : Project_Tree_Ref;
254       Buffer      : in out String_Access;
255       Buffer_Last : in out Natural)
256    is
257       Current    : String_List_Id := Source_Dirs;
258       Source_Dir : String_Element;
259    begin
260       while Current /= Nil_String loop
261          Source_Dir := In_Tree.String_Elements.Table (Current);
262          Add_To_Path (Get_Name_String (Source_Dir.Display_Value),
263                       Buffer, Buffer_Last);
264          Current := Source_Dir.Next;
265       end loop;
266    end Add_To_Path;
267
268    procedure Add_To_Path
269      (Dir         : String;
270       Buffer      : in out String_Access;
271       Buffer_Last : in out Natural)
272    is
273       Len        : Natural;
274       New_Buffer : String_Access;
275       Min_Len    : Natural;
276
277       function Is_Present (Path : String; Dir : String) return Boolean;
278       --  Return True if Dir is part of Path
279
280       ----------------
281       -- Is_Present --
282       ----------------
283
284       function Is_Present (Path : String; Dir : String) return Boolean is
285          Last : constant Integer := Path'Last - Dir'Length + 1;
286
287       begin
288          for J in Path'First .. Last loop
289
290             --  Note: the order of the conditions below is important, since
291             --  it ensures a minimal number of string comparisons.
292
293             if (J = Path'First
294                 or else Path (J - 1) = Path_Separator)
295               and then
296                 (J + Dir'Length > Path'Last
297                  or else Path (J + Dir'Length) = Path_Separator)
298               and then Dir = Path (J .. J + Dir'Length - 1)
299             then
300                return True;
301             end if;
302          end loop;
303
304          return False;
305       end Is_Present;
306
307    --  Start of processing for Add_To_Path
308
309    begin
310       if Is_Present (Buffer (1 .. Buffer_Last), Dir) then
311
312          --  Dir is already in the path, nothing to do
313
314          return;
315       end if;
316
317       Min_Len := Buffer_Last + Dir'Length;
318
319       if Buffer_Last > 0 then
320
321          --  Add 1 for the Path_Separator character
322
323          Min_Len := Min_Len + 1;
324       end if;
325
326       --  If Ada_Path_Buffer is too small, increase it
327
328       Len := Buffer'Last;
329
330       if Len < Min_Len then
331          loop
332             Len := Len * 2;
333             exit when Len >= Min_Len;
334          end loop;
335
336          New_Buffer := new String (1 .. Len);
337          New_Buffer (1 .. Buffer_Last) := Buffer (1 .. Buffer_Last);
338          Free (Buffer);
339          Buffer := New_Buffer;
340       end if;
341
342       if Buffer_Last > 0 then
343          Buffer_Last := Buffer_Last + 1;
344          Buffer (Buffer_Last) := Path_Separator;
345       end if;
346
347       Buffer (Buffer_Last + 1 .. Buffer_Last + Dir'Length) := Dir;
348       Buffer_Last := Buffer_Last + Dir'Length;
349    end Add_To_Path;
350
351    ------------------------
352    -- Add_To_Source_Path --
353    ------------------------
354
355    procedure Add_To_Source_Path
356      (Source_Dirs  : String_List_Id;
357       In_Tree      : Project_Tree_Ref;
358       Source_Paths : in out Source_Path_Table.Instance)
359    is
360       Current    : String_List_Id := Source_Dirs;
361       Source_Dir : String_Element;
362       Add_It     : Boolean;
363
364    begin
365       --  Add each source directory
366
367       while Current /= Nil_String loop
368          Source_Dir := In_Tree.String_Elements.Table (Current);
369          Add_It := True;
370
371          --  Check if the source directory is already in the table
372
373          for Index in Source_Path_Table.First ..
374                       Source_Path_Table.Last (Source_Paths)
375          loop
376             --  If it is already, no need to add it
377
378             if Source_Paths.Table (Index) = Source_Dir.Value then
379                Add_It := False;
380                exit;
381             end if;
382          end loop;
383
384          if Add_It then
385             Source_Path_Table.Append (Source_Paths, Source_Dir.Value);
386          end if;
387
388          --  Next source directory
389
390          Current := Source_Dir.Next;
391       end loop;
392    end Add_To_Source_Path;
393
394    --------------------------------
395    -- Create_Config_Pragmas_File --
396    --------------------------------
397
398    procedure Create_Config_Pragmas_File
399      (For_Project : Project_Id;
400       In_Tree     : Project_Tree_Ref)
401    is
402       type Naming_Id is new Nat;
403       package Naming_Table is new GNAT.Dynamic_Tables
404         (Table_Component_Type => Lang_Naming_Data,
405          Table_Index_Type     => Naming_Id,
406          Table_Low_Bound      => 1,
407          Table_Initial        => 5,
408          Table_Increment      => 100);
409       Default_Naming : constant Naming_Id := Naming_Table.First;
410       Namings        : Naming_Table.Instance;
411       --  Table storing the naming data for gnatmake/gprmake
412
413       File_Name : Path_Name_Type  := No_Path;
414       File      : File_Descriptor := Invalid_FD;
415
416       Current_Naming  : Naming_Id;
417       Iter            : Source_Iterator;
418       Source          : Source_Id;
419
420       Status : Boolean;
421       --  For call to Close
422
423       procedure Check (Project : Project_Id; State : in out Integer);
424       --  Recursive procedure that put in the config pragmas file any non
425       --  standard naming schemes, if it is not already in the file, then call
426       --  itself for any imported project.
427
428       procedure Check_Temp_File;
429       --  Check that a temporary file has been opened.
430       --  If not, create one, and put its name in the project data,
431       --  with the indication that it is a temporary file.
432
433       procedure Put (Source : Source_Id);
434       --  Put an SFN pragma in the temporary file
435
436       procedure Put (File : File_Descriptor; S : String);
437       procedure Put_Line (File : File_Descriptor; S : String);
438       --  Output procedures, analogous to normal Text_IO procs of same name
439
440       -----------
441       -- Check --
442       -----------
443
444       procedure Check (Project : Project_Id; State : in out Integer) is
445          pragma Unreferenced (State);
446          Lang   : constant Language_Ptr :=
447                     Get_Language_From_Name (Project, "ada");
448          Naming : Lang_Naming_Data;
449
450       begin
451          if Current_Verbosity = High then
452             Write_Str ("Checking project file """);
453             Write_Str (Namet.Get_Name_String (Project.Name));
454             Write_Str (""".");
455             Write_Eol;
456          end if;
457
458          if Lang = null then
459             if Current_Verbosity = High then
460                Write_Line ("   Languages does not contain Ada, nothing to do");
461             end if;
462
463             return;
464          end if;
465
466          Naming := Lang.Config.Naming_Data;
467
468          --  Is the naming scheme of this project one that we know?
469
470          Current_Naming := Default_Naming;
471          while Current_Naming <= Naming_Table.Last (Namings)
472            and then Namings.Table (Current_Naming).Dot_Replacement =
473                                                     Naming.Dot_Replacement
474            and then Namings.Table (Current_Naming).Casing =
475                                                     Naming.Casing
476            and then Namings.Table (Current_Naming).Separate_Suffix =
477                                                     Naming.Separate_Suffix
478          loop
479             Current_Naming := Current_Naming + 1;
480          end loop;
481
482          --  If we don't know it, add it
483
484          if Current_Naming > Naming_Table.Last (Namings) then
485             Naming_Table.Increment_Last (Namings);
486             Namings.Table (Naming_Table.Last (Namings)) := Naming;
487
488             --  We need a temporary file to be created
489
490             Check_Temp_File;
491
492             --  Put the SFN pragmas for the naming scheme
493
494             --  Spec
495
496             Put_Line
497               (File, "pragma Source_File_Name_Project");
498             Put_Line
499               (File, "  (Spec_File_Name  => ""*" &
500                Get_Name_String (Naming.Spec_Suffix) & """,");
501             Put_Line
502               (File, "   Casing          => " &
503                Image (Naming.Casing) & ",");
504             Put_Line
505               (File, "   Dot_Replacement => """ &
506                Get_Name_String (Naming.Dot_Replacement) & """);");
507
508             --  and body
509
510             Put_Line
511               (File, "pragma Source_File_Name_Project");
512             Put_Line
513               (File, "  (Body_File_Name  => ""*" &
514                Get_Name_String (Naming.Body_Suffix) & """,");
515             Put_Line
516               (File, "   Casing          => " &
517                Image (Naming.Casing) & ",");
518             Put_Line
519               (File, "   Dot_Replacement => """ &
520                Get_Name_String (Naming.Dot_Replacement) &
521                """);");
522
523             --  and maybe separate
524
525             if Naming.Body_Suffix /= Naming.Separate_Suffix then
526                Put_Line (File, "pragma Source_File_Name_Project");
527                Put_Line
528                  (File, "  (Subunit_File_Name  => ""*" &
529                   Get_Name_String (Naming.Separate_Suffix) & """,");
530                Put_Line
531                  (File, "   Casing          => " &
532                   Image (Naming.Casing) & ",");
533                Put_Line
534                  (File, "   Dot_Replacement => """ &
535                   Get_Name_String (Naming.Dot_Replacement) &
536                   """);");
537             end if;
538          end if;
539       end Check;
540
541       ---------------------
542       -- Check_Temp_File --
543       ---------------------
544
545       procedure Check_Temp_File is
546       begin
547          if File = Invalid_FD then
548             Create_Temp_File
549               (In_Tree, File, File_Name, "configuration pragmas");
550          end if;
551       end Check_Temp_File;
552
553       ---------
554       -- Put --
555       ---------
556
557       procedure Put (Source : Source_Id) is
558       begin
559          --  A temporary file needs to be open
560
561          Check_Temp_File;
562
563          --  Put the pragma SFN for the unit kind (spec or body)
564
565          Put (File, "pragma Source_File_Name_Project (");
566          Put (File, Namet.Get_Name_String (Source.Unit.Name));
567
568          if Source.Kind = Spec then
569             Put (File, ", Spec_File_Name => """);
570          else
571             Put (File, ", Body_File_Name => """);
572          end if;
573
574          Put (File, Namet.Get_Name_String (Source.File));
575          Put (File, """");
576
577          if Source.Index /= 0 then
578             Put (File, ", Index =>");
579             Put (File, Source.Index'Img);
580          end if;
581
582          Put_Line (File, ");");
583       end Put;
584
585       procedure Put (File : File_Descriptor; S : String) is
586          Last : Natural;
587
588       begin
589          Last := Write (File, S (S'First)'Address, S'Length);
590
591          if Last /= S'Length then
592             Prj.Com.Fail
593               ("Disk full when creating " & Get_Name_String (File_Name));
594          end if;
595
596          if Current_Verbosity = High then
597             Write_Str (S);
598          end if;
599       end Put;
600
601       --------------
602       -- Put_Line --
603       --------------
604
605       procedure Put_Line (File : File_Descriptor; S : String) is
606          S0   : String (1 .. S'Length + 1);
607          Last : Natural;
608
609       begin
610          --  Add an ASCII.LF to the string. As this config file is supposed to
611          --  be used only by the compiler, we don't care about the characters
612          --  for the end of line. In fact we could have put a space, but
613          --  it is more convenient to be able to read gnat.adc during
614          --  development, for which the ASCII.LF is fine.
615
616          S0 (1 .. S'Length) := S;
617          S0 (S0'Last) := ASCII.LF;
618          Last := Write (File, S0'Address, S0'Length);
619
620          if Last /= S'Length + 1 then
621             Prj.Com.Fail
622               ("Disk full when creating " & Get_Name_String (File_Name));
623          end if;
624
625          if Current_Verbosity = High then
626             Write_Line (S);
627          end if;
628       end Put_Line;
629
630       procedure Check_Imported_Projects is new For_Every_Project_Imported
631         (Integer, Check);
632       Dummy : Integer := 0;
633
634    --  Start of processing for Create_Config_Pragmas_File
635
636    begin
637       if not For_Project.Config_Checked then
638
639          Naming_Table.Init (Namings);
640
641          --  Check the naming schemes
642
643          Check_Imported_Projects (For_Project, Dummy, Imported_First => False);
644
645          --  Visit all the files and process those that need an SFN pragma
646
647          Iter := For_Each_Source (In_Tree, For_Project);
648          while Element (Iter) /= No_Source loop
649             Source := Element (Iter);
650
651             if Source.Index >= 1
652               and then not Source.Locally_Removed
653               and then Source.Unit /= null
654             then
655                Put (Source);
656             end if;
657
658             Next (Iter);
659          end loop;
660
661          --  If there are no non standard naming scheme, issue the GNAT
662          --  standard naming scheme. This will tell the compiler that
663          --  a project file is used and will forbid any pragma SFN.
664
665          if File = Invalid_FD then
666             Check_Temp_File;
667
668             Put_Line (File, "pragma Source_File_Name_Project");
669             Put_Line (File, "   (Spec_File_Name  => ""*.ads"",");
670             Put_Line (File, "    Dot_Replacement => ""-"",");
671             Put_Line (File, "    Casing          => lowercase);");
672
673             Put_Line (File, "pragma Source_File_Name_Project");
674             Put_Line (File, "   (Body_File_Name  => ""*.adb"",");
675             Put_Line (File, "    Dot_Replacement => ""-"",");
676             Put_Line (File, "    Casing          => lowercase);");
677          end if;
678
679          --  Close the temporary file
680
681          GNAT.OS_Lib.Close (File, Status);
682
683          if not Status then
684             Prj.Com.Fail
685               ("Disk full when creating " & Get_Name_String (File_Name));
686          end if;
687
688          if Opt.Verbose_Mode then
689             Write_Str ("Closing configuration file """);
690             Write_Str (Get_Name_String (File_Name));
691             Write_Line ("""");
692          end if;
693
694          For_Project.Config_File_Name := File_Name;
695          For_Project.Config_File_Temp := True;
696          For_Project.Config_Checked   := True;
697       end if;
698    end Create_Config_Pragmas_File;
699
700    --------------------
701    -- Create_Mapping --
702    --------------------
703
704    procedure Create_Mapping (In_Tree : Project_Tree_Ref) is
705       Data : Source_Id;
706       Iter : Source_Iterator;
707
708    begin
709       Fmap.Reset_Tables;
710
711       Iter := For_Each_Source (In_Tree);
712       loop
713          Data := Element (Iter);
714          exit when Data = No_Source;
715
716          if Data.Unit /= No_Unit_Index then
717             if Data.Locally_Removed then
718                Fmap.Add_Forbidden_File_Name (Data.File);
719             else
720                Fmap.Add_To_File_Map
721                  (Unit_Name => Unit_Name_Type (Data.Unit.Name),
722                   File_Name => Data.File,
723                   Path_Name => File_Name_Type (Data.Path.Name));
724             end if;
725          end if;
726
727          Next (Iter);
728       end loop;
729    end Create_Mapping;
730
731    -------------------------
732    -- Create_Mapping_File --
733    -------------------------
734
735    procedure Create_Mapping_File
736      (Project  : Project_Id;
737       Language : Name_Id;
738       In_Tree  : Project_Tree_Ref;
739       Name     : out Path_Name_Type)
740    is
741       File   : File_Descriptor := Invalid_FD;
742       Status : Boolean;
743
744       procedure Put_Name_Buffer;
745       --  Put the line contained in the Name_Buffer in the mapping file
746
747       procedure Process (Project : Project_Id; State : in out Integer);
748       --  Generate the mapping file for Project (not recursively)
749
750       ---------
751       -- Put --
752       ---------
753
754       procedure Put_Name_Buffer is
755          Last : Natural;
756
757       begin
758          Name_Len := Name_Len + 1;
759          Name_Buffer (Name_Len) := ASCII.LF;
760          Last := Write (File, Name_Buffer (1)'Address, Name_Len);
761
762          if Current_Verbosity = High then
763             Write_Str ("Mapping file: " & Name_Buffer (1 .. Name_Len));
764          end if;
765
766          if Last /= Name_Len then
767             Prj.Com.Fail ("Disk full, cannot write mapping file");
768          end if;
769       end Put_Name_Buffer;
770
771       -------------
772       -- Process --
773       -------------
774
775       procedure Process (Project : Project_Id; State : in out Integer) is
776          pragma Unreferenced (State);
777          Source : Source_Id;
778          Suffix : File_Name_Type;
779          Iter   : Source_Iterator;
780
781       begin
782          Iter := For_Each_Source (In_Tree, Project, Language => Language);
783
784          loop
785             Source := Prj.Element (Iter);
786             exit when Source = No_Source;
787
788             if Source.Replaced_By = No_Source
789               and then Source.Path.Name /= No_Path
790               and then
791                 (Source.Language.Config.Kind = File_Based
792                   or else Source.Unit /= No_Unit_Index)
793             then
794                if Source.Unit /= No_Unit_Index then
795                   Get_Name_String (Source.Unit.Name);
796
797                   if Source.Language.Config.Kind = Unit_Based then
798
799                      --  ??? Mapping_Spec_Suffix could be set in the case of
800                      --  gnatmake as well
801
802                      Add_Char_To_Name_Buffer ('%');
803
804                      if Source.Kind = Spec then
805                         Add_Char_To_Name_Buffer ('s');
806                      else
807                         Add_Char_To_Name_Buffer ('b');
808                      end if;
809
810                   else
811                      case Source.Kind is
812                         when Spec =>
813                            Suffix :=
814                              Source.Language.Config.Mapping_Spec_Suffix;
815                         when Impl | Sep =>
816                            Suffix :=
817                              Source.Language.Config.Mapping_Body_Suffix;
818                      end case;
819
820                      if Suffix /= No_File then
821                         Add_Str_To_Name_Buffer
822                           (Get_Name_String (Suffix));
823                      end if;
824                   end if;
825
826                   Put_Name_Buffer;
827                end if;
828
829                Get_Name_String (Source.File);
830                Put_Name_Buffer;
831
832                if Source.Locally_Removed then
833                   Name_Len := 1;
834                   Name_Buffer (1) := '/';
835                else
836                   Get_Name_String (Source.Path.Name);
837                end if;
838
839                Put_Name_Buffer;
840             end if;
841
842             Next (Iter);
843          end loop;
844       end Process;
845
846       procedure For_Every_Imported_Project is new
847         For_Every_Project_Imported (State => Integer, Action => Process);
848
849       Dummy : Integer := 0;
850
851    --  Start of processing for Create_Mapping_File
852
853    begin
854
855       --  Create the temporary file
856
857       Create_Temp_File (In_Tree, File, Name, "mapping");
858
859       For_Every_Imported_Project (Project, Dummy);
860       GNAT.OS_Lib.Close (File, Status);
861
862       if not Status then
863
864          --  We were able to create the temporary file, so there is no problem
865          --  of protection. However, we are not able to close it, so there must
866          --  be a capacity problem that we express using "disk full".
867
868          Prj.Com.Fail ("disk full, could not write mapping file");
869       end if;
870    end Create_Mapping_File;
871
872    ----------------------
873    -- Create_Temp_File --
874    ----------------------
875
876    procedure Create_Temp_File
877      (In_Tree   : Project_Tree_Ref;
878       Path_FD   : out File_Descriptor;
879       Path_Name : out Path_Name_Type;
880       File_Use  : String)
881    is
882    begin
883       Tempdir.Create_Temp_File (Path_FD, Path_Name);
884
885       if Path_Name /= No_Path then
886          if Current_Verbosity = High then
887             Write_Line ("Create temp file (" & File_Use & ") "
888                         & Get_Name_String (Path_Name));
889          end if;
890
891          Record_Temp_File (In_Tree, Path_Name);
892
893       else
894          Prj.Com.Fail
895            ("unable to create temporary " & File_Use & " file");
896       end if;
897    end Create_Temp_File;
898
899    --------------------------
900    -- Create_New_Path_File --
901    --------------------------
902
903    procedure Create_New_Path_File
904      (In_Tree   : Project_Tree_Ref;
905       Path_FD   : out File_Descriptor;
906       Path_Name : out Path_Name_Type)
907    is
908    begin
909       Create_Temp_File (In_Tree, Path_FD, Path_Name, "path file");
910    end Create_New_Path_File;
911
912    ------------------------------------
913    -- File_Name_Of_Library_Unit_Body --
914    ------------------------------------
915
916    function File_Name_Of_Library_Unit_Body
917      (Name              : String;
918       Project           : Project_Id;
919       In_Tree           : Project_Tree_Ref;
920       Main_Project_Only : Boolean := True;
921       Full_Path         : Boolean := False) return String
922    is
923       The_Project   : Project_Id := Project;
924       Original_Name : String := Name;
925
926       Lang   : constant Language_Ptr :=
927         Get_Language_From_Name (Project, "ada");
928
929       Unit              : Unit_Index;
930       The_Original_Name : Name_Id;
931       The_Spec_Name     : Name_Id;
932       The_Body_Name     : Name_Id;
933
934    begin
935       --  ??? Same block in Project_Of
936       Canonical_Case_File_Name (Original_Name);
937       Name_Len := Original_Name'Length;
938       Name_Buffer (1 .. Name_Len) := Original_Name;
939       The_Original_Name := Name_Find;
940
941       if Lang /= null then
942          declare
943             Naming : constant Lang_Naming_Data := Lang.Config.Naming_Data;
944             Extended_Spec_Name : String :=
945                                    Name & Namet.Get_Name_String
946                                             (Naming.Spec_Suffix);
947             Extended_Body_Name : String :=
948                                    Name & Namet.Get_Name_String
949                                             (Naming.Body_Suffix);
950
951          begin
952             Canonical_Case_File_Name (Extended_Spec_Name);
953             Name_Len := Extended_Spec_Name'Length;
954             Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
955             The_Spec_Name := Name_Find;
956
957             Canonical_Case_File_Name (Extended_Body_Name);
958             Name_Len := Extended_Body_Name'Length;
959             Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
960             The_Body_Name := Name_Find;
961          end;
962
963       else
964          Name_Len := Name'Length;
965          Name_Buffer (1 .. Name_Len) := Name;
966          Canonical_Case_File_Name (Name_Buffer);
967          The_Spec_Name := Name_Find;
968          The_Body_Name := The_Spec_Name;
969       end if;
970
971       if Current_Verbosity = High then
972          Write_Str  ("Looking for file name of """);
973          Write_Str  (Name);
974          Write_Char ('"');
975          Write_Eol;
976          Write_Str  ("   Extended Spec Name = """);
977          Write_Str  (Get_Name_String (The_Spec_Name));
978          Write_Char ('"');
979          Write_Eol;
980          Write_Str  ("   Extended Body Name = """);
981          Write_Str  (Get_Name_String (The_Body_Name));
982          Write_Char ('"');
983          Write_Eol;
984       end if;
985
986       --  For extending project, search in the extended project if the source
987       --  is not found. For non extending projects, this loop will be run only
988       --  once.
989
990       loop
991          --  Loop through units
992
993          Unit := Units_Htable.Get_First (In_Tree.Units_HT);
994          while Unit /= null loop
995             --  Check for body
996
997             if not Main_Project_Only
998               or else
999                 (Unit.File_Names (Impl) /= null
1000                  and then Unit.File_Names (Impl).Project = The_Project)
1001             then
1002                declare
1003                   Current_Name : File_Name_Type;
1004                begin
1005                   --  Case of a body present
1006
1007                   if Unit.File_Names (Impl) /= null then
1008                      Current_Name := Unit.File_Names (Impl).File;
1009
1010                      if Current_Verbosity = High then
1011                         Write_Str  ("   Comparing with """);
1012                         Write_Str  (Get_Name_String (Current_Name));
1013                         Write_Char ('"');
1014                         Write_Eol;
1015                      end if;
1016
1017                      --  If it has the name of the original name, return the
1018                      --  original name.
1019
1020                      if Unit.Name = The_Original_Name
1021                        or else
1022                          Current_Name = File_Name_Type (The_Original_Name)
1023                      then
1024                         if Current_Verbosity = High then
1025                            Write_Line ("   OK");
1026                         end if;
1027
1028                         if Full_Path then
1029                            return Get_Name_String
1030                              (Unit.File_Names (Impl).Path.Name);
1031
1032                         else
1033                            return Get_Name_String (Current_Name);
1034                         end if;
1035
1036                         --  If it has the name of the extended body name,
1037                         --  return the extended body name
1038
1039                      elsif Current_Name = File_Name_Type (The_Body_Name) then
1040                         if Current_Verbosity = High then
1041                            Write_Line ("   OK");
1042                         end if;
1043
1044                         if Full_Path then
1045                            return Get_Name_String
1046                              (Unit.File_Names (Impl).Path.Name);
1047
1048                         else
1049                            return Get_Name_String (The_Body_Name);
1050                         end if;
1051
1052                      else
1053                         if Current_Verbosity = High then
1054                            Write_Line ("   not good");
1055                         end if;
1056                      end if;
1057                   end if;
1058                end;
1059             end if;
1060
1061             --  Check for spec
1062
1063             if not Main_Project_Only
1064               or else
1065                 (Unit.File_Names (Spec) /= null
1066                  and then Unit.File_Names (Spec).Project =
1067                    The_Project)
1068             then
1069                declare
1070                   Current_Name : File_Name_Type;
1071
1072                begin
1073                   --  Case of spec present
1074
1075                   if Unit.File_Names (Spec) /= null then
1076                      Current_Name := Unit.File_Names (Spec).File;
1077                      if Current_Verbosity = High then
1078                         Write_Str  ("   Comparing with """);
1079                         Write_Str  (Get_Name_String (Current_Name));
1080                         Write_Char ('"');
1081                         Write_Eol;
1082                      end if;
1083
1084                      --  If name same as original name, return original name
1085
1086                      if Unit.Name = The_Original_Name
1087                        or else
1088                          Current_Name = File_Name_Type (The_Original_Name)
1089                      then
1090                         if Current_Verbosity = High then
1091                            Write_Line ("   OK");
1092                         end if;
1093
1094                         if Full_Path then
1095                            return Get_Name_String
1096                              (Unit.File_Names (Spec).Path.Name);
1097                         else
1098                            return Get_Name_String (Current_Name);
1099                         end if;
1100
1101                         --  If it has the same name as the extended spec name,
1102                         --  return the extended spec name.
1103
1104                      elsif Current_Name = File_Name_Type (The_Spec_Name) then
1105                         if Current_Verbosity = High then
1106                            Write_Line ("   OK");
1107                         end if;
1108
1109                         if Full_Path then
1110                            return Get_Name_String
1111                              (Unit.File_Names (Spec).Path.Name);
1112                         else
1113                            return Get_Name_String (The_Spec_Name);
1114                         end if;
1115
1116                      else
1117                         if Current_Verbosity = High then
1118                            Write_Line ("   not good");
1119                         end if;
1120                      end if;
1121                   end if;
1122                end;
1123             end if;
1124
1125             Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1126          end loop;
1127
1128          --  If we are not in an extending project, give up
1129
1130          exit when not Main_Project_Only
1131            or else The_Project.Extends = No_Project;
1132
1133          --  Otherwise, look in the project we are extending
1134
1135          The_Project := The_Project.Extends;
1136       end loop;
1137
1138       --  We don't know this file name, return an empty string
1139
1140       return "";
1141    end File_Name_Of_Library_Unit_Body;
1142
1143    -------------------------
1144    -- For_All_Object_Dirs --
1145    -------------------------
1146
1147    procedure For_All_Object_Dirs (Project : Project_Id) is
1148       procedure For_Project (Prj : Project_Id; Dummy : in out Integer);
1149       --  Get all object directories of Prj
1150
1151       -----------------
1152       -- For_Project --
1153       -----------------
1154
1155       procedure For_Project (Prj : Project_Id; Dummy : in out Integer) is
1156          pragma Unreferenced (Dummy);
1157       begin
1158          --  ??? Set_Ada_Paths has a different behavior for library project
1159          --  files, should we have the same ?
1160
1161          if Prj.Object_Directory /= No_Path_Information then
1162             Get_Name_String (Prj.Object_Directory.Display_Name);
1163             Action (Name_Buffer (1 .. Name_Len));
1164          end if;
1165       end For_Project;
1166
1167       procedure Get_Object_Dirs is
1168         new For_Every_Project_Imported (Integer, For_Project);
1169       Dummy : Integer := 1;
1170
1171    --  Start of processing for For_All_Object_Dirs
1172
1173    begin
1174       Get_Object_Dirs (Project, Dummy);
1175    end For_All_Object_Dirs;
1176
1177    -------------------------
1178    -- For_All_Source_Dirs --
1179    -------------------------
1180
1181    procedure For_All_Source_Dirs
1182      (Project : Project_Id;
1183       In_Tree : Project_Tree_Ref)
1184    is
1185       procedure For_Project (Prj : Project_Id; Dummy : in out Integer);
1186       --  Get all object directories of Prj
1187
1188       -----------------
1189       -- For_Project --
1190       -----------------
1191
1192       procedure For_Project (Prj : Project_Id; Dummy : in out Integer) is
1193          pragma Unreferenced (Dummy);
1194          Current    : String_List_Id := Prj.Source_Dirs;
1195          The_String : String_Element;
1196
1197       begin
1198          --  If there are Ada sources, call action with the name of every
1199          --  source directory.
1200
1201          if Has_Ada_Sources (Project) then
1202             while Current /= Nil_String loop
1203                The_String := In_Tree.String_Elements.Table (Current);
1204                Action (Get_Name_String (The_String.Display_Value));
1205                Current := The_String.Next;
1206             end loop;
1207          end if;
1208       end For_Project;
1209
1210       procedure Get_Source_Dirs is
1211         new For_Every_Project_Imported (Integer, For_Project);
1212       Dummy : Integer := 1;
1213
1214    --  Start of processing for For_All_Source_Dirs
1215
1216    begin
1217       Get_Source_Dirs (Project, Dummy);
1218    end For_All_Source_Dirs;
1219
1220    -------------------
1221    -- Get_Reference --
1222    -------------------
1223
1224    procedure Get_Reference
1225      (Source_File_Name : String;
1226       In_Tree          : Project_Tree_Ref;
1227       Project          : out Project_Id;
1228       Path             : out Path_Name_Type)
1229    is
1230    begin
1231       --  Body below could use some comments ???
1232
1233       if Current_Verbosity > Default then
1234          Write_Str ("Getting Reference_Of (""");
1235          Write_Str (Source_File_Name);
1236          Write_Str (""") ... ");
1237       end if;
1238
1239       declare
1240          Original_Name : String := Source_File_Name;
1241          Unit          : Unit_Index;
1242
1243       begin
1244          Canonical_Case_File_Name (Original_Name);
1245          Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1246
1247          while Unit /= null loop
1248             if Unit.File_Names (Spec) /= null
1249               and then Unit.File_Names (Spec).File /= No_File
1250               and then
1251                 (Namet.Get_Name_String
1252                      (Unit.File_Names (Spec).File) = Original_Name
1253                  or else (Unit.File_Names (Spec).Path /=
1254                             No_Path_Information
1255                           and then
1256                             Namet.Get_Name_String
1257                               (Unit.File_Names (Spec).Path.Name) =
1258                             Original_Name))
1259             then
1260                Project := Ultimate_Extension_Of
1261                           (Project => Unit.File_Names (Spec).Project);
1262                Path := Unit.File_Names (Spec).Path.Display_Name;
1263
1264                if Current_Verbosity > Default then
1265                   Write_Str ("Done: Spec.");
1266                   Write_Eol;
1267                end if;
1268
1269                return;
1270
1271             elsif Unit.File_Names (Impl) /= null
1272               and then Unit.File_Names (Impl).File /= No_File
1273               and then
1274                 (Namet.Get_Name_String
1275                    (Unit.File_Names (Impl).File) = Original_Name
1276                  or else (Unit.File_Names (Impl).Path /=
1277                             No_Path_Information
1278                           and then Namet.Get_Name_String
1279                             (Unit.File_Names (Impl).Path.Name) =
1280                             Original_Name))
1281             then
1282                Project := Ultimate_Extension_Of
1283                             (Project => Unit.File_Names (Impl).Project);
1284                Path := Unit.File_Names (Impl).Path.Display_Name;
1285
1286                if Current_Verbosity > Default then
1287                   Write_Str ("Done: Body.");
1288                   Write_Eol;
1289                end if;
1290
1291                return;
1292             end if;
1293
1294             Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1295          end loop;
1296       end;
1297
1298       Project := No_Project;
1299       Path    := No_Path;
1300
1301       if Current_Verbosity > Default then
1302          Write_Str ("Cannot be found.");
1303          Write_Eol;
1304       end if;
1305    end Get_Reference;
1306
1307    ----------------
1308    -- Initialize --
1309    ----------------
1310
1311    procedure Initialize (In_Tree : Project_Tree_Ref) is
1312    begin
1313       In_Tree.Private_Part.Current_Source_Path_File := No_Path;
1314       In_Tree.Private_Part.Current_Object_Path_File := No_Path;
1315    end Initialize;
1316
1317    -------------------
1318    -- Print_Sources --
1319    -------------------
1320
1321    --  Could use some comments in this body ???
1322
1323    procedure Print_Sources (In_Tree : Project_Tree_Ref) is
1324       Unit : Unit_Index;
1325
1326    begin
1327       Write_Line ("List of Sources:");
1328
1329       Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1330
1331       while Unit /= No_Unit_Index loop
1332          Write_Str  ("   ");
1333          Write_Line (Namet.Get_Name_String (Unit.Name));
1334
1335          if Unit.File_Names (Spec).File /= No_File then
1336             if Unit.File_Names (Spec).Project = No_Project then
1337                Write_Line ("   No project");
1338
1339             else
1340                Write_Str  ("   Project: ");
1341                Get_Name_String
1342                  (Unit.File_Names (Spec).Project.Path.Name);
1343                Write_Line (Name_Buffer (1 .. Name_Len));
1344             end if;
1345
1346             Write_Str  ("      spec: ");
1347             Write_Line
1348               (Namet.Get_Name_String
1349                (Unit.File_Names (Spec).File));
1350          end if;
1351
1352          if Unit.File_Names (Impl).File /= No_File then
1353             if Unit.File_Names (Impl).Project = No_Project then
1354                Write_Line ("   No project");
1355
1356             else
1357                Write_Str  ("   Project: ");
1358                Get_Name_String
1359                  (Unit.File_Names (Impl).Project.Path.Name);
1360                Write_Line (Name_Buffer (1 .. Name_Len));
1361             end if;
1362
1363             Write_Str  ("      body: ");
1364             Write_Line
1365               (Namet.Get_Name_String (Unit.File_Names (Impl).File));
1366          end if;
1367
1368          Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1369       end loop;
1370
1371       Write_Line ("end of List of Sources.");
1372    end Print_Sources;
1373
1374    ----------------
1375    -- Project_Of --
1376    ----------------
1377
1378    function Project_Of
1379      (Name         : String;
1380       Main_Project : Project_Id;
1381       In_Tree      : Project_Tree_Ref) return Project_Id
1382    is
1383       Result : Project_Id := No_Project;
1384
1385       Original_Name : String := Name;
1386
1387       Lang : constant Language_Ptr :=
1388                Get_Language_From_Name (Main_Project, "ada");
1389
1390       Unit : Unit_Index;
1391
1392       Current_Name      : File_Name_Type;
1393       The_Original_Name : File_Name_Type;
1394       The_Spec_Name     : File_Name_Type;
1395       The_Body_Name     : File_Name_Type;
1396
1397    begin
1398       --  ??? Same block in File_Name_Of_Library_Unit_Body
1399       Canonical_Case_File_Name (Original_Name);
1400       Name_Len := Original_Name'Length;
1401       Name_Buffer (1 .. Name_Len) := Original_Name;
1402       The_Original_Name := Name_Find;
1403
1404       if Lang /= null then
1405          declare
1406             Naming : Lang_Naming_Data renames Lang.Config.Naming_Data;
1407             Extended_Spec_Name : String :=
1408                                    Name & Namet.Get_Name_String
1409                                             (Naming.Spec_Suffix);
1410             Extended_Body_Name : String :=
1411                                    Name & Namet.Get_Name_String
1412                                             (Naming.Body_Suffix);
1413
1414          begin
1415             Canonical_Case_File_Name (Extended_Spec_Name);
1416             Name_Len := Extended_Spec_Name'Length;
1417             Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1418             The_Spec_Name := Name_Find;
1419
1420             Canonical_Case_File_Name (Extended_Body_Name);
1421             Name_Len := Extended_Body_Name'Length;
1422             Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1423             The_Body_Name := Name_Find;
1424          end;
1425
1426       else
1427          The_Spec_Name := The_Original_Name;
1428          The_Body_Name := The_Original_Name;
1429       end if;
1430
1431       Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1432       while Unit /= null loop
1433
1434          --  Case of a body present
1435
1436          if Unit.File_Names (Impl) /= null then
1437             Current_Name := Unit.File_Names (Impl).File;
1438
1439             --  If it has the name of the original name or the body name,
1440             --  we have found the project.
1441
1442             if Unit.Name = Name_Id (The_Original_Name)
1443               or else Current_Name = The_Original_Name
1444               or else Current_Name = The_Body_Name
1445             then
1446                Result := Unit.File_Names (Impl).Project;
1447                exit;
1448             end if;
1449          end if;
1450
1451          --  Check for spec
1452
1453          if Unit.File_Names (Spec) /= null then
1454             Current_Name := Unit.File_Names (Spec).File;
1455
1456             --  If name same as the original name, or the spec name, we have
1457             --  found the project.
1458
1459             if Unit.Name = Name_Id (The_Original_Name)
1460               or else Current_Name = The_Original_Name
1461               or else Current_Name = The_Spec_Name
1462             then
1463                Result := Unit.File_Names (Spec).Project;
1464                exit;
1465             end if;
1466          end if;
1467
1468          Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1469       end loop;
1470
1471       --  Get the ultimate extending project
1472
1473       if Result /= No_Project then
1474          while Result.Extended_By /= No_Project loop
1475             Result := Result.Extended_By;
1476          end loop;
1477       end if;
1478
1479       return Result;
1480    end Project_Of;
1481
1482    -------------------
1483    -- Set_Ada_Paths --
1484    -------------------
1485
1486    procedure Set_Ada_Paths
1487      (Project             : Project_Id;
1488       In_Tree             : Project_Tree_Ref;
1489       Including_Libraries : Boolean)
1490
1491    is
1492       Source_Paths : Source_Path_Table.Instance;
1493       Object_Paths : Object_Path_Table.Instance;
1494       --  List of source or object dirs. Only computed the first time this
1495       --  procedure is called (since Source_FD is then reused)
1496
1497       Source_FD : File_Descriptor := Invalid_FD;
1498       Object_FD : File_Descriptor := Invalid_FD;
1499       --  The temporary files to store the paths. These are only created the
1500       --  first time this procedure is called, and reused from then on.
1501
1502       Process_Source_Dirs : Boolean := False;
1503       Process_Object_Dirs : Boolean := False;
1504
1505       Status : Boolean;
1506       --  For calls to Close
1507
1508       Len : Natural;
1509
1510       procedure Recursive_Add (Project : Project_Id; Dummy : in out Boolean);
1511       --  Recursive procedure to add the source/object paths of extended/
1512       --  imported projects.
1513
1514       -------------------
1515       -- Recursive_Add --
1516       -------------------
1517
1518       procedure Recursive_Add (Project : Project_Id; Dummy : in out Boolean) is
1519          pragma Unreferenced (Dummy);
1520
1521          Path : Path_Name_Type;
1522
1523       begin
1524          --  ??? This is almost the equivalent of For_All_Source_Dirs
1525
1526          if Process_Source_Dirs then
1527
1528             --  Add to path all source directories of this project if there are
1529             --  Ada sources.
1530
1531             if Has_Ada_Sources (Project) then
1532                Add_To_Source_Path (Project.Source_Dirs, In_Tree, Source_Paths);
1533             end if;
1534          end if;
1535
1536          if Process_Object_Dirs then
1537             Path := Get_Object_Directory
1538               (Project,
1539                Including_Libraries => Including_Libraries,
1540                Only_If_Ada         => True);
1541
1542             if Path /= No_Path then
1543                Add_To_Object_Path (Path, Object_Paths);
1544             end if;
1545          end if;
1546       end Recursive_Add;
1547
1548       procedure For_All_Projects is
1549         new For_Every_Project_Imported (Boolean, Recursive_Add);
1550       Dummy : Boolean := False;
1551
1552    --  Start of processing for Set_Ada_Paths
1553
1554    begin
1555       --  If it is the first time we call this procedure for this project,
1556       --  compute the source path and/or the object path.
1557
1558       if Project.Include_Path_File = No_Path then
1559          Source_Path_Table.Init (Source_Paths);
1560          Process_Source_Dirs := True;
1561          Create_New_Path_File
1562            (In_Tree, Source_FD, Project.Include_Path_File);
1563       end if;
1564
1565       --  For the object path, we make a distinction depending on
1566       --  Including_Libraries.
1567
1568       if Including_Libraries then
1569          if Project.Objects_Path_File_With_Libs = No_Path then
1570             Object_Path_Table.Init (Object_Paths);
1571             Process_Object_Dirs := True;
1572             Create_New_Path_File
1573               (In_Tree, Object_FD, Project.Objects_Path_File_With_Libs);
1574          end if;
1575
1576       else
1577          if Project.Objects_Path_File_Without_Libs = No_Path then
1578             Object_Path_Table.Init (Object_Paths);
1579             Process_Object_Dirs := True;
1580             Create_New_Path_File
1581               (In_Tree, Object_FD, Project.Objects_Path_File_Without_Libs);
1582          end if;
1583       end if;
1584
1585       --  If there is something to do, set Seen to False for all projects,
1586       --  then call the recursive procedure Add for Project.
1587
1588       if Process_Source_Dirs or Process_Object_Dirs then
1589          For_All_Projects (Project, Dummy);
1590       end if;
1591
1592       --  Write and close any file that has been created. Source_FD is not set
1593       --  when this subprogram is called a second time or more, since we reuse
1594       --  the previous version of the file.
1595
1596       if Source_FD /= Invalid_FD then
1597          for Index in Source_Path_Table.First ..
1598                       Source_Path_Table.Last (Source_Paths)
1599          loop
1600             Get_Name_String (Source_Paths.Table (Index));
1601             Name_Len := Name_Len + 1;
1602             Name_Buffer (Name_Len) := ASCII.LF;
1603             Len := Write (Source_FD, Name_Buffer (1)'Address, Name_Len);
1604
1605             if Len /= Name_Len then
1606                Prj.Com.Fail ("disk full");
1607             end if;
1608          end loop;
1609
1610          Close (Source_FD, Status);
1611
1612          if not Status then
1613             Prj.Com.Fail ("disk full");
1614          end if;
1615       end if;
1616
1617       if Object_FD /= Invalid_FD then
1618          for Index in Object_Path_Table.First ..
1619                       Object_Path_Table.Last (Object_Paths)
1620          loop
1621             Get_Name_String (Object_Paths.Table (Index));
1622             Name_Len := Name_Len + 1;
1623             Name_Buffer (Name_Len) := ASCII.LF;
1624             Len := Write (Object_FD, Name_Buffer (1)'Address, Name_Len);
1625
1626             if Len /= Name_Len then
1627                Prj.Com.Fail ("disk full");
1628             end if;
1629          end loop;
1630
1631          Close (Object_FD, Status);
1632
1633          if not Status then
1634             Prj.Com.Fail ("disk full");
1635          end if;
1636       end if;
1637
1638       --  Set the env vars, if they need to be changed, and set the
1639       --  corresponding flags.
1640
1641       if In_Tree.Private_Part.Current_Source_Path_File /=
1642            Project.Include_Path_File
1643       then
1644          In_Tree.Private_Part.Current_Source_Path_File :=
1645            Project.Include_Path_File;
1646          Set_Path_File_Var
1647            (Project_Include_Path_File,
1648             Get_Name_String (In_Tree.Private_Part.Current_Source_Path_File));
1649       end if;
1650
1651       if Including_Libraries then
1652          if In_Tree.Private_Part.Current_Object_Path_File /=
1653             Project.Objects_Path_File_With_Libs
1654          then
1655             In_Tree.Private_Part.Current_Object_Path_File :=
1656               Project.Objects_Path_File_With_Libs;
1657             Set_Path_File_Var
1658               (Project_Objects_Path_File,
1659                Get_Name_String
1660                  (In_Tree.Private_Part.Current_Object_Path_File));
1661          end if;
1662
1663       else
1664          if In_Tree.Private_Part.Current_Object_Path_File /=
1665             Project.Objects_Path_File_Without_Libs
1666          then
1667             In_Tree.Private_Part.Current_Object_Path_File :=
1668               Project.Objects_Path_File_Without_Libs;
1669             Set_Path_File_Var
1670               (Project_Objects_Path_File,
1671                Get_Name_String
1672                  (In_Tree.Private_Part.Current_Object_Path_File));
1673          end if;
1674       end if;
1675    end Set_Ada_Paths;
1676
1677    -----------------------
1678    -- Set_Path_File_Var --
1679    -----------------------
1680
1681    procedure Set_Path_File_Var (Name : String; Value : String) is
1682       Host_Spec : String_Access := To_Host_File_Spec (Value);
1683    begin
1684       if Host_Spec = null then
1685          Prj.Com.Fail
1686            ("could not convert file name """ & Value & """ to host spec");
1687       else
1688          Setenv (Name, Host_Spec.all);
1689          Free (Host_Spec);
1690       end if;
1691    end Set_Path_File_Var;
1692
1693    ---------------------------
1694    -- Ultimate_Extension_Of --
1695    ---------------------------
1696
1697    function Ultimate_Extension_Of
1698      (Project : Project_Id) return Project_Id
1699    is
1700       Result : Project_Id;
1701
1702    begin
1703       Result := Project;
1704       while Result.Extended_By /= No_Project loop
1705          Result := Result.Extended_By;
1706       end loop;
1707
1708       return Result;
1709    end Ultimate_Extension_Of;
1710
1711 end Prj.Env;