OSDN Git Service

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