1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2001-2009, Free Software Foundation, Inc. --
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. --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 ------------------------------------------------------------------------------
28 with Osint; use Osint;
29 with Output; use Output;
30 with Prj.Com; use Prj.Com;
33 package body Prj.Env is
35 Buffer_Initial : constant := 1_000;
36 -- Initial size of Buffer
38 -----------------------
39 -- Local Subprograms --
40 -----------------------
42 package Source_Path_Table is new GNAT.Dynamic_Tables
43 (Table_Component_Type => Name_Id,
44 Table_Index_Type => Natural,
47 Table_Increment => 100);
48 -- A table to store the source dirs before creating the source path file
50 package Object_Path_Table is new GNAT.Dynamic_Tables
51 (Table_Component_Type => Path_Name_Type,
52 Table_Index_Type => Natural,
55 Table_Increment => 100);
56 -- A table to store the object dirs, before creating the object path file
58 procedure Add_To_Buffer
60 Buffer : in out String_Access;
61 Buffer_Last : in out Natural);
62 -- Add a string to Buffer, extending Buffer if needed
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.
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.
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.
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.
92 procedure Set_Path_File_Var (Name : String; Value : String);
93 -- Call Setenv, after calling To_Host_File_Spec
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.
100 procedure Create_Temp_File
101 (In_Tree : Project_Tree_Ref;
102 Path_FD : out File_Descriptor;
103 Path_Name : out Path_Name_Type;
105 -- Create a temporary file, and fail with an error if it could not be
108 ----------------------
109 -- Ada_Include_Path --
110 ----------------------
112 function Ada_Include_Path
113 (Project : Project_Id;
114 In_Tree : Project_Tree_Ref;
115 Recursive : Boolean := False) return String
117 Buffer : String_Access;
118 Buffer_Last : Natural := 0;
120 procedure Add (Project : Project_Id; Dummy : in out Boolean);
121 -- Add source dirs of Project to the path
127 procedure Add (Project : Project_Id; Dummy : in out Boolean) is
128 pragma Unreferenced (Dummy);
130 Add_To_Path (Project.Source_Dirs, In_Tree, Buffer, Buffer_Last);
133 procedure For_All_Projects is
134 new For_Every_Project_Imported (Boolean, Add);
136 Dummy : Boolean := False;
138 -- Start of processing for Ada_Include_Path
143 -- If it is the first time we call this function for
144 -- this project, compute the source path
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));
153 return Project.Ada_Include_Path.all;
156 Buffer := new String (1 .. 4096);
157 Add_To_Path (Project.Source_Dirs, In_Tree, Buffer, Buffer_Last);
160 Result : constant String := Buffer (1 .. Buffer_Last);
166 end Ada_Include_Path;
168 ----------------------
169 -- Ada_Objects_Path --
170 ----------------------
172 function Ada_Objects_Path
173 (Project : Project_Id;
174 Including_Libraries : Boolean := True) return String_Access
176 Buffer : String_Access;
177 Buffer_Last : Natural := 0;
179 procedure Add (Project : Project_Id; Dummy : in out Boolean);
180 -- Add all the object directories of a project to the path
186 procedure Add (Project : Project_Id; Dummy : in out Boolean) is
187 pragma Unreferenced (Dummy);
188 Path : constant Path_Name_Type :=
191 Including_Libraries => Including_Libraries,
192 Only_If_Ada => False);
194 if Path /= No_Path then
195 Add_To_Path (Get_Name_String (Path), Buffer, Buffer_Last);
199 procedure For_All_Projects is
200 new For_Every_Project_Imported (Boolean, Add);
202 Dummy : Boolean := False;
204 -- Start of processing for Ada_Objects_Path
207 -- If it is the first time we call this function for
208 -- this project, compute the objects path
210 if Project.Ada_Objects_Path = null then
211 Buffer := new String (1 .. 4096);
212 For_All_Projects (Project, Dummy);
214 Project.Ada_Objects_Path := new String'(Buffer (1 .. Buffer_Last));
218 return Project.Ada_Objects_Path;
219 end Ada_Objects_Path;
225 -- Wouldn't it be more consistent to use a Table for Buffer ???
227 procedure Add_To_Buffer
229 Buffer : in out String_Access;
230 Buffer_Last : in out Natural)
232 Last : constant Natural := Buffer_Last + S'Length;
235 while Last > Buffer'Last loop
237 New_Buffer : constant String_Access :=
238 new String (1 .. 2 * Buffer'Last);
241 New_Buffer (1 .. Buffer_Last) := Buffer (1 .. Buffer_Last);
243 Buffer := New_Buffer;
247 Buffer (Buffer_Last + 1 .. Last) := S;
251 ------------------------
252 -- Add_To_Object_Path --
253 ------------------------
255 procedure Add_To_Object_Path
256 (Object_Dir : Path_Name_Type;
257 Object_Paths : in out Object_Path_Table.Instance)
260 -- Check if the directory is already in the table
262 for Index in Object_Path_Table.First ..
263 Object_Path_Table.Last (Object_Paths)
266 -- If it is, remove it, and add it as the last one
268 if Object_Paths.Table (Index) = Object_Dir then
269 for Index2 in Index + 1 ..
270 Object_Path_Table.Last (Object_Paths)
272 Object_Paths.Table (Index2 - 1) := Object_Paths.Table (Index2);
276 (Object_Path_Table.Last (Object_Paths)) := Object_Dir;
281 -- The directory is not already in the table, add it
283 Object_Path_Table.Append (Object_Paths, Object_Dir);
284 end Add_To_Object_Path;
290 procedure Add_To_Path
291 (Source_Dirs : String_List_Id;
292 In_Tree : Project_Tree_Ref;
293 Buffer : in out String_Access;
294 Buffer_Last : in out Natural)
296 Current : String_List_Id := Source_Dirs;
297 Source_Dir : String_Element;
299 while Current /= Nil_String loop
300 Source_Dir := In_Tree.String_Elements.Table (Current);
301 Add_To_Path (Get_Name_String (Source_Dir.Display_Value),
302 Buffer, Buffer_Last);
303 Current := Source_Dir.Next;
307 procedure Add_To_Path
309 Buffer : in out String_Access;
310 Buffer_Last : in out Natural)
313 New_Buffer : String_Access;
316 function Is_Present (Path : String; Dir : String) return Boolean;
317 -- Return True if Dir is part of Path
323 function Is_Present (Path : String; Dir : String) return Boolean is
324 Last : constant Integer := Path'Last - Dir'Length + 1;
327 for J in Path'First .. Last loop
329 -- Note: the order of the conditions below is important, since
330 -- it ensures a minimal number of string comparisons.
333 or else Path (J - 1) = Path_Separator)
335 (J + Dir'Length > Path'Last
336 or else Path (J + Dir'Length) = Path_Separator)
337 and then Dir = Path (J .. J + Dir'Length - 1)
346 -- Start of processing for Add_To_Path
349 if Is_Present (Buffer (1 .. Buffer_Last), Dir) then
351 -- Dir is already in the path, nothing to do
356 Min_Len := Buffer_Last + Dir'Length;
358 if Buffer_Last > 0 then
360 -- Add 1 for the Path_Separator character
362 Min_Len := Min_Len + 1;
365 -- If Ada_Path_Buffer is too small, increase it
369 if Len < Min_Len then
372 exit when Len >= Min_Len;
375 New_Buffer := new String (1 .. Len);
376 New_Buffer (1 .. Buffer_Last) := Buffer (1 .. Buffer_Last);
378 Buffer := New_Buffer;
381 if Buffer_Last > 0 then
382 Buffer_Last := Buffer_Last + 1;
383 Buffer (Buffer_Last) := Path_Separator;
386 Buffer (Buffer_Last + 1 .. Buffer_Last + Dir'Length) := Dir;
387 Buffer_Last := Buffer_Last + Dir'Length;
390 ------------------------
391 -- Add_To_Source_Path --
392 ------------------------
394 procedure Add_To_Source_Path
395 (Source_Dirs : String_List_Id;
396 In_Tree : Project_Tree_Ref;
397 Source_Paths : in out Source_Path_Table.Instance)
399 Current : String_List_Id := Source_Dirs;
400 Source_Dir : String_Element;
404 -- Add each source directory
406 while Current /= Nil_String loop
407 Source_Dir := In_Tree.String_Elements.Table (Current);
410 -- Check if the source directory is already in the table
412 for Index in Source_Path_Table.First ..
413 Source_Path_Table.Last (Source_Paths)
415 -- If it is already, no need to add it
417 if Source_Paths.Table (Index) = Source_Dir.Value then
424 Source_Path_Table.Append (Source_Paths, Source_Dir.Value);
427 -- Next source directory
429 Current := Source_Dir.Next;
431 end Add_To_Source_Path;
433 --------------------------------
434 -- Create_Config_Pragmas_File --
435 --------------------------------
437 procedure Create_Config_Pragmas_File
438 (For_Project : Project_Id;
439 In_Tree : Project_Tree_Ref)
441 type Naming_Id is new Nat;
442 package Naming_Table is new GNAT.Dynamic_Tables
443 (Table_Component_Type => Lang_Naming_Data,
444 Table_Index_Type => Naming_Id,
445 Table_Low_Bound => 1,
447 Table_Increment => 100);
448 Default_Naming : constant Naming_Id := Naming_Table.First;
449 Namings : Naming_Table.Instance;
450 -- Table storing the naming data for gnatmake/gprmake
452 Buffer : String_Access := new String (1 .. Buffer_Initial);
453 Buffer_Last : Natural := 0;
455 File_Name : Path_Name_Type := No_Path;
456 File : File_Descriptor := Invalid_FD;
458 Current_Naming : Naming_Id;
459 Iter : Source_Iterator;
462 procedure Check (Project : Project_Id; State : in out Integer);
463 -- Recursive procedure that put in the config pragmas file any non
464 -- standard naming schemes, if it is not already in the file, then call
465 -- itself for any imported project.
467 procedure Put (Source : Source_Id);
468 -- Put an SFN pragma in the temporary file
470 procedure Put (S : String);
471 procedure Put_Line (S : String);
472 -- Output procedures, analogous to normal Text_IO procs of same name.
473 -- The text is put in Buffer, then it will be writen into a temporary
474 -- file with procedure Write_Temp_File below.
476 procedure Write_Temp_File;
477 -- Create a temporary file and put the content of the buffer in it
483 procedure Check (Project : Project_Id; State : in out Integer) is
484 pragma Unreferenced (State);
485 Lang : constant Language_Ptr :=
486 Get_Language_From_Name (Project, "ada");
487 Naming : Lang_Naming_Data;
490 if Current_Verbosity = High then
491 Write_Str ("Checking project file """);
492 Write_Str (Namet.Get_Name_String (Project.Name));
498 if Current_Verbosity = High then
499 Write_Line (" Languages does not contain Ada, nothing to do");
505 Naming := Lang.Config.Naming_Data;
507 -- Is the naming scheme of this project one that we know?
509 Current_Naming := Default_Naming;
510 while Current_Naming <= Naming_Table.Last (Namings)
511 and then Namings.Table (Current_Naming).Dot_Replacement =
512 Naming.Dot_Replacement
513 and then Namings.Table (Current_Naming).Casing =
515 and then Namings.Table (Current_Naming).Separate_Suffix =
516 Naming.Separate_Suffix
518 Current_Naming := Current_Naming + 1;
521 -- If we don't know it, add it
523 if Current_Naming > Naming_Table.Last (Namings) then
524 Naming_Table.Increment_Last (Namings);
525 Namings.Table (Naming_Table.Last (Namings)) := Naming;
527 -- Put the SFN pragmas for the naming scheme
532 ("pragma Source_File_Name_Project");
534 (" (Spec_File_Name => ""*" &
535 Get_Name_String (Naming.Spec_Suffix) & """,");
538 Image (Naming.Casing) & ",");
540 (" Dot_Replacement => """ &
541 Get_Name_String (Naming.Dot_Replacement) & """);");
546 ("pragma Source_File_Name_Project");
548 (" (Body_File_Name => ""*" &
549 Get_Name_String (Naming.Body_Suffix) & """,");
552 Image (Naming.Casing) & ",");
554 (" Dot_Replacement => """ &
555 Get_Name_String (Naming.Dot_Replacement) &
558 -- and maybe separate
560 if Naming.Body_Suffix /= Naming.Separate_Suffix then
561 Put_Line ("pragma Source_File_Name_Project");
563 (" (Subunit_File_Name => ""*" &
564 Get_Name_String (Naming.Separate_Suffix) & """,");
567 Image (Naming.Casing) & ",");
569 (" Dot_Replacement => """ &
570 Get_Name_String (Naming.Dot_Replacement) &
580 procedure Put (Source : Source_Id) is
582 -- Put the pragma SFN for the unit kind (spec or body)
584 Put ("pragma Source_File_Name_Project (");
585 Put (Namet.Get_Name_String (Source.Unit.Name));
587 if Source.Kind = Spec then
588 Put (", Spec_File_Name => """);
590 Put (", Body_File_Name => """);
593 Put (Namet.Get_Name_String (Source.File));
596 if Source.Index /= 0 then
598 Put (Source.Index'Img);
604 procedure Put (S : String) is
606 Add_To_Buffer (S, Buffer, Buffer_Last);
608 if Current_Verbosity = High then
617 procedure Put_Line (S : String) is
619 -- Add an ASCII.LF to the string. As this config file is supposed to
620 -- be used only by the compiler, we don't care about the characters
621 -- for the end of line. In fact we could have put a space, but
622 -- it is more convenient to be able to read gnat.adc during
623 -- development, for which the ASCII.LF is fine.
626 Put (S => (1 => ASCII.LF));
629 ---------------------
630 -- Write_Temp_File --
631 ---------------------
633 procedure Write_Temp_File is
634 Status : Boolean := False;
638 Tempdir.Create_Temp_File (File, File_Name);
640 if File /= Invalid_FD then
641 Last := Write (File, Buffer (1)'Address, Buffer_Last);
643 if Last = Buffer_Last then
644 Close (File, Status);
649 Prj.Com.Fail ("unable to create temporary file");
653 procedure Check_Imported_Projects is
654 new For_Every_Project_Imported (Integer, Check);
656 Dummy : Integer := 0;
658 -- Start of processing for Create_Config_Pragmas_File
661 if not For_Project.Config_Checked then
662 Naming_Table.Init (Namings);
664 -- Check the naming schemes
666 Check_Imported_Projects (For_Project, Dummy, Imported_First => False);
668 -- Visit all the files and process those that need an SFN pragma
670 Iter := For_Each_Source (In_Tree, For_Project);
671 while Element (Iter) /= No_Source loop
672 Source := Element (Iter);
675 and then not Source.Locally_Removed
676 and then Source.Unit /= null
684 -- If there are no non standard naming scheme, issue the GNAT
685 -- standard naming scheme. This will tell the compiler that
686 -- a project file is used and will forbid any pragma SFN.
688 if Buffer_Last = 0 then
690 Put_Line ("pragma Source_File_Name_Project");
691 Put_Line (" (Spec_File_Name => ""*.ads"",");
692 Put_Line (" Dot_Replacement => ""-"",");
693 Put_Line (" Casing => lowercase);");
695 Put_Line ("pragma Source_File_Name_Project");
696 Put_Line (" (Body_File_Name => ""*.adb"",");
697 Put_Line (" Dot_Replacement => ""-"",");
698 Put_Line (" Casing => lowercase);");
701 -- Close the temporary file
705 if Opt.Verbose_Mode then
706 Write_Str ("Created configuration file """);
707 Write_Str (Get_Name_String (File_Name));
711 For_Project.Config_File_Name := File_Name;
712 For_Project.Config_File_Temp := True;
713 For_Project.Config_Checked := True;
717 end Create_Config_Pragmas_File;
723 procedure Create_Mapping (In_Tree : Project_Tree_Ref) is
725 Iter : Source_Iterator;
730 Iter := For_Each_Source (In_Tree);
732 Data := Element (Iter);
733 exit when Data = No_Source;
735 if Data.Unit /= No_Unit_Index then
736 if Data.Locally_Removed then
737 Fmap.Add_Forbidden_File_Name (Data.File);
740 (Unit_Name => Unit_Name_Type (Data.Unit.Name),
741 File_Name => Data.File,
742 Path_Name => File_Name_Type (Data.Path.Name));
750 -------------------------
751 -- Create_Mapping_File --
752 -------------------------
754 procedure Create_Mapping_File
755 (Project : Project_Id;
757 In_Tree : Project_Tree_Ref;
758 Name : out Path_Name_Type)
760 File : File_Descriptor := Invalid_FD;
762 Buffer : String_Access := new String (1 .. Buffer_Initial);
763 Buffer_Last : Natural := 0;
765 procedure Put_Name_Buffer;
766 -- Put the line contained in the Name_Buffer in the global buffer
768 procedure Process (Project : Project_Id; State : in out Integer);
769 -- Generate the mapping file for Project (not recursively)
771 ---------------------
772 -- Put_Name_Buffer --
773 ---------------------
775 procedure Put_Name_Buffer is
777 Name_Len := Name_Len + 1;
778 Name_Buffer (Name_Len) := ASCII.LF;
780 if Current_Verbosity = High then
781 Write_Str ("Mapping file: " & Name_Buffer (1 .. Name_Len));
784 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
791 procedure Process (Project : Project_Id; State : in out Integer) is
792 pragma Unreferenced (State);
794 Suffix : File_Name_Type;
795 Iter : Source_Iterator;
798 Iter := For_Each_Source (In_Tree, Project, Language => Language);
801 Source := Prj.Element (Iter);
802 exit when Source = No_Source;
804 if Source.Replaced_By = No_Source
805 and then Source.Path.Name /= No_Path
807 (Source.Language.Config.Kind = File_Based
808 or else Source.Unit /= No_Unit_Index)
810 if Source.Unit /= No_Unit_Index then
811 Get_Name_String (Source.Unit.Name);
813 if Source.Language.Config.Kind = Unit_Based then
815 -- ??? Mapping_Spec_Suffix could be set in the case of
818 Add_Char_To_Name_Buffer ('%');
820 if Source.Kind = Spec then
821 Add_Char_To_Name_Buffer ('s');
823 Add_Char_To_Name_Buffer ('b');
830 Source.Language.Config.Mapping_Spec_Suffix;
833 Source.Language.Config.Mapping_Body_Suffix;
836 if Suffix /= No_File then
837 Add_Str_To_Name_Buffer
838 (Get_Name_String (Suffix));
845 Get_Name_String (Source.File);
848 if Source.Locally_Removed then
850 Name_Buffer (1) := '/';
852 Get_Name_String (Source.Path.Name);
862 procedure For_Every_Imported_Project is new
863 For_Every_Project_Imported (State => Integer, Action => Process);
865 Dummy : Integer := 0;
867 -- Start of processing for Create_Mapping_File
870 For_Every_Imported_Project (Project, Dummy);
874 Status : Boolean := False;
877 Create_Temp_File (In_Tree, File, Name, "mapping");
879 if File /= Invalid_FD then
880 Last := Write (File, Buffer (1)'Address, Buffer_Last);
882 if Last = Buffer_Last then
883 GNAT.OS_Lib.Close (File, Status);
888 Prj.Com.Fail ("could not write mapping file");
893 end Create_Mapping_File;
895 ----------------------
896 -- Create_Temp_File --
897 ----------------------
899 procedure Create_Temp_File
900 (In_Tree : Project_Tree_Ref;
901 Path_FD : out File_Descriptor;
902 Path_Name : out Path_Name_Type;
906 Tempdir.Create_Temp_File (Path_FD, Path_Name);
908 if Path_Name /= No_Path then
909 if Current_Verbosity = High then
910 Write_Line ("Create temp file (" & File_Use & ") "
911 & Get_Name_String (Path_Name));
914 Record_Temp_File (In_Tree, Path_Name);
918 ("unable to create temporary " & File_Use & " file");
920 end Create_Temp_File;
922 --------------------------
923 -- Create_New_Path_File --
924 --------------------------
926 procedure Create_New_Path_File
927 (In_Tree : Project_Tree_Ref;
928 Path_FD : out File_Descriptor;
929 Path_Name : out Path_Name_Type)
932 Create_Temp_File (In_Tree, Path_FD, Path_Name, "path file");
933 end Create_New_Path_File;
935 ------------------------------------
936 -- File_Name_Of_Library_Unit_Body --
937 ------------------------------------
939 function File_Name_Of_Library_Unit_Body
941 Project : Project_Id;
942 In_Tree : Project_Tree_Ref;
943 Main_Project_Only : Boolean := True;
944 Full_Path : Boolean := False) return String
946 The_Project : Project_Id := Project;
947 Original_Name : String := Name;
949 Lang : constant Language_Ptr :=
950 Get_Language_From_Name (Project, "ada");
953 The_Original_Name : Name_Id;
954 The_Spec_Name : Name_Id;
955 The_Body_Name : Name_Id;
958 -- ??? Same block in Project_Of
959 Canonical_Case_File_Name (Original_Name);
960 Name_Len := Original_Name'Length;
961 Name_Buffer (1 .. Name_Len) := Original_Name;
962 The_Original_Name := Name_Find;
966 Naming : constant Lang_Naming_Data := Lang.Config.Naming_Data;
967 Extended_Spec_Name : String :=
968 Name & Namet.Get_Name_String
969 (Naming.Spec_Suffix);
970 Extended_Body_Name : String :=
971 Name & Namet.Get_Name_String
972 (Naming.Body_Suffix);
975 Canonical_Case_File_Name (Extended_Spec_Name);
976 Name_Len := Extended_Spec_Name'Length;
977 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
978 The_Spec_Name := Name_Find;
980 Canonical_Case_File_Name (Extended_Body_Name);
981 Name_Len := Extended_Body_Name'Length;
982 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
983 The_Body_Name := Name_Find;
987 Name_Len := Name'Length;
988 Name_Buffer (1 .. Name_Len) := Name;
989 Canonical_Case_File_Name (Name_Buffer);
990 The_Spec_Name := Name_Find;
991 The_Body_Name := The_Spec_Name;
994 if Current_Verbosity = High then
995 Write_Str ("Looking for file name of """);
999 Write_Str (" Extended Spec Name = """);
1000 Write_Str (Get_Name_String (The_Spec_Name));
1003 Write_Str (" Extended Body Name = """);
1004 Write_Str (Get_Name_String (The_Body_Name));
1009 -- For extending project, search in the extended project if the source
1010 -- is not found. For non extending projects, this loop will be run only
1014 -- Loop through units
1016 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1017 while Unit /= null loop
1020 if not Main_Project_Only
1022 (Unit.File_Names (Impl) /= null
1023 and then Unit.File_Names (Impl).Project = The_Project)
1026 Current_Name : File_Name_Type;
1028 -- Case of a body present
1030 if Unit.File_Names (Impl) /= null then
1031 Current_Name := Unit.File_Names (Impl).File;
1033 if Current_Verbosity = High then
1034 Write_Str (" Comparing with """);
1035 Write_Str (Get_Name_String (Current_Name));
1040 -- If it has the name of the original name, return the
1043 if Unit.Name = The_Original_Name
1045 Current_Name = File_Name_Type (The_Original_Name)
1047 if Current_Verbosity = High then
1052 return Get_Name_String
1053 (Unit.File_Names (Impl).Path.Name);
1056 return Get_Name_String (Current_Name);
1059 -- If it has the name of the extended body name,
1060 -- return the extended body name
1062 elsif Current_Name = File_Name_Type (The_Body_Name) then
1063 if Current_Verbosity = High then
1068 return Get_Name_String
1069 (Unit.File_Names (Impl).Path.Name);
1072 return Get_Name_String (The_Body_Name);
1076 if Current_Verbosity = High then
1077 Write_Line (" not good");
1086 if not Main_Project_Only
1088 (Unit.File_Names (Spec) /= null
1089 and then Unit.File_Names (Spec).Project =
1093 Current_Name : File_Name_Type;
1096 -- Case of spec present
1098 if Unit.File_Names (Spec) /= null then
1099 Current_Name := Unit.File_Names (Spec).File;
1100 if Current_Verbosity = High then
1101 Write_Str (" Comparing with """);
1102 Write_Str (Get_Name_String (Current_Name));
1107 -- If name same as original name, return original name
1109 if Unit.Name = The_Original_Name
1111 Current_Name = File_Name_Type (The_Original_Name)
1113 if Current_Verbosity = High then
1118 return Get_Name_String
1119 (Unit.File_Names (Spec).Path.Name);
1121 return Get_Name_String (Current_Name);
1124 -- If it has the same name as the extended spec name,
1125 -- return the extended spec name.
1127 elsif Current_Name = File_Name_Type (The_Spec_Name) then
1128 if Current_Verbosity = High then
1133 return Get_Name_String
1134 (Unit.File_Names (Spec).Path.Name);
1136 return Get_Name_String (The_Spec_Name);
1140 if Current_Verbosity = High then
1141 Write_Line (" not good");
1148 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1151 -- If we are not in an extending project, give up
1153 exit when not Main_Project_Only
1154 or else The_Project.Extends = No_Project;
1156 -- Otherwise, look in the project we are extending
1158 The_Project := The_Project.Extends;
1161 -- We don't know this file name, return an empty string
1164 end File_Name_Of_Library_Unit_Body;
1166 -------------------------
1167 -- For_All_Object_Dirs --
1168 -------------------------
1170 procedure For_All_Object_Dirs (Project : Project_Id) is
1171 procedure For_Project (Prj : Project_Id; Dummy : in out Integer);
1172 -- Get all object directories of Prj
1178 procedure For_Project (Prj : Project_Id; Dummy : in out Integer) is
1179 pragma Unreferenced (Dummy);
1181 -- ??? Set_Ada_Paths has a different behavior for library project
1182 -- files, should we have the same ?
1184 if Prj.Object_Directory /= No_Path_Information then
1185 Get_Name_String (Prj.Object_Directory.Display_Name);
1186 Action (Name_Buffer (1 .. Name_Len));
1190 procedure Get_Object_Dirs is
1191 new For_Every_Project_Imported (Integer, For_Project);
1192 Dummy : Integer := 1;
1194 -- Start of processing for For_All_Object_Dirs
1197 Get_Object_Dirs (Project, Dummy);
1198 end For_All_Object_Dirs;
1200 -------------------------
1201 -- For_All_Source_Dirs --
1202 -------------------------
1204 procedure For_All_Source_Dirs
1205 (Project : Project_Id;
1206 In_Tree : Project_Tree_Ref)
1208 procedure For_Project (Prj : Project_Id; Dummy : in out Integer);
1209 -- Get all object directories of Prj
1215 procedure For_Project (Prj : Project_Id; Dummy : in out Integer) is
1216 pragma Unreferenced (Dummy);
1217 Current : String_List_Id := Prj.Source_Dirs;
1218 The_String : String_Element;
1221 -- If there are Ada sources, call action with the name of every
1222 -- source directory.
1224 if Has_Ada_Sources (Project) then
1225 while Current /= Nil_String loop
1226 The_String := In_Tree.String_Elements.Table (Current);
1227 Action (Get_Name_String (The_String.Display_Value));
1228 Current := The_String.Next;
1233 procedure Get_Source_Dirs is
1234 new For_Every_Project_Imported (Integer, For_Project);
1235 Dummy : Integer := 1;
1237 -- Start of processing for For_All_Source_Dirs
1240 Get_Source_Dirs (Project, Dummy);
1241 end For_All_Source_Dirs;
1247 procedure Get_Reference
1248 (Source_File_Name : String;
1249 In_Tree : Project_Tree_Ref;
1250 Project : out Project_Id;
1251 Path : out Path_Name_Type)
1254 -- Body below could use some comments ???
1256 if Current_Verbosity > Default then
1257 Write_Str ("Getting Reference_Of (""");
1258 Write_Str (Source_File_Name);
1259 Write_Str (""") ... ");
1263 Original_Name : String := Source_File_Name;
1267 Canonical_Case_File_Name (Original_Name);
1268 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1270 while Unit /= null loop
1271 if Unit.File_Names (Spec) /= null
1272 and then Unit.File_Names (Spec).File /= No_File
1274 (Namet.Get_Name_String
1275 (Unit.File_Names (Spec).File) = Original_Name
1276 or else (Unit.File_Names (Spec).Path /=
1279 Namet.Get_Name_String
1280 (Unit.File_Names (Spec).Path.Name) =
1283 Project := Ultimate_Extension_Of
1284 (Project => Unit.File_Names (Spec).Project);
1285 Path := Unit.File_Names (Spec).Path.Display_Name;
1287 if Current_Verbosity > Default then
1288 Write_Str ("Done: Spec.");
1294 elsif Unit.File_Names (Impl) /= null
1295 and then Unit.File_Names (Impl).File /= No_File
1297 (Namet.Get_Name_String
1298 (Unit.File_Names (Impl).File) = Original_Name
1299 or else (Unit.File_Names (Impl).Path /=
1301 and then Namet.Get_Name_String
1302 (Unit.File_Names (Impl).Path.Name) =
1305 Project := Ultimate_Extension_Of
1306 (Project => Unit.File_Names (Impl).Project);
1307 Path := Unit.File_Names (Impl).Path.Display_Name;
1309 if Current_Verbosity > Default then
1310 Write_Str ("Done: Body.");
1317 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1321 Project := No_Project;
1324 if Current_Verbosity > Default then
1325 Write_Str ("Cannot be found.");
1334 procedure Initialize (In_Tree : Project_Tree_Ref) is
1336 In_Tree.Private_Part.Current_Source_Path_File := No_Path;
1337 In_Tree.Private_Part.Current_Object_Path_File := No_Path;
1344 -- Could use some comments in this body ???
1346 procedure Print_Sources (In_Tree : Project_Tree_Ref) is
1350 Write_Line ("List of Sources:");
1352 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1354 while Unit /= No_Unit_Index loop
1356 Write_Line (Namet.Get_Name_String (Unit.Name));
1358 if Unit.File_Names (Spec).File /= No_File then
1359 if Unit.File_Names (Spec).Project = No_Project then
1360 Write_Line (" No project");
1363 Write_Str (" Project: ");
1365 (Unit.File_Names (Spec).Project.Path.Name);
1366 Write_Line (Name_Buffer (1 .. Name_Len));
1369 Write_Str (" spec: ");
1371 (Namet.Get_Name_String
1372 (Unit.File_Names (Spec).File));
1375 if Unit.File_Names (Impl).File /= No_File then
1376 if Unit.File_Names (Impl).Project = No_Project then
1377 Write_Line (" No project");
1380 Write_Str (" Project: ");
1382 (Unit.File_Names (Impl).Project.Path.Name);
1383 Write_Line (Name_Buffer (1 .. Name_Len));
1386 Write_Str (" body: ");
1388 (Namet.Get_Name_String (Unit.File_Names (Impl).File));
1391 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1394 Write_Line ("end of List of Sources.");
1403 Main_Project : Project_Id;
1404 In_Tree : Project_Tree_Ref) return Project_Id
1406 Result : Project_Id := No_Project;
1408 Original_Name : String := Name;
1410 Lang : constant Language_Ptr :=
1411 Get_Language_From_Name (Main_Project, "ada");
1415 Current_Name : File_Name_Type;
1416 The_Original_Name : File_Name_Type;
1417 The_Spec_Name : File_Name_Type;
1418 The_Body_Name : File_Name_Type;
1421 -- ??? Same block in File_Name_Of_Library_Unit_Body
1422 Canonical_Case_File_Name (Original_Name);
1423 Name_Len := Original_Name'Length;
1424 Name_Buffer (1 .. Name_Len) := Original_Name;
1425 The_Original_Name := Name_Find;
1427 if Lang /= null then
1429 Naming : Lang_Naming_Data renames Lang.Config.Naming_Data;
1430 Extended_Spec_Name : String :=
1431 Name & Namet.Get_Name_String
1432 (Naming.Spec_Suffix);
1433 Extended_Body_Name : String :=
1434 Name & Namet.Get_Name_String
1435 (Naming.Body_Suffix);
1438 Canonical_Case_File_Name (Extended_Spec_Name);
1439 Name_Len := Extended_Spec_Name'Length;
1440 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1441 The_Spec_Name := Name_Find;
1443 Canonical_Case_File_Name (Extended_Body_Name);
1444 Name_Len := Extended_Body_Name'Length;
1445 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1446 The_Body_Name := Name_Find;
1450 The_Spec_Name := The_Original_Name;
1451 The_Body_Name := The_Original_Name;
1454 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1455 while Unit /= null loop
1457 -- Case of a body present
1459 if Unit.File_Names (Impl) /= null then
1460 Current_Name := Unit.File_Names (Impl).File;
1462 -- If it has the name of the original name or the body name,
1463 -- we have found the project.
1465 if Unit.Name = Name_Id (The_Original_Name)
1466 or else Current_Name = The_Original_Name
1467 or else Current_Name = The_Body_Name
1469 Result := Unit.File_Names (Impl).Project;
1476 if Unit.File_Names (Spec) /= null then
1477 Current_Name := Unit.File_Names (Spec).File;
1479 -- If name same as the original name, or the spec name, we have
1480 -- found the project.
1482 if Unit.Name = Name_Id (The_Original_Name)
1483 or else Current_Name = The_Original_Name
1484 or else Current_Name = The_Spec_Name
1486 Result := Unit.File_Names (Spec).Project;
1491 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1494 -- Get the ultimate extending project
1496 if Result /= No_Project then
1497 while Result.Extended_By /= No_Project loop
1498 Result := Result.Extended_By;
1509 procedure Set_Ada_Paths
1510 (Project : Project_Id;
1511 In_Tree : Project_Tree_Ref;
1512 Including_Libraries : Boolean)
1515 Source_Paths : Source_Path_Table.Instance;
1516 Object_Paths : Object_Path_Table.Instance;
1517 -- List of source or object dirs. Only computed the first time this
1518 -- procedure is called (since Source_FD is then reused)
1520 Source_FD : File_Descriptor := Invalid_FD;
1521 Object_FD : File_Descriptor := Invalid_FD;
1522 -- The temporary files to store the paths. These are only created the
1523 -- first time this procedure is called, and reused from then on.
1525 Process_Source_Dirs : Boolean := False;
1526 Process_Object_Dirs : Boolean := False;
1529 -- For calls to Close
1532 Buffer : String_Access := new String (1 .. Buffer_Initial);
1533 Buffer_Last : Natural := 0;
1535 procedure Recursive_Add (Project : Project_Id; Dummy : in out Boolean);
1536 -- Recursive procedure to add the source/object paths of extended/
1537 -- imported projects.
1543 procedure Recursive_Add (Project : Project_Id; Dummy : in out Boolean) is
1544 pragma Unreferenced (Dummy);
1546 Path : Path_Name_Type;
1549 -- ??? This is almost the equivalent of For_All_Source_Dirs
1551 if Process_Source_Dirs then
1553 -- Add to path all source directories of this project if there are
1556 if Has_Ada_Sources (Project) then
1557 Add_To_Source_Path (Project.Source_Dirs, In_Tree, Source_Paths);
1561 if Process_Object_Dirs then
1562 Path := Get_Object_Directory
1564 Including_Libraries => Including_Libraries,
1565 Only_If_Ada => True);
1567 if Path /= No_Path then
1568 Add_To_Object_Path (Path, Object_Paths);
1573 procedure For_All_Projects is
1574 new For_Every_Project_Imported (Boolean, Recursive_Add);
1576 Dummy : Boolean := False;
1578 -- Start of processing for Set_Ada_Paths
1581 -- If it is the first time we call this procedure for this project,
1582 -- compute the source path and/or the object path.
1584 if Project.Include_Path_File = No_Path then
1585 Source_Path_Table.Init (Source_Paths);
1586 Process_Source_Dirs := True;
1587 Create_New_Path_File
1588 (In_Tree, Source_FD, Project.Include_Path_File);
1591 -- For the object path, we make a distinction depending on
1592 -- Including_Libraries.
1594 if Including_Libraries then
1595 if Project.Objects_Path_File_With_Libs = No_Path then
1596 Object_Path_Table.Init (Object_Paths);
1597 Process_Object_Dirs := True;
1598 Create_New_Path_File
1599 (In_Tree, Object_FD, Project.Objects_Path_File_With_Libs);
1603 if Project.Objects_Path_File_Without_Libs = No_Path then
1604 Object_Path_Table.Init (Object_Paths);
1605 Process_Object_Dirs := True;
1606 Create_New_Path_File
1607 (In_Tree, Object_FD, Project.Objects_Path_File_Without_Libs);
1611 -- If there is something to do, set Seen to False for all projects,
1612 -- then call the recursive procedure Add for Project.
1614 if Process_Source_Dirs or Process_Object_Dirs then
1615 For_All_Projects (Project, Dummy);
1618 -- Write and close any file that has been created. Source_FD is not set
1619 -- when this subprogram is called a second time or more, since we reuse
1620 -- the previous version of the file.
1622 if Source_FD /= Invalid_FD then
1625 for Index in Source_Path_Table.First ..
1626 Source_Path_Table.Last (Source_Paths)
1628 Get_Name_String (Source_Paths.Table (Index));
1629 Name_Len := Name_Len + 1;
1630 Name_Buffer (Name_Len) := ASCII.LF;
1631 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
1634 Last := Write (Source_FD, Buffer (1)'Address, Buffer_Last);
1636 if Last = Buffer_Last then
1637 Close (Source_FD, Status);
1644 Prj.Com.Fail ("could not write temporary file");
1648 if Object_FD /= Invalid_FD then
1651 for Index in Object_Path_Table.First ..
1652 Object_Path_Table.Last (Object_Paths)
1654 Get_Name_String (Object_Paths.Table (Index));
1655 Name_Len := Name_Len + 1;
1656 Name_Buffer (Name_Len) := ASCII.LF;
1657 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
1660 Last := Write (Object_FD, Buffer (1)'Address, Buffer_Last);
1662 if Last = Buffer_Last then
1663 Close (Object_FD, Status);
1669 Prj.Com.Fail ("could not write temporary file");
1673 -- Set the env vars, if they need to be changed, and set the
1674 -- corresponding flags.
1676 if In_Tree.Private_Part.Current_Source_Path_File /=
1677 Project.Include_Path_File
1679 In_Tree.Private_Part.Current_Source_Path_File :=
1680 Project.Include_Path_File;
1682 (Project_Include_Path_File,
1683 Get_Name_String (In_Tree.Private_Part.Current_Source_Path_File));
1686 if Including_Libraries then
1687 if In_Tree.Private_Part.Current_Object_Path_File /=
1688 Project.Objects_Path_File_With_Libs
1690 In_Tree.Private_Part.Current_Object_Path_File :=
1691 Project.Objects_Path_File_With_Libs;
1693 (Project_Objects_Path_File,
1695 (In_Tree.Private_Part.Current_Object_Path_File));
1699 if In_Tree.Private_Part.Current_Object_Path_File /=
1700 Project.Objects_Path_File_Without_Libs
1702 In_Tree.Private_Part.Current_Object_Path_File :=
1703 Project.Objects_Path_File_Without_Libs;
1705 (Project_Objects_Path_File,
1707 (In_Tree.Private_Part.Current_Object_Path_File));
1714 -----------------------
1715 -- Set_Path_File_Var --
1716 -----------------------
1718 procedure Set_Path_File_Var (Name : String; Value : String) is
1719 Host_Spec : String_Access := To_Host_File_Spec (Value);
1721 if Host_Spec = null then
1723 ("could not convert file name """ & Value & """ to host spec");
1725 Setenv (Name, Host_Spec.all);
1728 end Set_Path_File_Var;
1730 ---------------------------
1731 -- Ultimate_Extension_Of --
1732 ---------------------------
1734 function Ultimate_Extension_Of
1735 (Project : Project_Id) return Project_Id
1737 Result : Project_Id;
1741 while Result.Extended_By /= No_Project loop
1742 Result := Result.Extended_By;
1746 end Ultimate_Extension_Of;