1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2001-2011, 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 Makeutl; use Makeutl;
30 with Osint; use Osint;
31 with Output; use Output;
32 with Prj.Com; use Prj.Com;
36 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
38 package body Prj.Env is
40 Buffer_Initial : constant := 1_000;
41 -- Initial size of Buffer
43 Uninitialized_Prefix : constant String := '#' & Path_Separator;
44 -- Prefix to indicate that the project path has not been initialized yet.
45 -- Must be two characters long
47 No_Project_Default_Dir : constant String := "-";
48 -- Indicator in the project path to indicate that the default search
49 -- directories should not be added to the path
51 -----------------------
52 -- Local Subprograms --
53 -----------------------
55 package Source_Path_Table is new GNAT.Dynamic_Tables
56 (Table_Component_Type => Name_Id,
57 Table_Index_Type => Natural,
60 Table_Increment => 100);
61 -- A table to store the source dirs before creating the source path file
63 package Object_Path_Table is new GNAT.Dynamic_Tables
64 (Table_Component_Type => Path_Name_Type,
65 Table_Index_Type => Natural,
68 Table_Increment => 100);
69 -- A table to store the object dirs, before creating the object path file
71 procedure Add_To_Buffer
73 Buffer : in out String_Access;
74 Buffer_Last : in out Natural);
75 -- Add a string to Buffer, extending Buffer if needed
78 (Source_Dirs : String_List_Id;
79 Shared : Shared_Project_Tree_Data_Access;
80 Buffer : in out String_Access;
81 Buffer_Last : in out Natural);
82 -- Add to Ada_Path_Buffer all the source directories in string list
83 -- Source_Dirs, if any.
87 Buffer : in out String_Access;
88 Buffer_Last : in out Natural);
89 -- If Dir is not already in the global variable Ada_Path_Buffer, add it.
90 -- If Buffer_Last /= 0, prepend a Path_Separator character to Path.
92 procedure Add_To_Source_Path
93 (Source_Dirs : String_List_Id;
94 Shared : Shared_Project_Tree_Data_Access;
95 Source_Paths : in out Source_Path_Table.Instance);
96 -- Add to Ada_Path_B all the source directories in string list
97 -- Source_Dirs, if any. Increment Ada_Path_Length.
99 procedure Add_To_Object_Path
100 (Object_Dir : Path_Name_Type;
101 Object_Paths : in out Object_Path_Table.Instance);
102 -- Add Object_Dir to object path table. Make sure it is not duplicate
103 -- and it is the last one in the current table.
105 procedure Set_Path_File_Var (Name : String; Value : String);
106 -- Call Setenv, after calling To_Host_File_Spec
108 function Ultimate_Extension_Of
109 (Project : Project_Id) return Project_Id;
110 -- Return a project that is either Project or an extended ancestor of
111 -- Project that itself is not extended.
113 ----------------------
114 -- Ada_Include_Path --
115 ----------------------
117 function Ada_Include_Path
118 (Project : Project_Id;
119 In_Tree : Project_Tree_Ref;
120 Recursive : Boolean := False) return String
122 Buffer : String_Access;
123 Buffer_Last : Natural := 0;
126 (Project : Project_Id;
127 In_Tree : Project_Tree_Ref;
128 Dummy : in out Boolean);
129 -- Add source dirs of Project to the path
136 (Project : Project_Id;
137 In_Tree : Project_Tree_Ref;
138 Dummy : in out Boolean)
140 pragma Unreferenced (Dummy);
143 (Project.Source_Dirs, In_Tree.Shared, Buffer, Buffer_Last);
146 procedure For_All_Projects is
147 new For_Every_Project_Imported (Boolean, Add);
149 Dummy : Boolean := False;
151 -- Start of processing for Ada_Include_Path
156 -- If it is the first time we call this function for
157 -- this project, compute the source path
159 if Project.Ada_Include_Path = null then
160 Buffer := new String (1 .. 4096);
162 (Project, In_Tree, Dummy, Include_Aggregated => True);
163 Project.Ada_Include_Path := new String'(Buffer (1 .. Buffer_Last));
167 return Project.Ada_Include_Path.all;
170 Buffer := new String (1 .. 4096);
172 (Project.Source_Dirs, In_Tree.Shared, Buffer, Buffer_Last);
175 Result : constant String := Buffer (1 .. Buffer_Last);
181 end Ada_Include_Path;
183 ----------------------
184 -- Ada_Objects_Path --
185 ----------------------
187 function Ada_Objects_Path
188 (Project : Project_Id;
189 In_Tree : Project_Tree_Ref;
190 Including_Libraries : Boolean := True) return String_Access
192 Buffer : String_Access;
193 Buffer_Last : Natural := 0;
196 (Project : Project_Id;
197 In_Tree : Project_Tree_Ref;
198 Dummy : in out Boolean);
199 -- Add all the object directories of a project to the path
206 (Project : Project_Id;
207 In_Tree : Project_Tree_Ref;
208 Dummy : in out Boolean)
210 pragma Unreferenced (Dummy, In_Tree);
212 Path : constant Path_Name_Type :=
215 Including_Libraries => Including_Libraries,
216 Only_If_Ada => False);
218 if Path /= No_Path then
219 Add_To_Path (Get_Name_String (Path), Buffer, Buffer_Last);
223 procedure For_All_Projects is
224 new For_Every_Project_Imported (Boolean, Add);
226 Dummy : Boolean := False;
228 -- Start of processing for Ada_Objects_Path
231 -- If it is the first time we call this function for
232 -- this project, compute the objects path
234 if Project.Ada_Objects_Path = null then
235 Buffer := new String (1 .. 4096);
236 For_All_Projects (Project, In_Tree, Dummy);
238 Project.Ada_Objects_Path := new String'(Buffer (1 .. Buffer_Last));
242 return Project.Ada_Objects_Path;
243 end Ada_Objects_Path;
249 procedure Add_To_Buffer
251 Buffer : in out String_Access;
252 Buffer_Last : in out Natural)
254 Last : constant Natural := Buffer_Last + S'Length;
257 while Last > Buffer'Last loop
259 New_Buffer : constant String_Access :=
260 new String (1 .. 2 * Buffer'Last);
262 New_Buffer (1 .. Buffer_Last) := Buffer (1 .. Buffer_Last);
264 Buffer := New_Buffer;
268 Buffer (Buffer_Last + 1 .. Last) := S;
272 ------------------------
273 -- Add_To_Object_Path --
274 ------------------------
276 procedure Add_To_Object_Path
277 (Object_Dir : Path_Name_Type;
278 Object_Paths : in out Object_Path_Table.Instance)
281 -- Check if the directory is already in the table
283 for Index in Object_Path_Table.First ..
284 Object_Path_Table.Last (Object_Paths)
287 -- If it is, remove it, and add it as the last one
289 if Object_Paths.Table (Index) = Object_Dir then
290 for Index2 in Index + 1 ..
291 Object_Path_Table.Last (Object_Paths)
293 Object_Paths.Table (Index2 - 1) := Object_Paths.Table (Index2);
297 (Object_Path_Table.Last (Object_Paths)) := Object_Dir;
302 -- The directory is not already in the table, add it
304 Object_Path_Table.Append (Object_Paths, Object_Dir);
305 end Add_To_Object_Path;
311 procedure Add_To_Path
312 (Source_Dirs : String_List_Id;
313 Shared : Shared_Project_Tree_Data_Access;
314 Buffer : in out String_Access;
315 Buffer_Last : in out Natural)
317 Current : String_List_Id := Source_Dirs;
318 Source_Dir : String_Element;
320 while Current /= Nil_String loop
321 Source_Dir := Shared.String_Elements.Table (Current);
322 Add_To_Path (Get_Name_String (Source_Dir.Display_Value),
323 Buffer, Buffer_Last);
324 Current := Source_Dir.Next;
328 procedure Add_To_Path
330 Buffer : in out String_Access;
331 Buffer_Last : in out Natural)
334 New_Buffer : String_Access;
337 function Is_Present (Path : String; Dir : String) return Boolean;
338 -- Return True if Dir is part of Path
344 function Is_Present (Path : String; Dir : String) return Boolean is
345 Last : constant Integer := Path'Last - Dir'Length + 1;
348 for J in Path'First .. Last loop
350 -- Note: the order of the conditions below is important, since
351 -- it ensures a minimal number of string comparisons.
354 or else Path (J - 1) = Path_Separator)
356 (J + Dir'Length > Path'Last
357 or else Path (J + Dir'Length) = Path_Separator)
358 and then Dir = Path (J .. J + Dir'Length - 1)
367 -- Start of processing for Add_To_Path
370 if Is_Present (Buffer (1 .. Buffer_Last), Dir) then
372 -- Dir is already in the path, nothing to do
377 Min_Len := Buffer_Last + Dir'Length;
379 if Buffer_Last > 0 then
381 -- Add 1 for the Path_Separator character
383 Min_Len := Min_Len + 1;
386 -- If Ada_Path_Buffer is too small, increase it
390 if Len < Min_Len then
393 exit when Len >= Min_Len;
396 New_Buffer := new String (1 .. Len);
397 New_Buffer (1 .. Buffer_Last) := Buffer (1 .. Buffer_Last);
399 Buffer := New_Buffer;
402 if Buffer_Last > 0 then
403 Buffer_Last := Buffer_Last + 1;
404 Buffer (Buffer_Last) := Path_Separator;
407 Buffer (Buffer_Last + 1 .. Buffer_Last + Dir'Length) := Dir;
408 Buffer_Last := Buffer_Last + Dir'Length;
411 ------------------------
412 -- Add_To_Source_Path --
413 ------------------------
415 procedure Add_To_Source_Path
416 (Source_Dirs : String_List_Id;
417 Shared : Shared_Project_Tree_Data_Access;
418 Source_Paths : in out Source_Path_Table.Instance)
420 Current : String_List_Id := Source_Dirs;
421 Source_Dir : String_Element;
425 -- Add each source directory
427 while Current /= Nil_String loop
428 Source_Dir := Shared.String_Elements.Table (Current);
431 -- Check if the source directory is already in the table
433 for Index in Source_Path_Table.First ..
434 Source_Path_Table.Last (Source_Paths)
436 -- If it is already, no need to add it
438 if Source_Paths.Table (Index) = Source_Dir.Value then
445 Source_Path_Table.Append (Source_Paths, Source_Dir.Display_Value);
448 -- Next source directory
450 Current := Source_Dir.Next;
452 end Add_To_Source_Path;
454 --------------------------------
455 -- Create_Config_Pragmas_File --
456 --------------------------------
458 procedure Create_Config_Pragmas_File
459 (For_Project : Project_Id;
460 In_Tree : Project_Tree_Ref)
462 type Naming_Id is new Nat;
463 package Naming_Table is new GNAT.Dynamic_Tables
464 (Table_Component_Type => Lang_Naming_Data,
465 Table_Index_Type => Naming_Id,
466 Table_Low_Bound => 1,
468 Table_Increment => 100);
469 Default_Naming : constant Naming_Id := Naming_Table.First;
470 Namings : Naming_Table.Instance;
471 -- Table storing the naming data for gnatmake/gprmake
473 Buffer : String_Access := new String (1 .. Buffer_Initial);
474 Buffer_Last : Natural := 0;
476 File_Name : Path_Name_Type := No_Path;
477 File : File_Descriptor := Invalid_FD;
479 Current_Naming : Naming_Id;
480 Iter : Source_Iterator;
484 (Project : Project_Id;
485 In_Tree : Project_Tree_Ref;
486 State : in out Integer);
487 -- Recursive procedure that put in the config pragmas file any non
488 -- standard naming schemes, if it is not already in the file, then call
489 -- itself for any imported project.
491 procedure Put (Source : Source_Id);
492 -- Put an SFN pragma in the temporary file
494 procedure Put (S : String);
495 procedure Put_Line (S : String);
496 -- Output procedures, analogous to normal Text_IO procs of same name.
497 -- The text is put in Buffer, then it will be written into a temporary
498 -- file with procedure Write_Temp_File below.
500 procedure Write_Temp_File;
501 -- Create a temporary file and put the content of the buffer in it
508 (Project : Project_Id;
509 In_Tree : Project_Tree_Ref;
510 State : in out Integer)
512 pragma Unreferenced (State, In_Tree);
514 Lang : constant Language_Ptr :=
515 Get_Language_From_Name (Project, "ada");
516 Naming : Lang_Naming_Data;
519 if Current_Verbosity = High then
520 Debug_Output ("Checking project file:", Project.Name);
524 if Current_Verbosity = High then
525 Debug_Output ("Languages does not contain Ada, nothing to do");
531 Naming := Lang.Config.Naming_Data;
533 -- Is the naming scheme of this project one that we know?
535 Current_Naming := Default_Naming;
536 while Current_Naming <= Naming_Table.Last (Namings)
537 and then Namings.Table (Current_Naming).Dot_Replacement =
538 Naming.Dot_Replacement
539 and then Namings.Table (Current_Naming).Casing =
541 and then Namings.Table (Current_Naming).Separate_Suffix =
542 Naming.Separate_Suffix
544 Current_Naming := Current_Naming + 1;
547 -- If we don't know it, add it
549 if Current_Naming > Naming_Table.Last (Namings) then
550 Naming_Table.Increment_Last (Namings);
551 Namings.Table (Naming_Table.Last (Namings)) := Naming;
553 -- Put the SFN pragmas for the naming scheme
558 ("pragma Source_File_Name_Project");
560 (" (Spec_File_Name => ""*" &
561 Get_Name_String (Naming.Spec_Suffix) & """,");
564 Image (Naming.Casing) & ",");
566 (" Dot_Replacement => """ &
567 Get_Name_String (Naming.Dot_Replacement) & """);");
572 ("pragma Source_File_Name_Project");
574 (" (Body_File_Name => ""*" &
575 Get_Name_String (Naming.Body_Suffix) & """,");
578 Image (Naming.Casing) & ",");
580 (" Dot_Replacement => """ &
581 Get_Name_String (Naming.Dot_Replacement) &
584 -- and maybe separate
586 if Naming.Body_Suffix /= Naming.Separate_Suffix then
587 Put_Line ("pragma Source_File_Name_Project");
589 (" (Subunit_File_Name => ""*" &
590 Get_Name_String (Naming.Separate_Suffix) & """,");
593 Image (Naming.Casing) & ",");
595 (" Dot_Replacement => """ &
596 Get_Name_String (Naming.Dot_Replacement) &
606 procedure Put (Source : Source_Id) is
608 -- Put the pragma SFN for the unit kind (spec or body)
610 Put ("pragma Source_File_Name_Project (");
611 Put (Namet.Get_Name_String (Source.Unit.Name));
613 if Source.Kind = Spec then
614 Put (", Spec_File_Name => """);
616 Put (", Body_File_Name => """);
619 Put (Namet.Get_Name_String (Source.File));
622 if Source.Index /= 0 then
624 Put (Source.Index'Img);
630 procedure Put (S : String) is
632 Add_To_Buffer (S, Buffer, Buffer_Last);
634 if Current_Verbosity = High then
643 procedure Put_Line (S : String) is
645 -- Add an ASCII.LF to the string. As this config file is supposed to
646 -- be used only by the compiler, we don't care about the characters
647 -- for the end of line. In fact we could have put a space, but
648 -- it is more convenient to be able to read gnat.adc during
649 -- development, for which the ASCII.LF is fine.
652 Put (S => (1 => ASCII.LF));
655 ---------------------
656 -- Write_Temp_File --
657 ---------------------
659 procedure Write_Temp_File is
660 Status : Boolean := False;
664 Tempdir.Create_Temp_File (File, File_Name);
666 if File /= Invalid_FD then
667 Last := Write (File, Buffer (1)'Address, Buffer_Last);
669 if Last = Buffer_Last then
670 Close (File, Status);
675 Prj.Com.Fail ("unable to create temporary file");
679 procedure Check_Imported_Projects is
680 new For_Every_Project_Imported (Integer, Check);
682 Dummy : Integer := 0;
684 -- Start of processing for Create_Config_Pragmas_File
687 if not For_Project.Config_Checked then
688 Naming_Table.Init (Namings);
690 -- Check the naming schemes
692 Check_Imported_Projects
693 (For_Project, In_Tree, Dummy, Imported_First => False);
695 -- Visit all the files and process those that need an SFN pragma
697 Iter := For_Each_Source (In_Tree, For_Project);
698 while Element (Iter) /= No_Source loop
699 Source := Element (Iter);
702 and then not Source.Locally_Removed
703 and then Source.Unit /= null
711 -- If there are no non standard naming scheme, issue the GNAT
712 -- standard naming scheme. This will tell the compiler that
713 -- a project file is used and will forbid any pragma SFN.
715 if Buffer_Last = 0 then
717 Put_Line ("pragma Source_File_Name_Project");
718 Put_Line (" (Spec_File_Name => ""*.ads"",");
719 Put_Line (" Dot_Replacement => ""-"",");
720 Put_Line (" Casing => lowercase);");
722 Put_Line ("pragma Source_File_Name_Project");
723 Put_Line (" (Body_File_Name => ""*.adb"",");
724 Put_Line (" Dot_Replacement => ""-"",");
725 Put_Line (" Casing => lowercase);");
728 -- Close the temporary file
732 if Opt.Verbose_Mode then
733 Write_Str ("Created configuration file """);
734 Write_Str (Get_Name_String (File_Name));
738 For_Project.Config_File_Name := File_Name;
739 For_Project.Config_File_Temp := True;
740 For_Project.Config_Checked := True;
744 end Create_Config_Pragmas_File;
750 procedure Create_Mapping (In_Tree : Project_Tree_Ref) is
752 Iter : Source_Iterator;
757 Iter := For_Each_Source (In_Tree);
759 Data := Element (Iter);
760 exit when Data = No_Source;
762 if Data.Unit /= No_Unit_Index then
763 if Data.Locally_Removed then
764 Fmap.Add_Forbidden_File_Name (Data.File);
767 (Unit_Name => Unit_Name_Type (Data.Unit.Name),
768 File_Name => Data.File,
769 Path_Name => File_Name_Type (Data.Path.Display_Name));
777 -------------------------
778 -- Create_Mapping_File --
779 -------------------------
781 procedure Create_Mapping_File
782 (Project : Project_Id;
784 In_Tree : Project_Tree_Ref;
785 Name : out Path_Name_Type)
787 File : File_Descriptor := Invalid_FD;
789 Buffer : String_Access := new String (1 .. Buffer_Initial);
790 Buffer_Last : Natural := 0;
792 procedure Put_Name_Buffer;
793 -- Put the line contained in the Name_Buffer in the global buffer
796 (Project : Project_Id;
797 In_Tree : Project_Tree_Ref;
798 State : in out Integer);
799 -- Generate the mapping file for Project (not recursively)
801 ---------------------
802 -- Put_Name_Buffer --
803 ---------------------
805 procedure Put_Name_Buffer is
807 if Current_Verbosity = High then
808 Debug_Output (Name_Buffer (1 .. Name_Len));
811 Name_Len := Name_Len + 1;
812 Name_Buffer (Name_Len) := ASCII.LF;
813 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
821 (Project : Project_Id;
822 In_Tree : Project_Tree_Ref;
823 State : in out Integer)
825 pragma Unreferenced (State);
828 Suffix : File_Name_Type;
829 Iter : Source_Iterator;
832 Iter := For_Each_Source (In_Tree, Project, Language => Language);
835 Source := Prj.Element (Iter);
836 exit when Source = No_Source;
838 if Source.Replaced_By = No_Source
839 and then Source.Path.Name /= No_Path
841 (Source.Language.Config.Kind = File_Based
842 or else Source.Unit /= No_Unit_Index)
844 if Source.Unit /= No_Unit_Index then
845 Get_Name_String (Source.Unit.Name);
847 if Source.Language.Config.Kind = Unit_Based then
849 -- ??? Mapping_Spec_Suffix could be set in the case of
852 Add_Char_To_Name_Buffer ('%');
854 if Source.Kind = Spec then
855 Add_Char_To_Name_Buffer ('s');
857 Add_Char_To_Name_Buffer ('b');
864 Source.Language.Config.Mapping_Spec_Suffix;
867 Source.Language.Config.Mapping_Body_Suffix;
870 if Suffix /= No_File then
871 Add_Str_To_Name_Buffer
872 (Get_Name_String (Suffix));
879 Get_Name_String (Source.Display_File);
882 if Source.Locally_Removed then
884 Name_Buffer (1) := '/';
886 Get_Name_String (Source.Path.Display_Name);
896 procedure For_Every_Imported_Project is new
897 For_Every_Project_Imported (State => Integer, Action => Process);
899 Dummy : Integer := 0;
901 -- Start of processing for Create_Mapping_File
904 Create_Temp_File (In_Tree, File, Name, "mapping");
906 if Current_Verbosity = High then
907 Debug_Increase_Indent ("Create mapping file ", Name_Id (Name));
910 For_Every_Imported_Project (Project, In_Tree, Dummy);
914 Status : Boolean := False;
917 if File /= Invalid_FD then
918 Last := Write (File, Buffer (1)'Address, Buffer_Last);
920 if Last = Buffer_Last then
921 GNAT.OS_Lib.Close (File, Status);
926 Prj.Com.Fail ("could not write mapping file");
932 Debug_Decrease_Indent ("Done create mapping file");
933 end Create_Mapping_File;
935 ----------------------
936 -- Create_Temp_File --
937 ----------------------
939 procedure Create_Temp_File
940 (In_Tree : Project_Tree_Ref;
941 Path_FD : out File_Descriptor;
942 Path_Name : out Path_Name_Type;
946 Tempdir.Create_Temp_File (Path_FD, Path_Name);
948 if Path_Name /= No_Path then
949 if Current_Verbosity = High then
950 Write_Line ("Create temp file (" & File_Use & ") "
951 & Get_Name_String (Path_Name));
954 Record_Temp_File (In_Tree, Path_Name);
958 ("unable to create temporary " & File_Use & " file");
960 end Create_Temp_File;
962 --------------------------
963 -- Create_New_Path_File --
964 --------------------------
966 procedure Create_New_Path_File
967 (In_Tree : Project_Tree_Ref;
968 Path_FD : out File_Descriptor;
969 Path_Name : out Path_Name_Type)
972 Create_Temp_File (In_Tree, Path_FD, Path_Name, "path file");
973 end Create_New_Path_File;
975 ------------------------------------
976 -- File_Name_Of_Library_Unit_Body --
977 ------------------------------------
979 function File_Name_Of_Library_Unit_Body
981 Project : Project_Id;
982 In_Tree : Project_Tree_Ref;
983 Main_Project_Only : Boolean := True;
984 Full_Path : Boolean := False) return String
986 The_Project : Project_Id := Project;
987 Original_Name : String := Name;
989 Lang : constant Language_Ptr :=
990 Get_Language_From_Name (Project, "ada");
993 The_Original_Name : Name_Id;
994 The_Spec_Name : Name_Id;
995 The_Body_Name : Name_Id;
998 -- ??? Same block in Project_Of
999 Canonical_Case_File_Name (Original_Name);
1000 Name_Len := Original_Name'Length;
1001 Name_Buffer (1 .. Name_Len) := Original_Name;
1002 The_Original_Name := Name_Find;
1004 if Lang /= null then
1006 Naming : constant Lang_Naming_Data := Lang.Config.Naming_Data;
1007 Extended_Spec_Name : String :=
1008 Name & Namet.Get_Name_String
1009 (Naming.Spec_Suffix);
1010 Extended_Body_Name : String :=
1011 Name & Namet.Get_Name_String
1012 (Naming.Body_Suffix);
1015 Canonical_Case_File_Name (Extended_Spec_Name);
1016 Name_Len := Extended_Spec_Name'Length;
1017 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1018 The_Spec_Name := Name_Find;
1020 Canonical_Case_File_Name (Extended_Body_Name);
1021 Name_Len := Extended_Body_Name'Length;
1022 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1023 The_Body_Name := Name_Find;
1027 Name_Len := Name'Length;
1028 Name_Buffer (1 .. Name_Len) := Name;
1029 Canonical_Case_File_Name (Name_Buffer);
1030 The_Spec_Name := Name_Find;
1031 The_Body_Name := The_Spec_Name;
1034 if Current_Verbosity = High then
1035 Write_Str ("Looking for file name of """);
1039 Write_Str (" Extended Spec Name = """);
1040 Write_Str (Get_Name_String (The_Spec_Name));
1043 Write_Str (" Extended Body Name = """);
1044 Write_Str (Get_Name_String (The_Body_Name));
1049 -- For extending project, search in the extended project if the source
1050 -- is not found. For non extending projects, this loop will be run only
1054 -- Loop through units
1056 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1057 while Unit /= null loop
1060 if not Main_Project_Only
1062 (Unit.File_Names (Impl) /= null
1063 and then Unit.File_Names (Impl).Project = The_Project)
1066 Current_Name : File_Name_Type;
1068 -- Case of a body present
1070 if Unit.File_Names (Impl) /= null then
1071 Current_Name := Unit.File_Names (Impl).File;
1073 if Current_Verbosity = High then
1074 Write_Str (" Comparing with """);
1075 Write_Str (Get_Name_String (Current_Name));
1080 -- If it has the name of the original name, return the
1083 if Unit.Name = The_Original_Name
1085 Current_Name = File_Name_Type (The_Original_Name)
1087 if Current_Verbosity = High then
1092 return Get_Name_String
1093 (Unit.File_Names (Impl).Path.Name);
1096 return Get_Name_String (Current_Name);
1099 -- If it has the name of the extended body name,
1100 -- return the extended body name
1102 elsif Current_Name = File_Name_Type (The_Body_Name) then
1103 if Current_Verbosity = High then
1108 return Get_Name_String
1109 (Unit.File_Names (Impl).Path.Name);
1112 return Get_Name_String (The_Body_Name);
1116 if Current_Verbosity = High then
1117 Write_Line (" not good");
1126 if not Main_Project_Only
1128 (Unit.File_Names (Spec) /= null
1129 and then Unit.File_Names (Spec).Project =
1133 Current_Name : File_Name_Type;
1136 -- Case of spec present
1138 if Unit.File_Names (Spec) /= null then
1139 Current_Name := Unit.File_Names (Spec).File;
1140 if Current_Verbosity = High then
1141 Write_Str (" Comparing with """);
1142 Write_Str (Get_Name_String (Current_Name));
1147 -- If name same as original name, return original name
1149 if Unit.Name = The_Original_Name
1151 Current_Name = File_Name_Type (The_Original_Name)
1153 if Current_Verbosity = High then
1158 return Get_Name_String
1159 (Unit.File_Names (Spec).Path.Name);
1161 return Get_Name_String (Current_Name);
1164 -- If it has the same name as the extended spec name,
1165 -- return the extended spec name.
1167 elsif Current_Name = File_Name_Type (The_Spec_Name) then
1168 if Current_Verbosity = High then
1173 return Get_Name_String
1174 (Unit.File_Names (Spec).Path.Name);
1176 return Get_Name_String (The_Spec_Name);
1180 if Current_Verbosity = High then
1181 Write_Line (" not good");
1188 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1191 -- If we are not in an extending project, give up
1193 exit when not Main_Project_Only
1194 or else The_Project.Extends = No_Project;
1196 -- Otherwise, look in the project we are extending
1198 The_Project := The_Project.Extends;
1201 -- We don't know this file name, return an empty string
1204 end File_Name_Of_Library_Unit_Body;
1206 -------------------------
1207 -- For_All_Object_Dirs --
1208 -------------------------
1210 procedure For_All_Object_Dirs
1211 (Project : Project_Id;
1212 Tree : Project_Tree_Ref)
1214 procedure For_Project
1216 Tree : Project_Tree_Ref;
1217 Dummy : in out Integer);
1218 -- Get all object directories of Prj
1224 procedure For_Project
1226 Tree : Project_Tree_Ref;
1227 Dummy : in out Integer)
1229 pragma Unreferenced (Dummy, Tree);
1232 -- ??? Set_Ada_Paths has a different behavior for library project
1233 -- files, should we have the same ?
1235 if Prj.Object_Directory /= No_Path_Information then
1236 Get_Name_String (Prj.Object_Directory.Display_Name);
1237 Action (Name_Buffer (1 .. Name_Len));
1241 procedure Get_Object_Dirs is
1242 new For_Every_Project_Imported (Integer, For_Project);
1243 Dummy : Integer := 1;
1245 -- Start of processing for For_All_Object_Dirs
1248 Get_Object_Dirs (Project, Tree, Dummy);
1249 end For_All_Object_Dirs;
1251 -------------------------
1252 -- For_All_Source_Dirs --
1253 -------------------------
1255 procedure For_All_Source_Dirs
1256 (Project : Project_Id;
1257 In_Tree : Project_Tree_Ref)
1259 procedure For_Project
1261 In_Tree : Project_Tree_Ref;
1262 Dummy : in out Integer);
1263 -- Get all object directories of Prj
1269 procedure For_Project
1271 In_Tree : Project_Tree_Ref;
1272 Dummy : in out Integer)
1274 pragma Unreferenced (Dummy);
1276 Current : String_List_Id := Prj.Source_Dirs;
1277 The_String : String_Element;
1280 -- If there are Ada sources, call action with the name of every
1281 -- source directory.
1283 if Has_Ada_Sources (Project) then
1284 while Current /= Nil_String loop
1285 The_String := In_Tree.Shared.String_Elements.Table (Current);
1286 Action (Get_Name_String (The_String.Display_Value));
1287 Current := The_String.Next;
1292 procedure Get_Source_Dirs is
1293 new For_Every_Project_Imported (Integer, For_Project);
1294 Dummy : Integer := 1;
1296 -- Start of processing for For_All_Source_Dirs
1299 Get_Source_Dirs (Project, In_Tree, Dummy);
1300 end For_All_Source_Dirs;
1306 procedure Get_Reference
1307 (Source_File_Name : String;
1308 In_Tree : Project_Tree_Ref;
1309 Project : out Project_Id;
1310 Path : out Path_Name_Type)
1313 -- Body below could use some comments ???
1315 if Current_Verbosity > Default then
1316 Write_Str ("Getting Reference_Of (""");
1317 Write_Str (Source_File_Name);
1318 Write_Str (""") ... ");
1322 Original_Name : String := Source_File_Name;
1326 Canonical_Case_File_Name (Original_Name);
1327 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1329 while Unit /= null loop
1330 if Unit.File_Names (Spec) /= null
1331 and then Unit.File_Names (Spec).File /= No_File
1333 (Namet.Get_Name_String
1334 (Unit.File_Names (Spec).File) = Original_Name
1335 or else (Unit.File_Names (Spec).Path /=
1338 Namet.Get_Name_String
1339 (Unit.File_Names (Spec).Path.Name) =
1342 Project := Ultimate_Extension_Of
1343 (Project => Unit.File_Names (Spec).Project);
1344 Path := Unit.File_Names (Spec).Path.Display_Name;
1346 if Current_Verbosity > Default then
1347 Write_Str ("Done: Spec.");
1353 elsif Unit.File_Names (Impl) /= null
1354 and then Unit.File_Names (Impl).File /= No_File
1356 (Namet.Get_Name_String
1357 (Unit.File_Names (Impl).File) = Original_Name
1358 or else (Unit.File_Names (Impl).Path /=
1360 and then Namet.Get_Name_String
1361 (Unit.File_Names (Impl).Path.Name) =
1364 Project := Ultimate_Extension_Of
1365 (Project => Unit.File_Names (Impl).Project);
1366 Path := Unit.File_Names (Impl).Path.Display_Name;
1368 if Current_Verbosity > Default then
1369 Write_Str ("Done: Body.");
1376 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1380 Project := No_Project;
1383 if Current_Verbosity > Default then
1384 Write_Str ("Cannot be found.");
1393 procedure Initialize (In_Tree : Project_Tree_Ref) is
1395 In_Tree.Private_Part.Current_Source_Path_File := No_Path;
1396 In_Tree.Private_Part.Current_Object_Path_File := No_Path;
1403 -- Could use some comments in this body ???
1405 procedure Print_Sources (In_Tree : Project_Tree_Ref) is
1409 Write_Line ("List of Sources:");
1411 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1413 while Unit /= No_Unit_Index loop
1415 Write_Line (Namet.Get_Name_String (Unit.Name));
1417 if Unit.File_Names (Spec).File /= No_File then
1418 if Unit.File_Names (Spec).Project = No_Project then
1419 Write_Line (" No project");
1422 Write_Str (" Project: ");
1424 (Unit.File_Names (Spec).Project.Path.Name);
1425 Write_Line (Name_Buffer (1 .. Name_Len));
1428 Write_Str (" spec: ");
1430 (Namet.Get_Name_String
1431 (Unit.File_Names (Spec).File));
1434 if Unit.File_Names (Impl).File /= No_File then
1435 if Unit.File_Names (Impl).Project = No_Project then
1436 Write_Line (" No project");
1439 Write_Str (" Project: ");
1441 (Unit.File_Names (Impl).Project.Path.Name);
1442 Write_Line (Name_Buffer (1 .. Name_Len));
1445 Write_Str (" body: ");
1447 (Namet.Get_Name_String (Unit.File_Names (Impl).File));
1450 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1453 Write_Line ("end of List of Sources.");
1462 Main_Project : Project_Id;
1463 In_Tree : Project_Tree_Ref) return Project_Id
1465 Result : Project_Id := No_Project;
1467 Original_Name : String := Name;
1469 Lang : constant Language_Ptr :=
1470 Get_Language_From_Name (Main_Project, "ada");
1474 Current_Name : File_Name_Type;
1475 The_Original_Name : File_Name_Type;
1476 The_Spec_Name : File_Name_Type;
1477 The_Body_Name : File_Name_Type;
1480 -- ??? Same block in File_Name_Of_Library_Unit_Body
1481 Canonical_Case_File_Name (Original_Name);
1482 Name_Len := Original_Name'Length;
1483 Name_Buffer (1 .. Name_Len) := Original_Name;
1484 The_Original_Name := Name_Find;
1486 if Lang /= null then
1488 Naming : Lang_Naming_Data renames Lang.Config.Naming_Data;
1489 Extended_Spec_Name : String :=
1490 Name & Namet.Get_Name_String
1491 (Naming.Spec_Suffix);
1492 Extended_Body_Name : String :=
1493 Name & Namet.Get_Name_String
1494 (Naming.Body_Suffix);
1497 Canonical_Case_File_Name (Extended_Spec_Name);
1498 Name_Len := Extended_Spec_Name'Length;
1499 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1500 The_Spec_Name := Name_Find;
1502 Canonical_Case_File_Name (Extended_Body_Name);
1503 Name_Len := Extended_Body_Name'Length;
1504 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1505 The_Body_Name := Name_Find;
1509 The_Spec_Name := The_Original_Name;
1510 The_Body_Name := The_Original_Name;
1513 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1514 while Unit /= null loop
1516 -- Case of a body present
1518 if Unit.File_Names (Impl) /= null then
1519 Current_Name := Unit.File_Names (Impl).File;
1521 -- If it has the name of the original name or the body name,
1522 -- we have found the project.
1524 if Unit.Name = Name_Id (The_Original_Name)
1525 or else Current_Name = The_Original_Name
1526 or else Current_Name = The_Body_Name
1528 Result := Unit.File_Names (Impl).Project;
1535 if Unit.File_Names (Spec) /= null then
1536 Current_Name := Unit.File_Names (Spec).File;
1538 -- If name same as the original name, or the spec name, we have
1539 -- found the project.
1541 if Unit.Name = Name_Id (The_Original_Name)
1542 or else Current_Name = The_Original_Name
1543 or else Current_Name = The_Spec_Name
1545 Result := Unit.File_Names (Spec).Project;
1550 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1553 -- Get the ultimate extending project
1555 if Result /= No_Project then
1556 while Result.Extended_By /= No_Project loop
1557 Result := Result.Extended_By;
1568 procedure Set_Ada_Paths
1569 (Project : Project_Id;
1570 In_Tree : Project_Tree_Ref;
1571 Including_Libraries : Boolean;
1572 Include_Path : Boolean := True;
1573 Objects_Path : Boolean := True)
1576 Source_Paths : Source_Path_Table.Instance;
1577 Object_Paths : Object_Path_Table.Instance;
1578 -- List of source or object dirs. Only computed the first time this
1579 -- procedure is called (since Source_FD is then reused)
1581 Source_FD : File_Descriptor := Invalid_FD;
1582 Object_FD : File_Descriptor := Invalid_FD;
1583 -- The temporary files to store the paths. These are only created the
1584 -- first time this procedure is called, and reused from then on.
1586 Process_Source_Dirs : Boolean := False;
1587 Process_Object_Dirs : Boolean := False;
1590 -- For calls to Close
1593 Buffer : String_Access := new String (1 .. Buffer_Initial);
1594 Buffer_Last : Natural := 0;
1596 procedure Recursive_Add
1597 (Project : Project_Id;
1598 In_Tree : Project_Tree_Ref;
1599 Dummy : in out Boolean);
1600 -- Recursive procedure to add the source/object paths of extended/
1601 -- imported projects.
1607 procedure Recursive_Add
1608 (Project : Project_Id;
1609 In_Tree : Project_Tree_Ref;
1610 Dummy : in out Boolean)
1612 pragma Unreferenced (Dummy);
1614 Path : Path_Name_Type;
1617 -- ??? This is almost the equivalent of For_All_Source_Dirs
1619 if Process_Source_Dirs then
1621 -- Add to path all source directories of this project if there are
1624 if Has_Ada_Sources (Project) then
1626 (Project.Source_Dirs, In_Tree.Shared, Source_Paths);
1630 if Process_Object_Dirs then
1631 Path := Get_Object_Directory
1633 Including_Libraries => Including_Libraries,
1634 Only_If_Ada => True);
1636 if Path /= No_Path then
1637 Add_To_Object_Path (Path, Object_Paths);
1642 procedure For_All_Projects is
1643 new For_Every_Project_Imported (Boolean, Recursive_Add);
1645 Dummy : Boolean := False;
1647 -- Start of processing for Set_Ada_Paths
1650 -- If it is the first time we call this procedure for this project,
1651 -- compute the source path and/or the object path.
1653 if Include_Path and then Project.Include_Path_File = No_Path then
1654 Source_Path_Table.Init (Source_Paths);
1655 Process_Source_Dirs := True;
1656 Create_New_Path_File
1657 (In_Tree, Source_FD, Project.Include_Path_File);
1660 -- For the object path, we make a distinction depending on
1661 -- Including_Libraries.
1663 if Objects_Path and Including_Libraries then
1664 if Project.Objects_Path_File_With_Libs = No_Path then
1665 Object_Path_Table.Init (Object_Paths);
1666 Process_Object_Dirs := True;
1667 Create_New_Path_File
1668 (In_Tree, Object_FD, Project.Objects_Path_File_With_Libs);
1671 elsif Objects_Path then
1672 if Project.Objects_Path_File_Without_Libs = No_Path then
1673 Object_Path_Table.Init (Object_Paths);
1674 Process_Object_Dirs := True;
1675 Create_New_Path_File
1676 (In_Tree, Object_FD, Project.Objects_Path_File_Without_Libs);
1680 -- If there is something to do, set Seen to False for all projects,
1681 -- then call the recursive procedure Add for Project.
1683 if Process_Source_Dirs or Process_Object_Dirs then
1684 For_All_Projects (Project, In_Tree, Dummy);
1687 -- Write and close any file that has been created. Source_FD is not set
1688 -- when this subprogram is called a second time or more, since we reuse
1689 -- the previous version of the file.
1691 if Source_FD /= Invalid_FD then
1694 for Index in Source_Path_Table.First ..
1695 Source_Path_Table.Last (Source_Paths)
1697 Get_Name_String (Source_Paths.Table (Index));
1698 Name_Len := Name_Len + 1;
1699 Name_Buffer (Name_Len) := ASCII.LF;
1700 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
1703 Last := Write (Source_FD, Buffer (1)'Address, Buffer_Last);
1705 if Last = Buffer_Last then
1706 Close (Source_FD, Status);
1713 Prj.Com.Fail ("could not write temporary file");
1717 if Object_FD /= Invalid_FD then
1720 for Index in Object_Path_Table.First ..
1721 Object_Path_Table.Last (Object_Paths)
1723 Get_Name_String (Object_Paths.Table (Index));
1724 Name_Len := Name_Len + 1;
1725 Name_Buffer (Name_Len) := ASCII.LF;
1726 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
1729 Last := Write (Object_FD, Buffer (1)'Address, Buffer_Last);
1731 if Last = Buffer_Last then
1732 Close (Object_FD, Status);
1738 Prj.Com.Fail ("could not write temporary file");
1742 -- Set the env vars, if they need to be changed, and set the
1743 -- corresponding flags.
1745 if Include_Path and then
1746 In_Tree.Private_Part.Current_Source_Path_File /=
1747 Project.Include_Path_File
1749 In_Tree.Private_Part.Current_Source_Path_File :=
1750 Project.Include_Path_File;
1752 (Project_Include_Path_File,
1753 Get_Name_String (In_Tree.Private_Part.Current_Source_Path_File));
1756 if Objects_Path then
1757 if Including_Libraries then
1758 if In_Tree.Private_Part.Current_Object_Path_File /=
1759 Project.Objects_Path_File_With_Libs
1761 In_Tree.Private_Part.Current_Object_Path_File :=
1762 Project.Objects_Path_File_With_Libs;
1764 (Project_Objects_Path_File,
1766 (In_Tree.Private_Part.Current_Object_Path_File));
1770 if In_Tree.Private_Part.Current_Object_Path_File /=
1771 Project.Objects_Path_File_Without_Libs
1773 In_Tree.Private_Part.Current_Object_Path_File :=
1774 Project.Objects_Path_File_Without_Libs;
1776 (Project_Objects_Path_File,
1778 (In_Tree.Private_Part.Current_Object_Path_File));
1786 -----------------------
1787 -- Set_Path_File_Var --
1788 -----------------------
1790 procedure Set_Path_File_Var (Name : String; Value : String) is
1791 Host_Spec : String_Access := To_Host_File_Spec (Value);
1793 if Host_Spec = null then
1795 ("could not convert file name """ & Value & """ to host spec");
1797 Setenv (Name, Host_Spec.all);
1800 end Set_Path_File_Var;
1802 ---------------------------
1803 -- Ultimate_Extension_Of --
1804 ---------------------------
1806 function Ultimate_Extension_Of
1807 (Project : Project_Id) return Project_Id
1809 Result : Project_Id;
1813 while Result.Extended_By /= No_Project loop
1814 Result := Result.Extended_By;
1818 end Ultimate_Extension_Of;
1820 ---------------------
1821 -- Add_Directories --
1822 ---------------------
1824 procedure Add_Directories
1825 (Self : in out Project_Search_Path;
1828 Tmp : String_Access;
1830 if Self.Path = null then
1831 Self.Path := new String'(Uninitialized_Prefix & Path);
1834 Self.Path := new String'(Tmp.all & Path_Separator & Path);
1837 end Add_Directories;
1839 --------------------
1840 -- Is_Initialized --
1841 --------------------
1843 function Is_Initialized (Self : Project_Search_Path) return Boolean is
1845 return Self.Path /= null
1846 and then (Self.Path'Length = 0
1847 or else Self.Path (Self.Path'First) /= '#');
1850 ----------------------
1851 -- Initialize_Empty --
1852 ----------------------
1854 procedure Initialize_Empty (Self : in out Project_Search_Path) is
1857 Self.Path := new String'("");
1858 end Initialize_Empty;
1860 -------------------------------------
1861 -- Initialize_Default_Project_Path --
1862 -------------------------------------
1864 procedure Initialize_Default_Project_Path
1865 (Self : in out Project_Search_Path;
1866 Target_Name : String)
1868 Add_Default_Dir : Boolean := True;
1872 New_Last : Positive;
1874 Ada_Project_Path : constant String := "ADA_PROJECT_PATH";
1875 Gpr_Project_Path : constant String := "GPR_PROJECT_PATH";
1876 -- Name of alternate env. variable that contain path name(s) of
1877 -- directories where project files may reside. GPR_PROJECT_PATH has
1878 -- precedence over ADA_PROJECT_PATH.
1880 Gpr_Prj_Path : String_Access;
1881 Ada_Prj_Path : String_Access;
1882 -- The path name(s) of directories where project files may reside.
1886 if Is_Initialized (Self) then
1890 -- The current directory is always first in the search path. Since the
1891 -- Project_Path currently starts with '#:' as a sign that it isn't
1892 -- initialized, we simply replace '#' with '.'
1894 if Self.Path = null then
1895 Self.Path := new String'('.' & Path_Separator);
1897 Self.Path (Self.Path'First) := '.';
1900 -- Then the reset of the project path (if any) currently contains the
1901 -- directories added through Add_Search_Project_Directory
1903 -- If environment variables are defined and not empty, add their content
1905 Gpr_Prj_Path := Getenv (Gpr_Project_Path);
1906 Ada_Prj_Path := Getenv (Ada_Project_Path);
1908 if Gpr_Prj_Path.all /= "" then
1909 Add_Directories (Self, Gpr_Prj_Path.all);
1912 Free (Gpr_Prj_Path);
1914 if Ada_Prj_Path.all /= "" then
1915 Add_Directories (Self, Ada_Prj_Path.all);
1918 Free (Ada_Prj_Path);
1920 -- Copy to Name_Buffer, since we will need to manipulate the path
1922 Name_Len := Self.Path'Length;
1923 Name_Buffer (1 .. Name_Len) := Self.Path.all;
1925 -- Scan the directory path to see if "-" is one of the directories.
1926 -- Remove each occurrence of "-" and set Add_Default_Dir to False.
1927 -- Also resolve relative paths and symbolic links.
1931 while First <= Name_Len
1932 and then (Name_Buffer (First) = Path_Separator)
1937 exit when First > Name_Len;
1941 while Last < Name_Len
1942 and then Name_Buffer (Last + 1) /= Path_Separator
1947 -- If the directory is "-", set Add_Default_Dir to False and
1948 -- remove from path.
1950 if Name_Buffer (First .. Last) = No_Project_Default_Dir then
1951 Add_Default_Dir := False;
1953 for J in Last + 1 .. Name_Len loop
1954 Name_Buffer (J - No_Project_Default_Dir'Length - 1) :=
1958 Name_Len := Name_Len - No_Project_Default_Dir'Length - 1;
1960 -- After removing the '-', go back one character to get the next
1961 -- directory correctly.
1965 elsif not Hostparm.OpenVMS
1966 or else not Is_Absolute_Path (Name_Buffer (First .. Last))
1968 -- On VMS, only expand relative path names, as absolute paths
1969 -- may correspond to multi-valued VMS logical names.
1972 New_Dir : constant String :=
1974 (Name_Buffer (First .. Last),
1975 Resolve_Links => Opt.Follow_Links_For_Dirs);
1978 -- If the absolute path was resolved and is different from
1979 -- the original, replace original with the resolved path.
1981 if New_Dir /= Name_Buffer (First .. Last)
1982 and then New_Dir'Length /= 0
1984 New_Len := Name_Len + New_Dir'Length - (Last - First + 1);
1985 New_Last := First + New_Dir'Length - 1;
1986 Name_Buffer (New_Last + 1 .. New_Len) :=
1987 Name_Buffer (Last + 1 .. Name_Len);
1988 Name_Buffer (First .. New_Last) := New_Dir;
1989 Name_Len := New_Len;
2000 -- Set the initial value of Current_Project_Path
2002 if Add_Default_Dir then
2004 Prefix : String_Ptr := Sdefault.Search_Dir_Prefix;
2007 if Prefix = null then
2008 Prefix := new String'(Executable_Prefix_Path);
2010 if Prefix.all /= "" then
2011 if Target_Name /= "" then
2012 Add_Str_To_Name_Buffer
2013 (Path_Separator & Prefix.all &
2014 Target_Name & Directory_Separator &
2015 "lib" & Directory_Separator & "gnat");
2018 Add_Str_To_Name_Buffer
2019 (Path_Separator & Prefix.all &
2020 "share" & Directory_Separator & "gpr");
2021 Add_Str_To_Name_Buffer
2022 (Path_Separator & Prefix.all &
2023 "lib" & Directory_Separator & "gnat");
2028 new String'(Name_Buffer (1 .. Name_Len) & Path_Separator &
2030 ".." & Directory_Separator &
2031 ".." & Directory_Separator &
2032 ".." & Directory_Separator & "gnat");
2039 if Self.Path = null then
2040 Self.Path := new String'(Name_Buffer (1 .. Name_Len));
2042 end Initialize_Default_Project_Path;
2048 procedure Get_Path (Self : Project_Search_Path; Path : out String_Access) is
2050 pragma Assert (Is_Initialized (Self));
2058 procedure Set_Path (Self : in out Project_Search_Path; Path : String) is
2061 Self.Path := new String'(Path);
2062 Projects_Paths.Reset (Self.Cache);
2069 procedure Find_Project
2070 (Self : in out Project_Search_Path;
2071 Project_File_Name : String;
2073 Path : out Namet.Path_Name_Type)
2075 File : constant String := Project_File_Name;
2076 -- Have to do a copy, in case the parameter is Name_Buffer, which we
2079 function Try_Path_Name (Path : String) return String_Access;
2080 pragma Inline (Try_Path_Name);
2081 -- Try the specified Path
2087 function Try_Path_Name (Path : String) return String_Access is
2090 Result : String_Access := null;
2093 if Current_Verbosity = High then
2094 Debug_Output ("Trying " & Path);
2097 if Is_Absolute_Path (Path) then
2098 if Is_Regular_File (Path) then
2099 Result := new String'(Path);
2103 -- Because we don't want to resolve symbolic links, we cannot use
2104 -- Locate_Regular_File. So, we try each possible path
2107 First := Self.Path'First;
2108 while First <= Self.Path'Last loop
2109 while First <= Self.Path'Last
2110 and then Self.Path (First) = Path_Separator
2115 exit when First > Self.Path'Last;
2118 while Last < Self.Path'Last
2119 and then Self.Path (Last + 1) /= Path_Separator
2126 if not Is_Absolute_Path (Self.Path (First .. Last)) then
2127 Add_Str_To_Name_Buffer (Get_Current_Dir); -- ??? System call
2128 Add_Char_To_Name_Buffer (Directory_Separator);
2131 Add_Str_To_Name_Buffer (Self.Path (First .. Last));
2132 Add_Char_To_Name_Buffer (Directory_Separator);
2133 Add_Str_To_Name_Buffer (Path);
2135 if Current_Verbosity = High then
2136 Debug_Output ("Testing file " & Name_Buffer (1 .. Name_Len));
2139 if Is_Regular_File (Name_Buffer (1 .. Name_Len)) then
2140 Result := new String'(Name_Buffer (1 .. Name_Len));
2151 -- Local Declarations
2153 Result : String_Access;
2154 Has_Dot : Boolean := False;
2157 -- Start of processing for Find_Project
2160 pragma Assert (Is_Initialized (Self));
2162 if Current_Verbosity = High then
2163 Debug_Increase_Indent
2164 ("Searching for project """ & File & """ in """
2168 -- Check the project cache
2170 Name_Len := File'Length;
2171 Name_Buffer (1 .. Name_Len) := File;
2173 Path := Projects_Paths.Get (Self.Cache, Key);
2175 if Path /= No_Path then
2176 Debug_Decrease_Indent;
2180 -- Check if File contains an extension (a dot before a
2181 -- directory separator). If it is the case we do not try project file
2182 -- with an added extension as it is not possible to have multiple dots
2183 -- on a project file name.
2185 Check_Dot : for K in reverse File'Range loop
2186 if File (K) = '.' then
2191 exit Check_Dot when File (K) = Directory_Separator
2192 or else File (K) = '/';
2195 if not Is_Absolute_Path (File) then
2197 -- First we try <directory>/<file_name>.<extension>
2200 Result := Try_Path_Name
2201 (Directory & Directory_Separator &
2202 File & Project_File_Extension);
2205 -- Then we try <directory>/<file_name>
2207 if Result = null then
2208 Result := Try_Path_Name (Directory & Directory_Separator & File);
2212 -- Then we try <file_name>.<extension>
2214 if Result = null and then not Has_Dot then
2215 Result := Try_Path_Name (File & Project_File_Extension);
2218 -- Then we try <file_name>
2220 if Result = null then
2221 Result := Try_Path_Name (File);
2224 -- If we cannot find the project file, we return an empty string
2226 if Result = null then
2227 Path := Namet.No_Path;
2232 Final_Result : constant String :=
2233 GNAT.OS_Lib.Normalize_Pathname
2235 Directory => Directory,
2236 Resolve_Links => Opt.Follow_Links_For_Files,
2237 Case_Sensitive => True);
2240 Name_Len := Final_Result'Length;
2241 Name_Buffer (1 .. Name_Len) := Final_Result;
2243 Projects_Paths.Set (Self.Cache, Key, Path);
2247 Debug_Decrease_Indent;
2254 procedure Free (Self : in out Project_Search_Path) is
2257 Projects_Paths.Reset (Self.Cache);
2264 procedure Copy (From : Project_Search_Path; To : out Project_Search_Path) is
2268 if From.Path /= null then
2269 To.Path := new String'(From.Path.all);
2272 -- No need to copy the Cache, it will be recomputed as needed