gcc/
[official-gcc.git] / gcc / ada / prj-env.adb
blob0bb0eb192aa87bdfc93c78bd356330a17b62b868
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-2013, 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 ------------------------------------------------------------------------------
26 with Fmap;
27 with Hostparm;
28 with Makeutl; use Makeutl;
29 with Opt;
30 with Osint; use Osint;
31 with Output; use Output;
32 with Prj.Com; use Prj.Com;
33 with Sdefault;
34 with Tempdir;
36 with Ada.Text_IO; use Ada.Text_IO;
38 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
40 package body Prj.Env is
42 Buffer_Initial : constant := 1_000;
43 -- Initial arbitrary size of buffers
45 Uninitialized_Prefix : constant String := '#' & Path_Separator;
46 -- Prefix to indicate that the project path has not been initialized yet.
47 -- Must be two characters long
49 No_Project_Default_Dir : constant String := "-";
50 -- Indicator in the project path to indicate that the default search
51 -- directories should not be added to the path
53 -----------------------
54 -- Local Subprograms --
55 -----------------------
57 package Source_Path_Table is new GNAT.Dynamic_Tables
58 (Table_Component_Type => Name_Id,
59 Table_Index_Type => Natural,
60 Table_Low_Bound => 1,
61 Table_Initial => 50,
62 Table_Increment => 100);
63 -- A table to store the source dirs before creating the source path file
65 package Object_Path_Table is new GNAT.Dynamic_Tables
66 (Table_Component_Type => Path_Name_Type,
67 Table_Index_Type => Natural,
68 Table_Low_Bound => 1,
69 Table_Initial => 50,
70 Table_Increment => 100);
71 -- A table to store the object dirs, before creating the object path file
73 procedure Add_To_Buffer
74 (S : String;
75 Buffer : in out String_Access;
76 Buffer_Last : in out Natural);
77 -- Add a string to Buffer, extending Buffer if needed
79 procedure Add_To_Path
80 (Source_Dirs : String_List_Id;
81 Shared : Shared_Project_Tree_Data_Access;
82 Buffer : in out String_Access;
83 Buffer_Last : in out Natural);
84 -- Add to Ada_Path_Buffer all the source directories in string list
85 -- Source_Dirs, if any.
87 procedure Add_To_Path
88 (Dir : String;
89 Buffer : in out String_Access;
90 Buffer_Last : in out Natural);
91 -- If Dir is not already in the global variable Ada_Path_Buffer, add it.
92 -- If Buffer_Last /= 0, prepend a Path_Separator character to Path.
94 procedure Add_To_Source_Path
95 (Source_Dirs : String_List_Id;
96 Shared : Shared_Project_Tree_Data_Access;
97 Source_Paths : in out Source_Path_Table.Instance);
98 -- Add to Ada_Path_B all the source directories in string list
99 -- Source_Dirs, if any. Increment Ada_Path_Length.
101 procedure Add_To_Object_Path
102 (Object_Dir : Path_Name_Type;
103 Object_Paths : in out Object_Path_Table.Instance);
104 -- Add Object_Dir to object path table. Make sure it is not duplicate
105 -- and it is the last one in the current table.
107 ----------------------
108 -- Ada_Include_Path --
109 ----------------------
111 function Ada_Include_Path
112 (Project : Project_Id;
113 In_Tree : Project_Tree_Ref;
114 Recursive : Boolean := False) return String
116 Buffer : String_Access;
117 Buffer_Last : Natural := 0;
119 procedure Add
120 (Project : Project_Id;
121 In_Tree : Project_Tree_Ref;
122 Dummy : in out Boolean);
123 -- Add source dirs of Project to the path
125 ---------
126 -- Add --
127 ---------
129 procedure Add
130 (Project : Project_Id;
131 In_Tree : Project_Tree_Ref;
132 Dummy : in out Boolean)
134 pragma Unreferenced (Dummy);
135 begin
136 Add_To_Path
137 (Project.Source_Dirs, In_Tree.Shared, Buffer, Buffer_Last);
138 end Add;
140 procedure For_All_Projects is
141 new For_Every_Project_Imported (Boolean, Add);
143 Dummy : Boolean := False;
145 -- Start of processing for Ada_Include_Path
147 begin
148 if Recursive then
150 -- If it is the first time we call this function for this project,
151 -- compute the source path.
153 if Project.Ada_Include_Path = null then
154 Buffer := new String (1 .. Buffer_Initial);
155 For_All_Projects
156 (Project, In_Tree, Dummy, Include_Aggregated => True);
157 Project.Ada_Include_Path := new String'(Buffer (1 .. Buffer_Last));
158 Free (Buffer);
159 end if;
161 return Project.Ada_Include_Path.all;
163 else
164 Buffer := new String (1 .. Buffer_Initial);
165 Add_To_Path
166 (Project.Source_Dirs, In_Tree.Shared, Buffer, Buffer_Last);
168 declare
169 Result : constant String := Buffer (1 .. Buffer_Last);
170 begin
171 Free (Buffer);
172 return Result;
173 end;
174 end if;
175 end Ada_Include_Path;
177 ----------------------
178 -- Ada_Objects_Path --
179 ----------------------
181 function Ada_Objects_Path
182 (Project : Project_Id;
183 In_Tree : Project_Tree_Ref;
184 Including_Libraries : Boolean := True) return String_Access
186 Buffer : String_Access;
187 Buffer_Last : Natural := 0;
189 procedure Add
190 (Project : Project_Id;
191 In_Tree : Project_Tree_Ref;
192 Dummy : in out Boolean);
193 -- Add all the object directories of a project to the path
195 ---------
196 -- Add --
197 ---------
199 procedure Add
200 (Project : Project_Id;
201 In_Tree : Project_Tree_Ref;
202 Dummy : in out Boolean)
204 pragma Unreferenced (Dummy, In_Tree);
206 Path : constant Path_Name_Type :=
207 Get_Object_Directory
208 (Project,
209 Including_Libraries => Including_Libraries,
210 Only_If_Ada => False);
211 begin
212 if Path /= No_Path then
213 Add_To_Path (Get_Name_String (Path), Buffer, Buffer_Last);
214 end if;
215 end Add;
217 procedure For_All_Projects is
218 new For_Every_Project_Imported (Boolean, Add);
220 Dummy : Boolean := False;
222 Result : String_Access;
224 -- Start of processing for Ada_Objects_Path
226 begin
227 -- If it is the first time we call this function for
228 -- this project, compute the objects path
230 if Including_Libraries and then Project.Ada_Objects_Path /= null then
231 return Project.Ada_Objects_Path;
233 elsif not Including_Libraries
234 and then Project.Ada_Objects_Path_No_Libs /= null
235 then
236 return Project.Ada_Objects_Path_No_Libs;
238 else
239 Buffer := new String (1 .. Buffer_Initial);
240 For_All_Projects (Project, In_Tree, Dummy);
241 Result := new String'(Buffer (1 .. Buffer_Last));
242 Free (Buffer);
244 if Including_Libraries then
245 Project.Ada_Objects_Path := Result;
246 else
247 Project.Ada_Objects_Path_No_Libs := Result;
248 end if;
250 return Result;
251 end if;
252 end Ada_Objects_Path;
254 -------------------
255 -- Add_To_Buffer --
256 -------------------
258 procedure Add_To_Buffer
259 (S : String;
260 Buffer : in out String_Access;
261 Buffer_Last : in out Natural)
263 Last : constant Natural := Buffer_Last + S'Length;
265 begin
266 while Last > Buffer'Last loop
267 declare
268 New_Buffer : constant String_Access :=
269 new String (1 .. 2 * Buffer'Last);
270 begin
271 New_Buffer (1 .. Buffer_Last) := Buffer (1 .. Buffer_Last);
272 Free (Buffer);
273 Buffer := New_Buffer;
274 end;
275 end loop;
277 Buffer (Buffer_Last + 1 .. Last) := S;
278 Buffer_Last := Last;
279 end Add_To_Buffer;
281 ------------------------
282 -- Add_To_Object_Path --
283 ------------------------
285 procedure Add_To_Object_Path
286 (Object_Dir : Path_Name_Type;
287 Object_Paths : in out Object_Path_Table.Instance)
289 begin
290 -- Check if the directory is already in the table
292 for Index in
293 Object_Path_Table.First .. Object_Path_Table.Last (Object_Paths)
294 loop
295 -- If it is, remove it, and add it as the last one
297 if Object_Paths.Table (Index) = Object_Dir then
298 for Index2 in
299 Index + 1 .. Object_Path_Table.Last (Object_Paths)
300 loop
301 Object_Paths.Table (Index2 - 1) := Object_Paths.Table (Index2);
302 end loop;
304 Object_Paths.Table
305 (Object_Path_Table.Last (Object_Paths)) := Object_Dir;
306 return;
307 end if;
308 end loop;
310 -- The directory is not already in the table, add it
312 Object_Path_Table.Append (Object_Paths, Object_Dir);
313 end Add_To_Object_Path;
315 -----------------
316 -- Add_To_Path --
317 -----------------
319 procedure Add_To_Path
320 (Source_Dirs : String_List_Id;
321 Shared : Shared_Project_Tree_Data_Access;
322 Buffer : in out String_Access;
323 Buffer_Last : in out Natural)
325 Current : String_List_Id;
326 Source_Dir : String_Element;
327 begin
328 Current := Source_Dirs;
329 while Current /= Nil_String loop
330 Source_Dir := Shared.String_Elements.Table (Current);
331 Add_To_Path (Get_Name_String (Source_Dir.Display_Value),
332 Buffer, Buffer_Last);
333 Current := Source_Dir.Next;
334 end loop;
335 end Add_To_Path;
337 procedure Add_To_Path
338 (Dir : String;
339 Buffer : in out String_Access;
340 Buffer_Last : in out Natural)
342 Len : Natural;
343 New_Buffer : String_Access;
344 Min_Len : Natural;
346 function Is_Present (Path : String; Dir : String) return Boolean;
347 -- Return True if Dir is part of Path
349 ----------------
350 -- Is_Present --
351 ----------------
353 function Is_Present (Path : String; Dir : String) return Boolean is
354 Last : constant Integer := Path'Last - Dir'Length + 1;
356 begin
357 for J in Path'First .. Last loop
359 -- Note: the order of the conditions below is important, since
360 -- it ensures a minimal number of string comparisons.
362 if (J = Path'First or else Path (J - 1) = Path_Separator)
363 and then
364 (J + Dir'Length > Path'Last
365 or else Path (J + Dir'Length) = Path_Separator)
366 and then Dir = Path (J .. J + Dir'Length - 1)
367 then
368 return True;
369 end if;
370 end loop;
372 return False;
373 end Is_Present;
375 -- Start of processing for Add_To_Path
377 begin
378 if Is_Present (Buffer (1 .. Buffer_Last), Dir) then
380 -- Dir is already in the path, nothing to do
382 return;
383 end if;
385 Min_Len := Buffer_Last + Dir'Length;
387 if Buffer_Last > 0 then
389 -- Add 1 for the Path_Separator character
391 Min_Len := Min_Len + 1;
392 end if;
394 -- If Ada_Path_Buffer is too small, increase it
396 Len := Buffer'Last;
398 if Len < Min_Len then
399 loop
400 Len := Len * 2;
401 exit when Len >= Min_Len;
402 end loop;
404 New_Buffer := new String (1 .. Len);
405 New_Buffer (1 .. Buffer_Last) := Buffer (1 .. Buffer_Last);
406 Free (Buffer);
407 Buffer := New_Buffer;
408 end if;
410 if Buffer_Last > 0 then
411 Buffer_Last := Buffer_Last + 1;
412 Buffer (Buffer_Last) := Path_Separator;
413 end if;
415 Buffer (Buffer_Last + 1 .. Buffer_Last + Dir'Length) := Dir;
416 Buffer_Last := Buffer_Last + Dir'Length;
417 end Add_To_Path;
419 ------------------------
420 -- Add_To_Source_Path --
421 ------------------------
423 procedure Add_To_Source_Path
424 (Source_Dirs : String_List_Id;
425 Shared : Shared_Project_Tree_Data_Access;
426 Source_Paths : in out Source_Path_Table.Instance)
428 Current : String_List_Id;
429 Source_Dir : String_Element;
430 Add_It : Boolean;
432 begin
433 -- Add each source directory
435 Current := Source_Dirs;
436 while Current /= Nil_String loop
437 Source_Dir := Shared.String_Elements.Table (Current);
438 Add_It := True;
440 -- Check if the source directory is already in the table
442 for Index in
443 Source_Path_Table.First .. Source_Path_Table.Last (Source_Paths)
444 loop
445 -- If it is already, no need to add it
447 if Source_Paths.Table (Index) = Source_Dir.Value then
448 Add_It := False;
449 exit;
450 end if;
451 end loop;
453 if Add_It then
454 Source_Path_Table.Append (Source_Paths, Source_Dir.Display_Value);
455 end if;
457 -- Next source directory
459 Current := Source_Dir.Next;
460 end loop;
461 end Add_To_Source_Path;
463 --------------------------------
464 -- Create_Config_Pragmas_File --
465 --------------------------------
467 procedure Create_Config_Pragmas_File
468 (For_Project : Project_Id;
469 In_Tree : Project_Tree_Ref)
471 type Naming_Id is new Nat;
472 package Naming_Table is new GNAT.Dynamic_Tables
473 (Table_Component_Type => Lang_Naming_Data,
474 Table_Index_Type => Naming_Id,
475 Table_Low_Bound => 1,
476 Table_Initial => 5,
477 Table_Increment => 100);
479 Default_Naming : constant Naming_Id := Naming_Table.First;
480 Namings : Naming_Table.Instance;
481 -- Table storing the naming data for gnatmake/gprmake
483 Buffer : String_Access := new String (1 .. Buffer_Initial);
484 Buffer_Last : Natural := 0;
486 File_Name : Path_Name_Type := No_Path;
487 File : File_Descriptor := Invalid_FD;
489 Current_Naming : Naming_Id;
491 procedure Check
492 (Project : Project_Id;
493 In_Tree : Project_Tree_Ref;
494 State : in out Integer);
495 -- Recursive procedure that put in the config pragmas file any non
496 -- standard naming schemes, if it is not already in the file, then call
497 -- itself for any imported project.
499 procedure Put (Source : Source_Id);
500 -- Put an SFN pragma in the temporary file
502 procedure Put (S : String);
503 procedure Put_Line (S : String);
504 -- Output procedures, analogous to normal Text_IO procs of same name.
505 -- The text is put in Buffer, then it will be written into a temporary
506 -- file with procedure Write_Temp_File below.
508 procedure Write_Temp_File;
509 -- Create a temporary file and put the content of the buffer in it
511 -----------
512 -- Check --
513 -----------
515 procedure Check
516 (Project : Project_Id;
517 In_Tree : Project_Tree_Ref;
518 State : in out Integer)
520 pragma Unreferenced (State);
522 Lang : constant Language_Ptr :=
523 Get_Language_From_Name (Project, "ada");
524 Naming : Lang_Naming_Data;
525 Iter : Source_Iterator;
526 Source : Source_Id;
528 begin
529 if Current_Verbosity = High then
530 Debug_Output ("Checking project file:", Project.Name);
531 end if;
533 if Lang = null then
534 if Current_Verbosity = High then
535 Debug_Output ("Languages does not contain Ada, nothing to do");
536 end if;
538 return;
539 end if;
541 -- Visit all the files and process those that need an SFN pragma
543 Iter := For_Each_Source (In_Tree, Project);
544 while Element (Iter) /= No_Source loop
545 Source := Element (Iter);
547 if not Source.Locally_Removed
548 and then Source.Unit /= null
549 and then
550 (Source.Index >= 1 or else Source.Naming_Exception /= No)
551 then
552 Put (Source);
553 end if;
555 Next (Iter);
556 end loop;
558 Naming := Lang.Config.Naming_Data;
560 -- Is the naming scheme of this project one that we know?
562 Current_Naming := Default_Naming;
563 while Current_Naming <= Naming_Table.Last (Namings)
564 and then Namings.Table (Current_Naming).Dot_Replacement =
565 Naming.Dot_Replacement
566 and then Namings.Table (Current_Naming).Casing =
567 Naming.Casing
568 and then Namings.Table (Current_Naming).Separate_Suffix =
569 Naming.Separate_Suffix
570 loop
571 Current_Naming := Current_Naming + 1;
572 end loop;
574 -- If we don't know it, add it
576 if Current_Naming > Naming_Table.Last (Namings) then
577 Naming_Table.Increment_Last (Namings);
578 Namings.Table (Naming_Table.Last (Namings)) := Naming;
580 -- Put the SFN pragmas for the naming scheme
582 -- Spec
584 Put_Line
585 ("pragma Source_File_Name_Project");
586 Put_Line
587 (" (Spec_File_Name => ""*" &
588 Get_Name_String (Naming.Spec_Suffix) & """,");
589 Put_Line
590 (" Casing => " &
591 Image (Naming.Casing) & ",");
592 Put_Line
593 (" Dot_Replacement => """ &
594 Get_Name_String (Naming.Dot_Replacement) & """);");
596 -- and body
598 Put_Line
599 ("pragma Source_File_Name_Project");
600 Put_Line
601 (" (Body_File_Name => ""*" &
602 Get_Name_String (Naming.Body_Suffix) & """,");
603 Put_Line
604 (" Casing => " &
605 Image (Naming.Casing) & ",");
606 Put_Line
607 (" Dot_Replacement => """ &
608 Get_Name_String (Naming.Dot_Replacement) &
609 """);");
611 -- and maybe separate
613 if Naming.Body_Suffix /= Naming.Separate_Suffix then
614 Put_Line ("pragma Source_File_Name_Project");
615 Put_Line
616 (" (Subunit_File_Name => ""*" &
617 Get_Name_String (Naming.Separate_Suffix) & """,");
618 Put_Line
619 (" Casing => " &
620 Image (Naming.Casing) & ",");
621 Put_Line
622 (" Dot_Replacement => """ &
623 Get_Name_String (Naming.Dot_Replacement) &
624 """);");
625 end if;
626 end if;
627 end Check;
629 ---------
630 -- Put --
631 ---------
633 procedure Put (Source : Source_Id) is
634 begin
635 -- Put the pragma SFN for the unit kind (spec or body)
637 Put ("pragma Source_File_Name_Project (");
638 Put (Namet.Get_Name_String (Source.Unit.Name));
640 if Source.Kind = Spec then
641 Put (", Spec_File_Name => """);
642 else
643 Put (", Body_File_Name => """);
644 end if;
646 Put (Namet.Get_Name_String (Source.File));
647 Put ("""");
649 if Source.Index /= 0 then
650 Put (", Index =>");
651 Put (Source.Index'Img);
652 end if;
654 Put_Line (");");
655 end Put;
657 procedure Put (S : String) is
658 begin
659 Add_To_Buffer (S, Buffer, Buffer_Last);
661 if Current_Verbosity = High then
662 Write_Str (S);
663 end if;
664 end Put;
666 --------------
667 -- Put_Line --
668 --------------
670 procedure Put_Line (S : String) is
671 begin
672 -- Add an ASCII.LF to the string. As this config file is supposed to
673 -- be used only by the compiler, we don't care about the characters
674 -- for the end of line. In fact we could have put a space, but
675 -- it is more convenient to be able to read gnat.adc during
676 -- development, for which the ASCII.LF is fine.
678 Put (S);
679 Put (S => (1 => ASCII.LF));
680 end Put_Line;
682 ---------------------
683 -- Write_Temp_File --
684 ---------------------
686 procedure Write_Temp_File is
687 Status : Boolean := False;
688 Last : Natural;
690 begin
691 Tempdir.Create_Temp_File (File, File_Name);
693 if File /= Invalid_FD then
694 Last := Write (File, Buffer (1)'Address, Buffer_Last);
696 if Last = Buffer_Last then
697 Close (File, Status);
698 end if;
699 end if;
701 if not Status then
702 Prj.Com.Fail ("unable to create temporary file");
703 end if;
704 end Write_Temp_File;
706 procedure Check_Imported_Projects is
707 new For_Every_Project_Imported (Integer, Check);
709 Dummy : Integer := 0;
711 -- Start of processing for Create_Config_Pragmas_File
713 begin
714 if not For_Project.Config_Checked then
715 Naming_Table.Init (Namings);
717 -- Check the naming schemes
719 Check_Imported_Projects
720 (For_Project, In_Tree, Dummy, Imported_First => False);
722 -- If there are no non standard naming scheme, issue the GNAT
723 -- standard naming scheme. This will tell the compiler that
724 -- a project file is used and will forbid any pragma SFN.
726 if Buffer_Last = 0 then
728 Put_Line ("pragma Source_File_Name_Project");
729 Put_Line (" (Spec_File_Name => ""*.ads"",");
730 Put_Line (" Dot_Replacement => ""-"",");
731 Put_Line (" Casing => lowercase);");
733 Put_Line ("pragma Source_File_Name_Project");
734 Put_Line (" (Body_File_Name => ""*.adb"",");
735 Put_Line (" Dot_Replacement => ""-"",");
736 Put_Line (" Casing => lowercase);");
737 end if;
739 -- Close the temporary file
741 Write_Temp_File;
743 if Opt.Verbose_Mode then
744 Write_Str ("Created configuration file """);
745 Write_Str (Get_Name_String (File_Name));
746 Write_Line ("""");
747 end if;
749 For_Project.Config_File_Name := File_Name;
750 For_Project.Config_File_Temp := True;
751 For_Project.Config_Checked := True;
752 end if;
754 Free (Buffer);
755 end Create_Config_Pragmas_File;
757 --------------------
758 -- Create_Mapping --
759 --------------------
761 procedure Create_Mapping (In_Tree : Project_Tree_Ref) is
762 Data : Source_Id;
763 Iter : Source_Iterator;
765 begin
766 Fmap.Reset_Tables;
768 Iter := For_Each_Source (In_Tree);
769 loop
770 Data := Element (Iter);
771 exit when Data = No_Source;
773 if Data.Unit /= No_Unit_Index then
774 if Data.Locally_Removed and then not Data.Suppressed then
775 Fmap.Add_Forbidden_File_Name (Data.File);
776 else
777 Fmap.Add_To_File_Map
778 (Unit_Name => Unit_Name_Type (Data.Unit.Name),
779 File_Name => Data.File,
780 Path_Name => File_Name_Type (Data.Path.Display_Name));
781 end if;
782 end if;
784 Next (Iter);
785 end loop;
786 end Create_Mapping;
788 -------------------------
789 -- Create_Mapping_File --
790 -------------------------
792 procedure Create_Mapping_File
793 (Project : Project_Id;
794 Language : Name_Id;
795 In_Tree : Project_Tree_Ref;
796 Name : out Path_Name_Type)
798 File : File_Descriptor := Invalid_FD;
799 Buffer : String_Access := new String (1 .. Buffer_Initial);
800 Buffer_Last : Natural := 0;
802 procedure Put_Name_Buffer;
803 -- Put the line contained in the Name_Buffer in the global buffer
805 procedure Process
806 (Project : Project_Id;
807 In_Tree : Project_Tree_Ref;
808 State : in out Integer);
809 -- Generate the mapping file for Project (not recursively)
811 ---------------------
812 -- Put_Name_Buffer --
813 ---------------------
815 procedure Put_Name_Buffer is
816 begin
817 if Current_Verbosity = High then
818 Debug_Output (Name_Buffer (1 .. Name_Len));
819 end if;
821 Name_Len := Name_Len + 1;
822 Name_Buffer (Name_Len) := ASCII.LF;
823 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
824 end Put_Name_Buffer;
826 -------------
827 -- Process --
828 -------------
830 procedure Process
831 (Project : Project_Id;
832 In_Tree : Project_Tree_Ref;
833 State : in out Integer)
835 pragma Unreferenced (State);
837 Source : Source_Id;
838 Suffix : File_Name_Type;
839 Iter : Source_Iterator;
841 begin
842 Debug_Output ("Add mapping for project", Project.Name);
843 Iter := For_Each_Source (In_Tree, Project, Language => Language);
845 loop
846 Source := Prj.Element (Iter);
847 exit when Source = No_Source;
849 if not Source.Suppressed
850 and then Source.Replaced_By = No_Source
851 and then Source.Path.Name /= No_Path
852 and then (Source.Language.Config.Kind = File_Based
853 or else Source.Unit /= No_Unit_Index)
854 then
855 if Source.Unit /= No_Unit_Index then
857 -- Put the encoded unit name in the name buffer
859 declare
860 Uname : constant String :=
861 Get_Name_String (Source.Unit.Name);
863 begin
864 Name_Len := 0;
865 for J in Uname'Range loop
866 if Uname (J) in Upper_Half_Character then
867 Store_Encoded_Character (Get_Char_Code (Uname (J)));
868 else
869 Add_Char_To_Name_Buffer (Uname (J));
870 end if;
871 end loop;
872 end;
874 if Source.Language.Config.Kind = Unit_Based then
876 -- ??? Mapping_Spec_Suffix could be set in the case of
877 -- gnatmake as well
879 Add_Char_To_Name_Buffer ('%');
881 if Source.Kind = Spec then
882 Add_Char_To_Name_Buffer ('s');
883 else
884 Add_Char_To_Name_Buffer ('b');
885 end if;
887 else
888 case Source.Kind is
889 when Spec =>
890 Suffix :=
891 Source.Language.Config.Mapping_Spec_Suffix;
892 when Impl | Sep =>
893 Suffix :=
894 Source.Language.Config.Mapping_Body_Suffix;
895 end case;
897 if Suffix /= No_File then
898 Add_Str_To_Name_Buffer (Get_Name_String (Suffix));
899 end if;
900 end if;
902 Put_Name_Buffer;
903 end if;
905 Get_Name_String (Source.Display_File);
906 Put_Name_Buffer;
908 if Source.Locally_Removed then
909 Name_Len := 1;
910 Name_Buffer (1) := '/';
911 else
912 Get_Name_String (Source.Path.Display_Name);
913 end if;
915 Put_Name_Buffer;
916 end if;
918 Next (Iter);
919 end loop;
920 end Process;
922 procedure For_Every_Imported_Project is new
923 For_Every_Project_Imported (State => Integer, Action => Process);
925 -- Local variables
927 Dummy : Integer := 0;
929 -- Start of processing for Create_Mapping_File
931 begin
932 if Current_Verbosity = High then
933 Debug_Output ("Create mapping file for", Debug_Name (In_Tree));
934 end if;
936 Create_Temp_File (In_Tree.Shared, File, Name, "mapping");
938 if Current_Verbosity = High then
939 Debug_Increase_Indent ("Create mapping file ", Name_Id (Name));
940 end if;
942 For_Every_Imported_Project
943 (Project, In_Tree, Dummy, Include_Aggregated => False);
945 declare
946 Last : Natural;
947 Status : Boolean := False;
949 begin
950 if File /= Invalid_FD then
951 Last := Write (File, Buffer (1)'Address, Buffer_Last);
953 if Last = Buffer_Last then
954 GNAT.OS_Lib.Close (File, Status);
955 end if;
956 end if;
958 if not Status then
959 Prj.Com.Fail ("could not write mapping file");
960 end if;
961 end;
963 Free (Buffer);
965 Debug_Decrease_Indent ("Done create mapping file");
966 end Create_Mapping_File;
968 ----------------------
969 -- Create_Temp_File --
970 ----------------------
972 procedure Create_Temp_File
973 (Shared : Shared_Project_Tree_Data_Access;
974 Path_FD : out File_Descriptor;
975 Path_Name : out Path_Name_Type;
976 File_Use : String)
978 begin
979 Tempdir.Create_Temp_File (Path_FD, Path_Name);
981 if Path_Name /= No_Path then
982 if Current_Verbosity = High then
983 Write_Line ("Create temp file (" & File_Use & ") "
984 & Get_Name_String (Path_Name));
985 end if;
987 Record_Temp_File (Shared, Path_Name);
989 else
990 Prj.Com.Fail
991 ("unable to create temporary " & File_Use & " file");
992 end if;
993 end Create_Temp_File;
995 --------------------------
996 -- Create_New_Path_File --
997 --------------------------
999 procedure Create_New_Path_File
1000 (Shared : Shared_Project_Tree_Data_Access;
1001 Path_FD : out File_Descriptor;
1002 Path_Name : out Path_Name_Type)
1004 begin
1005 Create_Temp_File (Shared, Path_FD, Path_Name, "path file");
1006 end Create_New_Path_File;
1008 ------------------------------------
1009 -- File_Name_Of_Library_Unit_Body --
1010 ------------------------------------
1012 function File_Name_Of_Library_Unit_Body
1013 (Name : String;
1014 Project : Project_Id;
1015 In_Tree : Project_Tree_Ref;
1016 Main_Project_Only : Boolean := True;
1017 Full_Path : Boolean := False) return String
1020 Lang : constant Language_Ptr :=
1021 Get_Language_From_Name (Project, "ada");
1022 The_Project : Project_Id := Project;
1023 Original_Name : String := Name;
1025 Unit : Unit_Index;
1026 The_Original_Name : Name_Id;
1027 The_Spec_Name : Name_Id;
1028 The_Body_Name : Name_Id;
1030 begin
1031 -- ??? Same block in Project_Of
1032 Canonical_Case_File_Name (Original_Name);
1033 Name_Len := Original_Name'Length;
1034 Name_Buffer (1 .. Name_Len) := Original_Name;
1035 The_Original_Name := Name_Find;
1037 if Lang /= null then
1038 declare
1039 Naming : constant Lang_Naming_Data := Lang.Config.Naming_Data;
1040 Extended_Spec_Name : String :=
1041 Name & Namet.Get_Name_String
1042 (Naming.Spec_Suffix);
1043 Extended_Body_Name : String :=
1044 Name & Namet.Get_Name_String
1045 (Naming.Body_Suffix);
1047 begin
1048 Canonical_Case_File_Name (Extended_Spec_Name);
1049 Name_Len := Extended_Spec_Name'Length;
1050 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1051 The_Spec_Name := Name_Find;
1053 Canonical_Case_File_Name (Extended_Body_Name);
1054 Name_Len := Extended_Body_Name'Length;
1055 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1056 The_Body_Name := Name_Find;
1057 end;
1059 else
1060 Name_Len := Name'Length;
1061 Name_Buffer (1 .. Name_Len) := Name;
1062 Canonical_Case_File_Name (Name_Buffer);
1063 The_Spec_Name := Name_Find;
1064 The_Body_Name := The_Spec_Name;
1065 end if;
1067 if Current_Verbosity = High then
1068 Write_Str ("Looking for file name of """);
1069 Write_Str (Name);
1070 Write_Char ('"');
1071 Write_Eol;
1072 Write_Str (" Extended Spec Name = """);
1073 Write_Str (Get_Name_String (The_Spec_Name));
1074 Write_Char ('"');
1075 Write_Eol;
1076 Write_Str (" Extended Body Name = """);
1077 Write_Str (Get_Name_String (The_Body_Name));
1078 Write_Char ('"');
1079 Write_Eol;
1080 end if;
1082 -- For extending project, search in the extended project if the source
1083 -- is not found. For non extending projects, this loop will be run only
1084 -- once.
1086 loop
1087 -- Loop through units
1089 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1090 while Unit /= null loop
1092 -- Check for body
1094 if not Main_Project_Only
1095 or else
1096 (Unit.File_Names (Impl) /= null
1097 and then Unit.File_Names (Impl).Project = The_Project)
1098 then
1099 declare
1100 Current_Name : File_Name_Type;
1102 begin
1103 -- Case of a body present
1105 if Unit.File_Names (Impl) /= null then
1106 Current_Name := Unit.File_Names (Impl).File;
1108 if Current_Verbosity = High then
1109 Write_Str (" Comparing with """);
1110 Write_Str (Get_Name_String (Current_Name));
1111 Write_Char ('"');
1112 Write_Eol;
1113 end if;
1115 -- If it has the name of the original name, return the
1116 -- original name.
1118 if Unit.Name = The_Original_Name
1119 or else
1120 Current_Name = File_Name_Type (The_Original_Name)
1121 then
1122 if Current_Verbosity = High then
1123 Write_Line (" OK");
1124 end if;
1126 if Full_Path then
1127 return Get_Name_String
1128 (Unit.File_Names (Impl).Path.Name);
1130 else
1131 return Get_Name_String (Current_Name);
1132 end if;
1134 -- If it has the name of the extended body name,
1135 -- return the extended body name
1137 elsif Current_Name = File_Name_Type (The_Body_Name) then
1138 if Current_Verbosity = High then
1139 Write_Line (" OK");
1140 end if;
1142 if Full_Path then
1143 return Get_Name_String
1144 (Unit.File_Names (Impl).Path.Name);
1146 else
1147 return Get_Name_String (The_Body_Name);
1148 end if;
1150 else
1151 if Current_Verbosity = High then
1152 Write_Line (" not good");
1153 end if;
1154 end if;
1155 end if;
1156 end;
1157 end if;
1159 -- Check for spec
1161 if not Main_Project_Only
1162 or else (Unit.File_Names (Spec) /= null
1163 and then Unit.File_Names (Spec).Project = The_Project)
1164 then
1165 declare
1166 Current_Name : File_Name_Type;
1168 begin
1169 -- Case of spec present
1171 if Unit.File_Names (Spec) /= null then
1172 Current_Name := Unit.File_Names (Spec).File;
1173 if Current_Verbosity = High then
1174 Write_Str (" Comparing with """);
1175 Write_Str (Get_Name_String (Current_Name));
1176 Write_Char ('"');
1177 Write_Eol;
1178 end if;
1180 -- If name same as original name, return original name
1182 if Unit.Name = The_Original_Name
1183 or else
1184 Current_Name = File_Name_Type (The_Original_Name)
1185 then
1186 if Current_Verbosity = High then
1187 Write_Line (" OK");
1188 end if;
1190 if Full_Path then
1191 return Get_Name_String
1192 (Unit.File_Names (Spec).Path.Name);
1193 else
1194 return Get_Name_String (Current_Name);
1195 end if;
1197 -- If it has the same name as the extended spec name,
1198 -- return the extended spec name.
1200 elsif Current_Name = File_Name_Type (The_Spec_Name) then
1201 if Current_Verbosity = High then
1202 Write_Line (" OK");
1203 end if;
1205 if Full_Path then
1206 return Get_Name_String
1207 (Unit.File_Names (Spec).Path.Name);
1208 else
1209 return Get_Name_String (The_Spec_Name);
1210 end if;
1212 else
1213 if Current_Verbosity = High then
1214 Write_Line (" not good");
1215 end if;
1216 end if;
1217 end if;
1218 end;
1219 end if;
1221 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1222 end loop;
1224 -- If we are not in an extending project, give up
1226 exit when not Main_Project_Only
1227 or else The_Project.Extends = No_Project;
1229 -- Otherwise, look in the project we are extending
1231 The_Project := The_Project.Extends;
1232 end loop;
1234 -- We don't know this file name, return an empty string
1236 return "";
1237 end File_Name_Of_Library_Unit_Body;
1239 -------------------------
1240 -- For_All_Object_Dirs --
1241 -------------------------
1243 procedure For_All_Object_Dirs
1244 (Project : Project_Id;
1245 Tree : Project_Tree_Ref)
1247 procedure For_Project
1248 (Prj : Project_Id;
1249 Tree : Project_Tree_Ref;
1250 Dummy : in out Integer);
1251 -- Get all object directories of Prj
1253 -----------------
1254 -- For_Project --
1255 -----------------
1257 procedure For_Project
1258 (Prj : Project_Id;
1259 Tree : Project_Tree_Ref;
1260 Dummy : in out Integer)
1262 pragma Unreferenced (Dummy, Tree);
1264 begin
1265 -- ??? Set_Ada_Paths has a different behavior for library project
1266 -- files, should we have the same ?
1268 if Prj.Object_Directory /= No_Path_Information then
1269 Get_Name_String (Prj.Object_Directory.Display_Name);
1270 Action (Name_Buffer (1 .. Name_Len));
1271 end if;
1272 end For_Project;
1274 procedure Get_Object_Dirs is
1275 new For_Every_Project_Imported (Integer, For_Project);
1276 Dummy : Integer := 1;
1278 -- Start of processing for For_All_Object_Dirs
1280 begin
1281 Get_Object_Dirs (Project, Tree, Dummy);
1282 end For_All_Object_Dirs;
1284 -------------------------
1285 -- For_All_Source_Dirs --
1286 -------------------------
1288 procedure For_All_Source_Dirs
1289 (Project : Project_Id;
1290 In_Tree : Project_Tree_Ref)
1292 procedure For_Project
1293 (Prj : Project_Id;
1294 In_Tree : Project_Tree_Ref;
1295 Dummy : in out Integer);
1296 -- Get all object directories of Prj
1298 -----------------
1299 -- For_Project --
1300 -----------------
1302 procedure For_Project
1303 (Prj : Project_Id;
1304 In_Tree : Project_Tree_Ref;
1305 Dummy : in out Integer)
1307 pragma Unreferenced (Dummy);
1309 Current : String_List_Id := Prj.Source_Dirs;
1310 The_String : String_Element;
1312 begin
1313 -- If there are Ada sources, call action with the name of every
1314 -- source directory.
1316 if Has_Ada_Sources (Prj) then
1317 while Current /= Nil_String loop
1318 The_String := In_Tree.Shared.String_Elements.Table (Current);
1319 Action (Get_Name_String (The_String.Display_Value));
1320 Current := The_String.Next;
1321 end loop;
1322 end if;
1323 end For_Project;
1325 procedure Get_Source_Dirs is
1326 new For_Every_Project_Imported (Integer, For_Project);
1327 Dummy : Integer := 1;
1329 -- Start of processing for For_All_Source_Dirs
1331 begin
1332 Get_Source_Dirs (Project, In_Tree, Dummy);
1333 end For_All_Source_Dirs;
1335 -------------------
1336 -- Get_Reference --
1337 -------------------
1339 procedure Get_Reference
1340 (Source_File_Name : String;
1341 In_Tree : Project_Tree_Ref;
1342 Project : out Project_Id;
1343 Path : out Path_Name_Type)
1345 begin
1346 -- Body below could use some comments ???
1348 if Current_Verbosity > Default then
1349 Write_Str ("Getting Reference_Of (""");
1350 Write_Str (Source_File_Name);
1351 Write_Str (""") ... ");
1352 end if;
1354 declare
1355 Original_Name : String := Source_File_Name;
1356 Unit : Unit_Index;
1358 begin
1359 Canonical_Case_File_Name (Original_Name);
1360 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1362 while Unit /= null loop
1363 if Unit.File_Names (Spec) /= null
1364 and then not Unit.File_Names (Spec).Locally_Removed
1365 and then Unit.File_Names (Spec).File /= No_File
1366 and then
1367 (Namet.Get_Name_String
1368 (Unit.File_Names (Spec).File) = Original_Name
1369 or else (Unit.File_Names (Spec).Path /= No_Path_Information
1370 and then
1371 Namet.Get_Name_String
1372 (Unit.File_Names (Spec).Path.Name) =
1373 Original_Name))
1374 then
1375 Project :=
1376 Ultimate_Extending_Project_Of
1377 (Unit.File_Names (Spec).Project);
1378 Path := Unit.File_Names (Spec).Path.Display_Name;
1380 if Current_Verbosity > Default then
1381 Write_Str ("Done: Spec.");
1382 Write_Eol;
1383 end if;
1385 return;
1387 elsif Unit.File_Names (Impl) /= null
1388 and then Unit.File_Names (Impl).File /= No_File
1389 and then not Unit.File_Names (Impl).Locally_Removed
1390 and then
1391 (Namet.Get_Name_String
1392 (Unit.File_Names (Impl).File) = Original_Name
1393 or else (Unit.File_Names (Impl).Path /= No_Path_Information
1394 and then Namet.Get_Name_String
1395 (Unit.File_Names (Impl).Path.Name) =
1396 Original_Name))
1397 then
1398 Project :=
1399 Ultimate_Extending_Project_Of
1400 (Unit.File_Names (Impl).Project);
1401 Path := Unit.File_Names (Impl).Path.Display_Name;
1403 if Current_Verbosity > Default then
1404 Write_Str ("Done: Body.");
1405 Write_Eol;
1406 end if;
1408 return;
1409 end if;
1411 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1412 end loop;
1413 end;
1415 Project := No_Project;
1416 Path := No_Path;
1418 if Current_Verbosity > Default then
1419 Write_Str ("Cannot be found.");
1420 Write_Eol;
1421 end if;
1422 end Get_Reference;
1424 ----------------------
1425 -- Get_Runtime_Path --
1426 ----------------------
1428 function Get_Runtime_Path
1429 (Self : Project_Search_Path;
1430 Name : String) return String_Access
1432 function Is_Base_Name (Path : String) return Boolean;
1433 -- Returns True if Path has no directory separator
1435 ------------------
1436 -- Is_Base_Name --
1437 ------------------
1439 function Is_Base_Name (Path : String) return Boolean is
1440 begin
1441 for J in Path'Range loop
1442 if Path (J) = Directory_Separator or else Path (J) = '/' then
1443 return False;
1444 end if;
1445 end loop;
1447 return True;
1448 end Is_Base_Name;
1450 function Find_Rts_In_Path is new Prj.Env.Find_Name_In_Path
1451 (Check_Filename => Is_Directory);
1453 -- Start of processing for Get_Runtime_Path
1455 begin
1456 if not Is_Base_Name (Name) then
1457 return Find_Rts_In_Path (Self, Name);
1458 else
1459 return null;
1460 end if;
1461 end Get_Runtime_Path;
1463 ----------------
1464 -- Initialize --
1465 ----------------
1467 procedure Initialize (In_Tree : Project_Tree_Ref) is
1468 begin
1469 In_Tree.Shared.Private_Part.Current_Source_Path_File := No_Path;
1470 In_Tree.Shared.Private_Part.Current_Object_Path_File := No_Path;
1471 end Initialize;
1473 -------------------
1474 -- Print_Sources --
1475 -------------------
1477 -- Could use some comments in this body ???
1479 procedure Print_Sources (In_Tree : Project_Tree_Ref) is
1480 Unit : Unit_Index;
1482 begin
1483 Write_Line ("List of Sources:");
1485 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1486 while Unit /= No_Unit_Index loop
1487 Write_Str (" ");
1488 Write_Line (Namet.Get_Name_String (Unit.Name));
1490 if Unit.File_Names (Spec).File /= No_File then
1491 if Unit.File_Names (Spec).Project = No_Project then
1492 Write_Line (" No project");
1494 else
1495 Write_Str (" Project: ");
1496 Get_Name_String
1497 (Unit.File_Names (Spec).Project.Path.Name);
1498 Write_Line (Name_Buffer (1 .. Name_Len));
1499 end if;
1501 Write_Str (" spec: ");
1502 Write_Line
1503 (Namet.Get_Name_String
1504 (Unit.File_Names (Spec).File));
1505 end if;
1507 if Unit.File_Names (Impl).File /= No_File then
1508 if Unit.File_Names (Impl).Project = No_Project then
1509 Write_Line (" No project");
1511 else
1512 Write_Str (" Project: ");
1513 Get_Name_String
1514 (Unit.File_Names (Impl).Project.Path.Name);
1515 Write_Line (Name_Buffer (1 .. Name_Len));
1516 end if;
1518 Write_Str (" body: ");
1519 Write_Line
1520 (Namet.Get_Name_String (Unit.File_Names (Impl).File));
1521 end if;
1523 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1524 end loop;
1526 Write_Line ("end of List of Sources.");
1527 end Print_Sources;
1529 ----------------
1530 -- Project_Of --
1531 ----------------
1533 function Project_Of
1534 (Name : String;
1535 Main_Project : Project_Id;
1536 In_Tree : Project_Tree_Ref) return Project_Id
1538 Result : Project_Id := No_Project;
1540 Original_Name : String := Name;
1542 Lang : constant Language_Ptr :=
1543 Get_Language_From_Name (Main_Project, "ada");
1545 Unit : Unit_Index;
1547 Current_Name : File_Name_Type;
1548 The_Original_Name : File_Name_Type;
1549 The_Spec_Name : File_Name_Type;
1550 The_Body_Name : File_Name_Type;
1552 begin
1553 -- ??? Same block in File_Name_Of_Library_Unit_Body
1554 Canonical_Case_File_Name (Original_Name);
1555 Name_Len := Original_Name'Length;
1556 Name_Buffer (1 .. Name_Len) := Original_Name;
1557 The_Original_Name := Name_Find;
1559 if Lang /= null then
1560 declare
1561 Naming : Lang_Naming_Data renames Lang.Config.Naming_Data;
1562 Extended_Spec_Name : String :=
1563 Name & Namet.Get_Name_String
1564 (Naming.Spec_Suffix);
1565 Extended_Body_Name : String :=
1566 Name & Namet.Get_Name_String
1567 (Naming.Body_Suffix);
1569 begin
1570 Canonical_Case_File_Name (Extended_Spec_Name);
1571 Name_Len := Extended_Spec_Name'Length;
1572 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1573 The_Spec_Name := Name_Find;
1575 Canonical_Case_File_Name (Extended_Body_Name);
1576 Name_Len := Extended_Body_Name'Length;
1577 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1578 The_Body_Name := Name_Find;
1579 end;
1581 else
1582 The_Spec_Name := The_Original_Name;
1583 The_Body_Name := The_Original_Name;
1584 end if;
1586 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1587 while Unit /= null loop
1589 -- Case of a body present
1591 if Unit.File_Names (Impl) /= null then
1592 Current_Name := Unit.File_Names (Impl).File;
1594 -- If it has the name of the original name or the body name,
1595 -- we have found the project.
1597 if Unit.Name = Name_Id (The_Original_Name)
1598 or else Current_Name = The_Original_Name
1599 or else Current_Name = The_Body_Name
1600 then
1601 Result := Unit.File_Names (Impl).Project;
1602 exit;
1603 end if;
1604 end if;
1606 -- Check for spec
1608 if Unit.File_Names (Spec) /= null then
1609 Current_Name := Unit.File_Names (Spec).File;
1611 -- If name same as the original name, or the spec name, we have
1612 -- found the project.
1614 if Unit.Name = Name_Id (The_Original_Name)
1615 or else Current_Name = The_Original_Name
1616 or else Current_Name = The_Spec_Name
1617 then
1618 Result := Unit.File_Names (Spec).Project;
1619 exit;
1620 end if;
1621 end if;
1623 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1624 end loop;
1626 return Ultimate_Extending_Project_Of (Result);
1627 end Project_Of;
1629 -------------------
1630 -- Set_Ada_Paths --
1631 -------------------
1633 procedure Set_Ada_Paths
1634 (Project : Project_Id;
1635 In_Tree : Project_Tree_Ref;
1636 Including_Libraries : Boolean;
1637 Include_Path : Boolean := True;
1638 Objects_Path : Boolean := True)
1641 Shared : constant Shared_Project_Tree_Data_Access := In_Tree.Shared;
1643 Source_Paths : Source_Path_Table.Instance;
1644 Object_Paths : Object_Path_Table.Instance;
1645 -- List of source or object dirs. Only computed the first time this
1646 -- procedure is called (since Source_FD is then reused)
1648 Source_FD : File_Descriptor := Invalid_FD;
1649 Object_FD : File_Descriptor := Invalid_FD;
1650 -- The temporary files to store the paths. These are only created the
1651 -- first time this procedure is called, and reused from then on.
1653 Process_Source_Dirs : Boolean := False;
1654 Process_Object_Dirs : Boolean := False;
1656 Status : Boolean;
1657 -- For calls to Close
1659 Last : Natural;
1660 Buffer : String_Access := new String (1 .. Buffer_Initial);
1661 Buffer_Last : Natural := 0;
1663 procedure Recursive_Add
1664 (Project : Project_Id;
1665 In_Tree : Project_Tree_Ref;
1666 Dummy : in out Boolean);
1667 -- Recursive procedure to add the source/object paths of extended/
1668 -- imported projects.
1670 -------------------
1671 -- Recursive_Add --
1672 -------------------
1674 procedure Recursive_Add
1675 (Project : Project_Id;
1676 In_Tree : Project_Tree_Ref;
1677 Dummy : in out Boolean)
1679 pragma Unreferenced (Dummy, In_Tree);
1681 Path : Path_Name_Type;
1683 begin
1684 if Process_Source_Dirs then
1686 -- Add to path all source directories of this project if there are
1687 -- Ada sources.
1689 if Has_Ada_Sources (Project) then
1690 Add_To_Source_Path (Project.Source_Dirs, Shared, Source_Paths);
1691 end if;
1692 end if;
1694 if Process_Object_Dirs then
1695 Path := Get_Object_Directory
1696 (Project,
1697 Including_Libraries => Including_Libraries,
1698 Only_If_Ada => True);
1700 if Path /= No_Path then
1701 Add_To_Object_Path (Path, Object_Paths);
1702 end if;
1703 end if;
1704 end Recursive_Add;
1706 procedure For_All_Projects is
1707 new For_Every_Project_Imported (Boolean, Recursive_Add);
1709 Dummy : Boolean := False;
1711 -- Start of processing for Set_Ada_Paths
1713 begin
1714 -- If it is the first time we call this procedure for this project,
1715 -- compute the source path and/or the object path.
1717 if Include_Path and then Project.Include_Path_File = No_Path then
1718 Source_Path_Table.Init (Source_Paths);
1719 Process_Source_Dirs := True;
1720 Create_New_Path_File (Shared, Source_FD, Project.Include_Path_File);
1721 end if;
1723 -- For the object path, we make a distinction depending on
1724 -- Including_Libraries.
1726 if Objects_Path and Including_Libraries then
1727 if Project.Objects_Path_File_With_Libs = No_Path then
1728 Object_Path_Table.Init (Object_Paths);
1729 Process_Object_Dirs := True;
1730 Create_New_Path_File
1731 (Shared, Object_FD, Project.Objects_Path_File_With_Libs);
1732 end if;
1734 elsif Objects_Path then
1735 if Project.Objects_Path_File_Without_Libs = No_Path then
1736 Object_Path_Table.Init (Object_Paths);
1737 Process_Object_Dirs := True;
1738 Create_New_Path_File
1739 (Shared, Object_FD, Project.Objects_Path_File_Without_Libs);
1740 end if;
1741 end if;
1743 -- If there is something to do, set Seen to False for all projects,
1744 -- then call the recursive procedure Add for Project.
1746 if Process_Source_Dirs or Process_Object_Dirs then
1747 For_All_Projects (Project, In_Tree, Dummy);
1748 end if;
1750 -- Write and close any file that has been created. Source_FD is not set
1751 -- when this subprogram is called a second time or more, since we reuse
1752 -- the previous version of the file.
1754 if Source_FD /= Invalid_FD then
1755 Buffer_Last := 0;
1757 for Index in
1758 Source_Path_Table.First .. Source_Path_Table.Last (Source_Paths)
1759 loop
1760 Get_Name_String (Source_Paths.Table (Index));
1761 Name_Len := Name_Len + 1;
1762 Name_Buffer (Name_Len) := ASCII.LF;
1763 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
1764 end loop;
1766 Last := Write (Source_FD, Buffer (1)'Address, Buffer_Last);
1768 if Last = Buffer_Last then
1769 Close (Source_FD, Status);
1771 else
1772 Status := False;
1773 end if;
1775 if not Status then
1776 Prj.Com.Fail ("could not write temporary file");
1777 end if;
1778 end if;
1780 if Object_FD /= Invalid_FD then
1781 Buffer_Last := 0;
1783 for Index in
1784 Object_Path_Table.First .. Object_Path_Table.Last (Object_Paths)
1785 loop
1786 Get_Name_String (Object_Paths.Table (Index));
1787 Name_Len := Name_Len + 1;
1788 Name_Buffer (Name_Len) := ASCII.LF;
1789 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
1790 end loop;
1792 Last := Write (Object_FD, Buffer (1)'Address, Buffer_Last);
1794 if Last = Buffer_Last then
1795 Close (Object_FD, Status);
1796 else
1797 Status := False;
1798 end if;
1800 if not Status then
1801 Prj.Com.Fail ("could not write temporary file");
1802 end if;
1803 end if;
1805 -- Set the env vars, if they need to be changed, and set the
1806 -- corresponding flags.
1808 if Include_Path
1809 and then
1810 Shared.Private_Part.Current_Source_Path_File /=
1811 Project.Include_Path_File
1812 then
1813 Shared.Private_Part.Current_Source_Path_File :=
1814 Project.Include_Path_File;
1815 Set_Path_File_Var
1816 (Project_Include_Path_File,
1817 Get_Name_String (Shared.Private_Part.Current_Source_Path_File));
1818 end if;
1820 if Objects_Path then
1821 if Including_Libraries then
1822 if Shared.Private_Part.Current_Object_Path_File /=
1823 Project.Objects_Path_File_With_Libs
1824 then
1825 Shared.Private_Part.Current_Object_Path_File :=
1826 Project.Objects_Path_File_With_Libs;
1827 Set_Path_File_Var
1828 (Project_Objects_Path_File,
1829 Get_Name_String
1830 (Shared.Private_Part.Current_Object_Path_File));
1831 end if;
1833 else
1834 if Shared.Private_Part.Current_Object_Path_File /=
1835 Project.Objects_Path_File_Without_Libs
1836 then
1837 Shared.Private_Part.Current_Object_Path_File :=
1838 Project.Objects_Path_File_Without_Libs;
1839 Set_Path_File_Var
1840 (Project_Objects_Path_File,
1841 Get_Name_String
1842 (Shared.Private_Part.Current_Object_Path_File));
1843 end if;
1844 end if;
1845 end if;
1847 Free (Buffer);
1848 end Set_Ada_Paths;
1850 ---------------------
1851 -- Add_Directories --
1852 ---------------------
1854 procedure Add_Directories
1855 (Self : in out Project_Search_Path;
1856 Path : String;
1857 Prepend : Boolean := False)
1859 Tmp : String_Access;
1860 begin
1861 if Self.Path = null then
1862 Self.Path := new String'(Uninitialized_Prefix & Path);
1863 else
1864 Tmp := Self.Path;
1865 if Prepend then
1866 Self.Path := new String'(Path & Path_Separator & Tmp.all);
1867 else
1868 Self.Path := new String'(Tmp.all & Path_Separator & Path);
1869 end if;
1870 Free (Tmp);
1871 end if;
1873 if Current_Verbosity = High then
1874 Debug_Output ("Adding directories to Project_Path: """
1875 & Path & '"');
1876 end if;
1877 end Add_Directories;
1879 --------------------
1880 -- Is_Initialized --
1881 --------------------
1883 function Is_Initialized (Self : Project_Search_Path) return Boolean is
1884 begin
1885 return Self.Path /= null
1886 and then (Self.Path'Length = 0
1887 or else Self.Path (Self.Path'First) /= '#');
1888 end Is_Initialized;
1890 ----------------------
1891 -- Initialize_Empty --
1892 ----------------------
1894 procedure Initialize_Empty (Self : in out Project_Search_Path) is
1895 begin
1896 Free (Self.Path);
1897 Self.Path := new String'("");
1898 end Initialize_Empty;
1900 -------------------------------------
1901 -- Initialize_Default_Project_Path --
1902 -------------------------------------
1904 procedure Initialize_Default_Project_Path
1905 (Self : in out Project_Search_Path;
1906 Target_Name : String)
1908 Add_Default_Dir : Boolean := True;
1909 First : Positive;
1910 Last : Positive;
1911 New_Len : Positive;
1912 New_Last : Positive;
1914 Ada_Project_Path : constant String := "ADA_PROJECT_PATH";
1915 Gpr_Project_Path : constant String := "GPR_PROJECT_PATH";
1916 Gpr_Project_Path_File : constant String := "GPR_PROJECT_PATH_FILE";
1917 -- Names of alternate env. variable that contain path name(s) of
1918 -- directories where project files may reside. They are taken into
1919 -- account in this order: GPR_PROJECT_PATH_FILE, GPR_PROJECT_PATH,
1920 -- ADA_PROJECT_PATH.
1922 Gpr_Prj_Path_File : String_Access;
1923 Gpr_Prj_Path : String_Access;
1924 Ada_Prj_Path : String_Access;
1925 -- The path name(s) of directories where project files may reside.
1926 -- May be empty.
1928 begin
1929 if Is_Initialized (Self) then
1930 return;
1931 end if;
1933 -- The current directory is always first in the search path. Since the
1934 -- Project_Path currently starts with '#:' as a sign that it isn't
1935 -- initialized, we simply replace '#' with '.'
1937 if Self.Path = null then
1938 Self.Path := new String'('.' & Path_Separator);
1939 else
1940 Self.Path (Self.Path'First) := '.';
1941 end if;
1943 -- Then the reset of the project path (if any) currently contains the
1944 -- directories added through Add_Search_Project_Directory
1946 -- If environment variables are defined and not empty, add their content
1948 Gpr_Prj_Path_File := Getenv (Gpr_Project_Path_File);
1949 Gpr_Prj_Path := Getenv (Gpr_Project_Path);
1950 Ada_Prj_Path := Getenv (Ada_Project_Path);
1952 if Gpr_Prj_Path_File.all /= "" then
1953 declare
1954 File : Ada.Text_IO.File_Type;
1955 Line : String (1 .. 10_000);
1956 Last : Natural;
1958 Tmp : String_Access;
1960 begin
1961 Open (File, In_File, Gpr_Prj_Path_File.all);
1963 while not End_Of_File (File) loop
1964 Get_Line (File, Line, Last);
1966 if Last /= 0
1967 and then (Last = 1 or else Line (1 .. 2) /= "--")
1968 then
1969 Tmp := Self.Path;
1970 Self.Path :=
1971 new String'
1972 (Tmp.all & Path_Separator & Line (1 .. Last));
1973 Free (Tmp);
1974 end if;
1976 if Current_Verbosity = High then
1977 Debug_Output ("Adding directory to Project_Path: """
1978 & Line (1 .. Last) & '"');
1979 end if;
1980 end loop;
1982 Close (File);
1984 exception
1985 when others =>
1986 Write_Str ("warning: could not read project path file """);
1987 Write_Str (Gpr_Prj_Path_File.all);
1988 Write_Line ("""");
1989 end;
1991 end if;
1993 if Gpr_Prj_Path.all /= "" then
1994 Add_Directories (Self, Gpr_Prj_Path.all);
1995 end if;
1997 Free (Gpr_Prj_Path);
1999 if Ada_Prj_Path.all /= "" then
2000 Add_Directories (Self, Ada_Prj_Path.all);
2001 end if;
2003 Free (Ada_Prj_Path);
2005 -- Copy to Name_Buffer, since we will need to manipulate the path
2007 Name_Len := Self.Path'Length;
2008 Name_Buffer (1 .. Name_Len) := Self.Path.all;
2010 -- Scan the directory path to see if "-" is one of the directories.
2011 -- Remove each occurrence of "-" and set Add_Default_Dir to False.
2012 -- Also resolve relative paths and symbolic links.
2014 First := 3;
2015 loop
2016 while First <= Name_Len
2017 and then (Name_Buffer (First) = Path_Separator)
2018 loop
2019 First := First + 1;
2020 end loop;
2022 exit when First > Name_Len;
2024 Last := First;
2026 while Last < Name_Len
2027 and then Name_Buffer (Last + 1) /= Path_Separator
2028 loop
2029 Last := Last + 1;
2030 end loop;
2032 -- If the directory is "-", set Add_Default_Dir to False and
2033 -- remove from path.
2035 if Name_Buffer (First .. Last) = No_Project_Default_Dir then
2036 Add_Default_Dir := False;
2038 for J in Last + 1 .. Name_Len loop
2039 Name_Buffer (J - No_Project_Default_Dir'Length - 1) :=
2040 Name_Buffer (J);
2041 end loop;
2043 Name_Len := Name_Len - No_Project_Default_Dir'Length - 1;
2045 -- After removing the '-', go back one character to get the next
2046 -- directory correctly.
2048 Last := Last - 1;
2050 elsif not Hostparm.OpenVMS
2051 or else not Is_Absolute_Path (Name_Buffer (First .. Last))
2052 then
2053 -- On VMS, only expand relative path names, as absolute paths
2054 -- may correspond to multi-valued VMS logical names.
2056 declare
2057 New_Dir : constant String :=
2058 Normalize_Pathname
2059 (Name_Buffer (First .. Last),
2060 Resolve_Links => Opt.Follow_Links_For_Dirs);
2062 begin
2063 -- If the absolute path was resolved and is different from
2064 -- the original, replace original with the resolved path.
2066 if New_Dir /= Name_Buffer (First .. Last)
2067 and then New_Dir'Length /= 0
2068 then
2069 New_Len := Name_Len + New_Dir'Length - (Last - First + 1);
2070 New_Last := First + New_Dir'Length - 1;
2071 Name_Buffer (New_Last + 1 .. New_Len) :=
2072 Name_Buffer (Last + 1 .. Name_Len);
2073 Name_Buffer (First .. New_Last) := New_Dir;
2074 Name_Len := New_Len;
2075 Last := New_Last;
2076 end if;
2077 end;
2078 end if;
2080 First := Last + 1;
2081 end loop;
2083 Free (Self.Path);
2085 -- Set the initial value of Current_Project_Path
2087 if Add_Default_Dir then
2088 declare
2089 Prefix : String_Ptr;
2091 begin
2092 if Sdefault.Search_Dir_Prefix = null then
2094 -- gprbuild case
2096 Prefix := new String'(Executable_Prefix_Path);
2098 else
2099 Prefix := new String'(Sdefault.Search_Dir_Prefix.all
2100 & ".." & Dir_Separator
2101 & ".." & Dir_Separator
2102 & ".." & Dir_Separator
2103 & ".." & Dir_Separator);
2104 end if;
2106 if Prefix.all /= "" then
2107 if Target_Name /= "" then
2109 -- $prefix/$target/lib/gnat
2111 Add_Str_To_Name_Buffer
2112 (Path_Separator & Prefix.all & Target_Name);
2114 -- Note: Target_Name has a trailing / when it comes from
2115 -- Sdefault.
2117 if Name_Buffer (Name_Len) /= '/' then
2118 Add_Char_To_Name_Buffer (Directory_Separator);
2119 end if;
2121 Add_Str_To_Name_Buffer
2122 ("lib" & Directory_Separator & "gnat");
2124 -- $prefix/$target/share/gpr
2126 Add_Str_To_Name_Buffer
2127 (Path_Separator & Prefix.all & Target_Name);
2129 -- Note: Target_Name has a trailing / when it comes from
2130 -- Sdefault.
2132 if Name_Buffer (Name_Len) /= '/' then
2133 Add_Char_To_Name_Buffer (Directory_Separator);
2134 end if;
2136 Add_Str_To_Name_Buffer
2137 ("share" & Directory_Separator & "gpr");
2138 end if;
2140 -- $prefix/share/gpr
2142 Add_Str_To_Name_Buffer
2143 (Path_Separator & Prefix.all &
2144 "share" & Directory_Separator & "gpr");
2146 -- $prefix/lib/gnat
2148 Add_Str_To_Name_Buffer
2149 (Path_Separator & Prefix.all &
2150 "lib" & Directory_Separator & "gnat");
2151 end if;
2153 Free (Prefix);
2154 end;
2155 end if;
2157 Self.Path := new String'(Name_Buffer (1 .. Name_Len));
2158 end Initialize_Default_Project_Path;
2160 --------------
2161 -- Get_Path --
2162 --------------
2164 procedure Get_Path (Self : Project_Search_Path; Path : out String_Access) is
2165 begin
2166 pragma Assert (Is_Initialized (Self));
2167 Path := Self.Path;
2168 end Get_Path;
2170 --------------
2171 -- Set_Path --
2172 --------------
2174 procedure Set_Path (Self : in out Project_Search_Path; Path : String) is
2175 begin
2176 Free (Self.Path);
2177 Self.Path := new String'(Path);
2178 Projects_Paths.Reset (Self.Cache);
2179 end Set_Path;
2181 -----------------------
2182 -- Find_Name_In_Path --
2183 -----------------------
2185 function Find_Name_In_Path
2186 (Self : Project_Search_Path;
2187 Path : String) return String_Access
2189 First : Natural;
2190 Last : Natural;
2192 begin
2193 if Current_Verbosity = High then
2194 Debug_Output ("Trying " & Path);
2195 end if;
2197 if Is_Absolute_Path (Path) then
2198 if Check_Filename (Path) then
2199 return new String'(Path);
2200 else
2201 return null;
2202 end if;
2204 else
2205 -- Because we don't want to resolve symbolic links, we cannot use
2206 -- Locate_Regular_File. So, we try each possible path successively.
2208 First := Self.Path'First;
2209 while First <= Self.Path'Last loop
2210 while First <= Self.Path'Last
2211 and then Self.Path (First) = Path_Separator
2212 loop
2213 First := First + 1;
2214 end loop;
2216 exit when First > Self.Path'Last;
2218 Last := First;
2219 while Last < Self.Path'Last
2220 and then Self.Path (Last + 1) /= Path_Separator
2221 loop
2222 Last := Last + 1;
2223 end loop;
2225 Name_Len := 0;
2227 if not Is_Absolute_Path (Self.Path (First .. Last)) then
2228 Add_Str_To_Name_Buffer (Get_Current_Dir); -- ??? System call
2229 Add_Char_To_Name_Buffer (Directory_Separator);
2230 end if;
2232 Add_Str_To_Name_Buffer (Self.Path (First .. Last));
2233 Add_Char_To_Name_Buffer (Directory_Separator);
2234 Add_Str_To_Name_Buffer (Path);
2236 if Current_Verbosity = High then
2237 Debug_Output ("Testing file " & Name_Buffer (1 .. Name_Len));
2238 end if;
2240 if Check_Filename (Name_Buffer (1 .. Name_Len)) then
2241 return new String'(Name_Buffer (1 .. Name_Len));
2242 end if;
2244 First := Last + 1;
2245 end loop;
2246 end if;
2248 return null;
2249 end Find_Name_In_Path;
2251 ------------------
2252 -- Find_Project --
2253 ------------------
2255 procedure Find_Project
2256 (Self : in out Project_Search_Path;
2257 Project_File_Name : String;
2258 Directory : String;
2259 Path : out Namet.Path_Name_Type)
2261 Result : String_Access;
2262 Has_Dot : Boolean := False;
2263 Key : Name_Id;
2265 File : constant String := Project_File_Name;
2266 -- Have to do a copy, in case the parameter is Name_Buffer, which we
2267 -- modify below.
2269 Cached_Path : Namet.Path_Name_Type;
2270 -- This should be commented rather than making us guess from the name???
2272 function Try_Path_Name is new
2273 Find_Name_In_Path (Check_Filename => Is_Regular_File);
2274 -- Find a file in the project search path
2276 -- Start of processing for Find_Project
2278 begin
2279 pragma Assert (Is_Initialized (Self));
2281 if Current_Verbosity = High then
2282 Debug_Increase_Indent
2283 ("Searching for project """ & File & """ in """
2284 & Directory & '"');
2285 end if;
2287 -- Check the project cache
2289 Name_Len := File'Length;
2290 Name_Buffer (1 .. Name_Len) := File;
2291 Key := Name_Find;
2292 Cached_Path := Projects_Paths.Get (Self.Cache, Key);
2294 -- Check if File contains an extension (a dot before a
2295 -- directory separator). If it is the case we do not try project file
2296 -- with an added extension as it is not possible to have multiple dots
2297 -- on a project file name.
2299 Check_Dot : for K in reverse File'Range loop
2300 if File (K) = '.' then
2301 Has_Dot := True;
2302 exit Check_Dot;
2303 end if;
2305 exit Check_Dot when File (K) = Directory_Separator
2306 or else File (K) = '/';
2307 end loop Check_Dot;
2309 if not Is_Absolute_Path (File) then
2311 -- If we have found project in the cache, check if in the directory
2313 if Cached_Path /= No_Path then
2314 declare
2315 Cached : constant String := Get_Name_String (Cached_Path);
2316 begin
2317 if (not Has_Dot
2318 and then Cached =
2319 GNAT.OS_Lib.Normalize_Pathname
2320 (File & Project_File_Extension,
2321 Directory => Directory,
2322 Resolve_Links => Opt.Follow_Links_For_Files,
2323 Case_Sensitive => True))
2324 or else
2325 Cached =
2326 GNAT.OS_Lib.Normalize_Pathname
2327 (File,
2328 Directory => Directory,
2329 Resolve_Links => Opt.Follow_Links_For_Files,
2330 Case_Sensitive => True)
2331 then
2332 Path := Cached_Path;
2333 Debug_Decrease_Indent;
2334 return;
2335 end if;
2336 end;
2337 end if;
2339 -- First we try <directory>/<file_name>.<extension>
2341 if not Has_Dot then
2342 Result :=
2343 Try_Path_Name
2344 (Self,
2345 Directory & Directory_Separator
2346 & File & Project_File_Extension);
2347 end if;
2349 -- Then we try <directory>/<file_name>
2351 if Result = null then
2352 Result :=
2353 Try_Path_Name (Self, Directory & Directory_Separator & File);
2354 end if;
2355 end if;
2357 -- If we found the path in the cache, this is the one
2359 if Result = null and then Cached_Path /= No_Path then
2360 Path := Cached_Path;
2361 Debug_Decrease_Indent;
2362 return;
2363 end if;
2365 -- Then we try <file_name>.<extension>
2367 if Result = null and then not Has_Dot then
2368 Result := Try_Path_Name (Self, File & Project_File_Extension);
2369 end if;
2371 -- Then we try <file_name>
2373 if Result = null then
2374 Result := Try_Path_Name (Self, File);
2375 end if;
2377 -- If we cannot find the project file, we return an empty string
2379 if Result = null then
2380 Path := Namet.No_Path;
2381 return;
2383 else
2384 declare
2385 Final_Result : constant String :=
2386 GNAT.OS_Lib.Normalize_Pathname
2387 (Result.all,
2388 Directory => Directory,
2389 Resolve_Links => Opt.Follow_Links_For_Files,
2390 Case_Sensitive => True);
2391 begin
2392 Free (Result);
2393 Name_Len := Final_Result'Length;
2394 Name_Buffer (1 .. Name_Len) := Final_Result;
2395 Path := Name_Find;
2396 Projects_Paths.Set (Self.Cache, Key, Path);
2397 end;
2398 end if;
2400 Debug_Decrease_Indent;
2401 end Find_Project;
2403 ----------
2404 -- Free --
2405 ----------
2407 procedure Free (Self : in out Project_Search_Path) is
2408 begin
2409 Free (Self.Path);
2410 Projects_Paths.Reset (Self.Cache);
2411 end Free;
2413 ----------
2414 -- Copy --
2415 ----------
2417 procedure Copy (From : Project_Search_Path; To : out Project_Search_Path) is
2418 begin
2419 Free (To);
2421 if From.Path /= null then
2422 To.Path := new String'(From.Path.all);
2423 end if;
2425 -- No need to copy the Cache, it will be recomputed as needed
2426 end Copy;
2428 end Prj.Env;