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);
211 Path : constant Path_Name_Type :=
214 Including_Libraries => Including_Libraries,
215 Only_If_Ada => False);
217 if Path /= No_Path then
218 Add_To_Path (Get_Name_String (Path), Buffer, Buffer_Last);
222 procedure For_All_Projects is
223 new For_Every_Project_Imported (Boolean, Add);
225 Dummy : Boolean := False;
227 -- Start of processing for Ada_Objects_Path
230 -- If it is the first time we call this function for
231 -- this project, compute the objects path
233 if Project.Ada_Objects_Path = null then
234 Buffer := new String (1 .. 4096);
235 For_All_Projects (Project, In_Tree, Dummy);
237 Project.Ada_Objects_Path := new String'(Buffer (1 .. Buffer_Last));
241 return Project.Ada_Objects_Path;
242 end Ada_Objects_Path;
248 procedure Add_To_Buffer
250 Buffer : in out String_Access;
251 Buffer_Last : in out Natural)
253 Last : constant Natural := Buffer_Last + S'Length;
256 while Last > Buffer'Last loop
258 New_Buffer : constant String_Access :=
259 new String (1 .. 2 * Buffer'Last);
261 New_Buffer (1 .. Buffer_Last) := Buffer (1 .. Buffer_Last);
263 Buffer := New_Buffer;
267 Buffer (Buffer_Last + 1 .. Last) := S;
271 ------------------------
272 -- Add_To_Object_Path --
273 ------------------------
275 procedure Add_To_Object_Path
276 (Object_Dir : Path_Name_Type;
277 Object_Paths : in out Object_Path_Table.Instance)
280 -- Check if the directory is already in the table
282 for Index in Object_Path_Table.First ..
283 Object_Path_Table.Last (Object_Paths)
286 -- If it is, remove it, and add it as the last one
288 if Object_Paths.Table (Index) = Object_Dir then
289 for Index2 in Index + 1 ..
290 Object_Path_Table.Last (Object_Paths)
292 Object_Paths.Table (Index2 - 1) := Object_Paths.Table (Index2);
296 (Object_Path_Table.Last (Object_Paths)) := Object_Dir;
301 -- The directory is not already in the table, add it
303 Object_Path_Table.Append (Object_Paths, Object_Dir);
304 end Add_To_Object_Path;
310 procedure Add_To_Path
311 (Source_Dirs : String_List_Id;
312 Shared : Shared_Project_Tree_Data_Access;
313 Buffer : in out String_Access;
314 Buffer_Last : in out Natural)
316 Current : String_List_Id := Source_Dirs;
317 Source_Dir : String_Element;
319 while Current /= Nil_String loop
320 Source_Dir := Shared.String_Elements.Table (Current);
321 Add_To_Path (Get_Name_String (Source_Dir.Display_Value),
322 Buffer, Buffer_Last);
323 Current := Source_Dir.Next;
327 procedure Add_To_Path
329 Buffer : in out String_Access;
330 Buffer_Last : in out Natural)
333 New_Buffer : String_Access;
336 function Is_Present (Path : String; Dir : String) return Boolean;
337 -- Return True if Dir is part of Path
343 function Is_Present (Path : String; Dir : String) return Boolean is
344 Last : constant Integer := Path'Last - Dir'Length + 1;
347 for J in Path'First .. Last loop
349 -- Note: the order of the conditions below is important, since
350 -- it ensures a minimal number of string comparisons.
353 or else Path (J - 1) = Path_Separator)
355 (J + Dir'Length > Path'Last
356 or else Path (J + Dir'Length) = Path_Separator)
357 and then Dir = Path (J .. J + Dir'Length - 1)
366 -- Start of processing for Add_To_Path
369 if Is_Present (Buffer (1 .. Buffer_Last), Dir) then
371 -- Dir is already in the path, nothing to do
376 Min_Len := Buffer_Last + Dir'Length;
378 if Buffer_Last > 0 then
380 -- Add 1 for the Path_Separator character
382 Min_Len := Min_Len + 1;
385 -- If Ada_Path_Buffer is too small, increase it
389 if Len < Min_Len then
392 exit when Len >= Min_Len;
395 New_Buffer := new String (1 .. Len);
396 New_Buffer (1 .. Buffer_Last) := Buffer (1 .. Buffer_Last);
398 Buffer := New_Buffer;
401 if Buffer_Last > 0 then
402 Buffer_Last := Buffer_Last + 1;
403 Buffer (Buffer_Last) := Path_Separator;
406 Buffer (Buffer_Last + 1 .. Buffer_Last + Dir'Length) := Dir;
407 Buffer_Last := Buffer_Last + Dir'Length;
410 ------------------------
411 -- Add_To_Source_Path --
412 ------------------------
414 procedure Add_To_Source_Path
415 (Source_Dirs : String_List_Id;
416 Shared : Shared_Project_Tree_Data_Access;
417 Source_Paths : in out Source_Path_Table.Instance)
419 Current : String_List_Id := Source_Dirs;
420 Source_Dir : String_Element;
424 -- Add each source directory
426 while Current /= Nil_String loop
427 Source_Dir := Shared.String_Elements.Table (Current);
430 -- Check if the source directory is already in the table
432 for Index in Source_Path_Table.First ..
433 Source_Path_Table.Last (Source_Paths)
435 -- If it is already, no need to add it
437 if Source_Paths.Table (Index) = Source_Dir.Value then
444 Source_Path_Table.Append (Source_Paths, Source_Dir.Display_Value);
447 -- Next source directory
449 Current := Source_Dir.Next;
451 end Add_To_Source_Path;
453 --------------------------------
454 -- Create_Config_Pragmas_File --
455 --------------------------------
457 procedure Create_Config_Pragmas_File
458 (For_Project : Project_Id;
459 In_Tree : Project_Tree_Ref)
461 type Naming_Id is new Nat;
462 package Naming_Table is new GNAT.Dynamic_Tables
463 (Table_Component_Type => Lang_Naming_Data,
464 Table_Index_Type => Naming_Id,
465 Table_Low_Bound => 1,
467 Table_Increment => 100);
468 Default_Naming : constant Naming_Id := Naming_Table.First;
469 Namings : Naming_Table.Instance;
470 -- Table storing the naming data for gnatmake/gprmake
472 Buffer : String_Access := new String (1 .. Buffer_Initial);
473 Buffer_Last : Natural := 0;
475 File_Name : Path_Name_Type := No_Path;
476 File : File_Descriptor := Invalid_FD;
478 Current_Naming : Naming_Id;
479 Iter : Source_Iterator;
483 (Project : Project_Id;
484 In_Tree : Project_Tree_Ref;
485 State : in out Integer);
486 -- Recursive procedure that put in the config pragmas file any non
487 -- standard naming schemes, if it is not already in the file, then call
488 -- itself for any imported project.
490 procedure Put (Source : Source_Id);
491 -- Put an SFN pragma in the temporary file
493 procedure Put (S : String);
494 procedure Put_Line (S : String);
495 -- Output procedures, analogous to normal Text_IO procs of same name.
496 -- The text is put in Buffer, then it will be written into a temporary
497 -- file with procedure Write_Temp_File below.
499 procedure Write_Temp_File;
500 -- Create a temporary file and put the content of the buffer in it
507 (Project : Project_Id;
508 In_Tree : Project_Tree_Ref;
509 State : in out Integer)
511 pragma Unreferenced (State, In_Tree);
512 Lang : constant Language_Ptr :=
513 Get_Language_From_Name (Project, "ada");
514 Naming : Lang_Naming_Data;
517 if Current_Verbosity = High then
518 Debug_Output ("Checking project file:", Project.Name);
522 if Current_Verbosity = High then
523 Debug_Output ("Languages does not contain Ada, nothing to do");
529 Naming := Lang.Config.Naming_Data;
531 -- Is the naming scheme of this project one that we know?
533 Current_Naming := Default_Naming;
534 while Current_Naming <= Naming_Table.Last (Namings)
535 and then Namings.Table (Current_Naming).Dot_Replacement =
536 Naming.Dot_Replacement
537 and then Namings.Table (Current_Naming).Casing =
539 and then Namings.Table (Current_Naming).Separate_Suffix =
540 Naming.Separate_Suffix
542 Current_Naming := Current_Naming + 1;
545 -- If we don't know it, add it
547 if Current_Naming > Naming_Table.Last (Namings) then
548 Naming_Table.Increment_Last (Namings);
549 Namings.Table (Naming_Table.Last (Namings)) := Naming;
551 -- Put the SFN pragmas for the naming scheme
556 ("pragma Source_File_Name_Project");
558 (" (Spec_File_Name => ""*" &
559 Get_Name_String (Naming.Spec_Suffix) & """,");
562 Image (Naming.Casing) & ",");
564 (" Dot_Replacement => """ &
565 Get_Name_String (Naming.Dot_Replacement) & """);");
570 ("pragma Source_File_Name_Project");
572 (" (Body_File_Name => ""*" &
573 Get_Name_String (Naming.Body_Suffix) & """,");
576 Image (Naming.Casing) & ",");
578 (" Dot_Replacement => """ &
579 Get_Name_String (Naming.Dot_Replacement) &
582 -- and maybe separate
584 if Naming.Body_Suffix /= Naming.Separate_Suffix then
585 Put_Line ("pragma Source_File_Name_Project");
587 (" (Subunit_File_Name => ""*" &
588 Get_Name_String (Naming.Separate_Suffix) & """,");
591 Image (Naming.Casing) & ",");
593 (" Dot_Replacement => """ &
594 Get_Name_String (Naming.Dot_Replacement) &
604 procedure Put (Source : Source_Id) is
606 -- Put the pragma SFN for the unit kind (spec or body)
608 Put ("pragma Source_File_Name_Project (");
609 Put (Namet.Get_Name_String (Source.Unit.Name));
611 if Source.Kind = Spec then
612 Put (", Spec_File_Name => """);
614 Put (", Body_File_Name => """);
617 Put (Namet.Get_Name_String (Source.File));
620 if Source.Index /= 0 then
622 Put (Source.Index'Img);
628 procedure Put (S : String) is
630 Add_To_Buffer (S, Buffer, Buffer_Last);
632 if Current_Verbosity = High then
641 procedure Put_Line (S : String) is
643 -- Add an ASCII.LF to the string. As this config file is supposed to
644 -- be used only by the compiler, we don't care about the characters
645 -- for the end of line. In fact we could have put a space, but
646 -- it is more convenient to be able to read gnat.adc during
647 -- development, for which the ASCII.LF is fine.
650 Put (S => (1 => ASCII.LF));
653 ---------------------
654 -- Write_Temp_File --
655 ---------------------
657 procedure Write_Temp_File is
658 Status : Boolean := False;
662 Tempdir.Create_Temp_File (File, File_Name);
664 if File /= Invalid_FD then
665 Last := Write (File, Buffer (1)'Address, Buffer_Last);
667 if Last = Buffer_Last then
668 Close (File, Status);
673 Prj.Com.Fail ("unable to create temporary file");
677 procedure Check_Imported_Projects is
678 new For_Every_Project_Imported (Integer, Check);
680 Dummy : Integer := 0;
682 -- Start of processing for Create_Config_Pragmas_File
685 if not For_Project.Config_Checked then
686 Naming_Table.Init (Namings);
688 -- Check the naming schemes
690 Check_Imported_Projects
691 (For_Project, In_Tree, Dummy, Imported_First => False);
693 -- Visit all the files and process those that need an SFN pragma
695 Iter := For_Each_Source (In_Tree, For_Project);
696 while Element (Iter) /= No_Source loop
697 Source := Element (Iter);
700 and then not Source.Locally_Removed
701 and then Source.Unit /= null
709 -- If there are no non standard naming scheme, issue the GNAT
710 -- standard naming scheme. This will tell the compiler that
711 -- a project file is used and will forbid any pragma SFN.
713 if Buffer_Last = 0 then
715 Put_Line ("pragma Source_File_Name_Project");
716 Put_Line (" (Spec_File_Name => ""*.ads"",");
717 Put_Line (" Dot_Replacement => ""-"",");
718 Put_Line (" Casing => lowercase);");
720 Put_Line ("pragma Source_File_Name_Project");
721 Put_Line (" (Body_File_Name => ""*.adb"",");
722 Put_Line (" Dot_Replacement => ""-"",");
723 Put_Line (" Casing => lowercase);");
726 -- Close the temporary file
730 if Opt.Verbose_Mode then
731 Write_Str ("Created configuration file """);
732 Write_Str (Get_Name_String (File_Name));
736 For_Project.Config_File_Name := File_Name;
737 For_Project.Config_File_Temp := True;
738 For_Project.Config_Checked := True;
742 end Create_Config_Pragmas_File;
748 procedure Create_Mapping (In_Tree : Project_Tree_Ref) is
750 Iter : Source_Iterator;
755 Iter := For_Each_Source (In_Tree);
757 Data := Element (Iter);
758 exit when Data = No_Source;
760 if Data.Unit /= No_Unit_Index then
761 if Data.Locally_Removed then
762 Fmap.Add_Forbidden_File_Name (Data.File);
765 (Unit_Name => Unit_Name_Type (Data.Unit.Name),
766 File_Name => Data.File,
767 Path_Name => File_Name_Type (Data.Path.Display_Name));
775 -------------------------
776 -- Create_Mapping_File --
777 -------------------------
779 procedure Create_Mapping_File
780 (Project : Project_Id;
782 In_Tree : Project_Tree_Ref;
783 Name : out Path_Name_Type)
785 File : File_Descriptor := Invalid_FD;
787 Buffer : String_Access := new String (1 .. Buffer_Initial);
788 Buffer_Last : Natural := 0;
790 procedure Put_Name_Buffer;
791 -- Put the line contained in the Name_Buffer in the global buffer
794 (Project : Project_Id;
795 In_Tree : Project_Tree_Ref;
796 State : in out Integer);
797 -- Generate the mapping file for Project (not recursively)
799 ---------------------
800 -- Put_Name_Buffer --
801 ---------------------
803 procedure Put_Name_Buffer is
805 if Current_Verbosity = High then
806 Debug_Output (Name_Buffer (1 .. Name_Len));
809 Name_Len := Name_Len + 1;
810 Name_Buffer (Name_Len) := ASCII.LF;
811 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
819 (Project : Project_Id;
820 In_Tree : Project_Tree_Ref;
821 State : in out Integer)
823 pragma Unreferenced (State);
825 Suffix : File_Name_Type;
826 Iter : Source_Iterator;
829 Iter := For_Each_Source (In_Tree, Project, Language => Language);
832 Source := Prj.Element (Iter);
833 exit when Source = No_Source;
835 if Source.Replaced_By = No_Source
836 and then Source.Path.Name /= No_Path
838 (Source.Language.Config.Kind = File_Based
839 or else Source.Unit /= No_Unit_Index)
841 if Source.Unit /= No_Unit_Index then
842 Get_Name_String (Source.Unit.Name);
844 if Source.Language.Config.Kind = Unit_Based then
846 -- ??? Mapping_Spec_Suffix could be set in the case of
849 Add_Char_To_Name_Buffer ('%');
851 if Source.Kind = Spec then
852 Add_Char_To_Name_Buffer ('s');
854 Add_Char_To_Name_Buffer ('b');
861 Source.Language.Config.Mapping_Spec_Suffix;
864 Source.Language.Config.Mapping_Body_Suffix;
867 if Suffix /= No_File then
868 Add_Str_To_Name_Buffer
869 (Get_Name_String (Suffix));
876 Get_Name_String (Source.Display_File);
879 if Source.Locally_Removed then
881 Name_Buffer (1) := '/';
883 Get_Name_String (Source.Path.Display_Name);
893 procedure For_Every_Imported_Project is new
894 For_Every_Project_Imported (State => Integer, Action => Process);
896 Dummy : Integer := 0;
898 -- Start of processing for Create_Mapping_File
901 Create_Temp_File (In_Tree, File, Name, "mapping");
903 if Current_Verbosity = High then
904 Debug_Increase_Indent ("Create mapping file ", Name_Id (Name));
907 For_Every_Imported_Project (Project, In_Tree, Dummy);
911 Status : Boolean := False;
914 if File /= Invalid_FD then
915 Last := Write (File, Buffer (1)'Address, Buffer_Last);
917 if Last = Buffer_Last then
918 GNAT.OS_Lib.Close (File, Status);
923 Prj.Com.Fail ("could not write mapping file");
929 Debug_Decrease_Indent ("Done create mapping file");
930 end Create_Mapping_File;
932 ----------------------
933 -- Create_Temp_File --
934 ----------------------
936 procedure Create_Temp_File
937 (In_Tree : Project_Tree_Ref;
938 Path_FD : out File_Descriptor;
939 Path_Name : out Path_Name_Type;
943 Tempdir.Create_Temp_File (Path_FD, Path_Name);
945 if Path_Name /= No_Path then
946 if Current_Verbosity = High then
947 Write_Line ("Create temp file (" & File_Use & ") "
948 & Get_Name_String (Path_Name));
951 Record_Temp_File (In_Tree, Path_Name);
955 ("unable to create temporary " & File_Use & " file");
957 end Create_Temp_File;
959 --------------------------
960 -- Create_New_Path_File --
961 --------------------------
963 procedure Create_New_Path_File
964 (In_Tree : Project_Tree_Ref;
965 Path_FD : out File_Descriptor;
966 Path_Name : out Path_Name_Type)
969 Create_Temp_File (In_Tree, Path_FD, Path_Name, "path file");
970 end Create_New_Path_File;
972 ------------------------------------
973 -- File_Name_Of_Library_Unit_Body --
974 ------------------------------------
976 function File_Name_Of_Library_Unit_Body
978 Project : Project_Id;
979 In_Tree : Project_Tree_Ref;
980 Main_Project_Only : Boolean := True;
981 Full_Path : Boolean := False) return String
983 The_Project : Project_Id := Project;
984 Original_Name : String := Name;
986 Lang : constant Language_Ptr :=
987 Get_Language_From_Name (Project, "ada");
990 The_Original_Name : Name_Id;
991 The_Spec_Name : Name_Id;
992 The_Body_Name : Name_Id;
995 -- ??? Same block in Project_Of
996 Canonical_Case_File_Name (Original_Name);
997 Name_Len := Original_Name'Length;
998 Name_Buffer (1 .. Name_Len) := Original_Name;
999 The_Original_Name := Name_Find;
1001 if Lang /= null then
1003 Naming : constant Lang_Naming_Data := Lang.Config.Naming_Data;
1004 Extended_Spec_Name : String :=
1005 Name & Namet.Get_Name_String
1006 (Naming.Spec_Suffix);
1007 Extended_Body_Name : String :=
1008 Name & Namet.Get_Name_String
1009 (Naming.Body_Suffix);
1012 Canonical_Case_File_Name (Extended_Spec_Name);
1013 Name_Len := Extended_Spec_Name'Length;
1014 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1015 The_Spec_Name := Name_Find;
1017 Canonical_Case_File_Name (Extended_Body_Name);
1018 Name_Len := Extended_Body_Name'Length;
1019 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1020 The_Body_Name := Name_Find;
1024 Name_Len := Name'Length;
1025 Name_Buffer (1 .. Name_Len) := Name;
1026 Canonical_Case_File_Name (Name_Buffer);
1027 The_Spec_Name := Name_Find;
1028 The_Body_Name := The_Spec_Name;
1031 if Current_Verbosity = High then
1032 Write_Str ("Looking for file name of """);
1036 Write_Str (" Extended Spec Name = """);
1037 Write_Str (Get_Name_String (The_Spec_Name));
1040 Write_Str (" Extended Body Name = """);
1041 Write_Str (Get_Name_String (The_Body_Name));
1046 -- For extending project, search in the extended project if the source
1047 -- is not found. For non extending projects, this loop will be run only
1051 -- Loop through units
1053 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1054 while Unit /= null loop
1057 if not Main_Project_Only
1059 (Unit.File_Names (Impl) /= null
1060 and then Unit.File_Names (Impl).Project = The_Project)
1063 Current_Name : File_Name_Type;
1065 -- Case of a body present
1067 if Unit.File_Names (Impl) /= null then
1068 Current_Name := Unit.File_Names (Impl).File;
1070 if Current_Verbosity = High then
1071 Write_Str (" Comparing with """);
1072 Write_Str (Get_Name_String (Current_Name));
1077 -- If it has the name of the original name, return the
1080 if Unit.Name = The_Original_Name
1082 Current_Name = File_Name_Type (The_Original_Name)
1084 if Current_Verbosity = High then
1089 return Get_Name_String
1090 (Unit.File_Names (Impl).Path.Name);
1093 return Get_Name_String (Current_Name);
1096 -- If it has the name of the extended body name,
1097 -- return the extended body name
1099 elsif Current_Name = File_Name_Type (The_Body_Name) then
1100 if Current_Verbosity = High then
1105 return Get_Name_String
1106 (Unit.File_Names (Impl).Path.Name);
1109 return Get_Name_String (The_Body_Name);
1113 if Current_Verbosity = High then
1114 Write_Line (" not good");
1123 if not Main_Project_Only
1125 (Unit.File_Names (Spec) /= null
1126 and then Unit.File_Names (Spec).Project =
1130 Current_Name : File_Name_Type;
1133 -- Case of spec present
1135 if Unit.File_Names (Spec) /= null then
1136 Current_Name := Unit.File_Names (Spec).File;
1137 if Current_Verbosity = High then
1138 Write_Str (" Comparing with """);
1139 Write_Str (Get_Name_String (Current_Name));
1144 -- If name same as original name, return original name
1146 if Unit.Name = The_Original_Name
1148 Current_Name = File_Name_Type (The_Original_Name)
1150 if Current_Verbosity = High then
1155 return Get_Name_String
1156 (Unit.File_Names (Spec).Path.Name);
1158 return Get_Name_String (Current_Name);
1161 -- If it has the same name as the extended spec name,
1162 -- return the extended spec name.
1164 elsif Current_Name = File_Name_Type (The_Spec_Name) then
1165 if Current_Verbosity = High then
1170 return Get_Name_String
1171 (Unit.File_Names (Spec).Path.Name);
1173 return Get_Name_String (The_Spec_Name);
1177 if Current_Verbosity = High then
1178 Write_Line (" not good");
1185 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1188 -- If we are not in an extending project, give up
1190 exit when not Main_Project_Only
1191 or else The_Project.Extends = No_Project;
1193 -- Otherwise, look in the project we are extending
1195 The_Project := The_Project.Extends;
1198 -- We don't know this file name, return an empty string
1201 end File_Name_Of_Library_Unit_Body;
1203 -------------------------
1204 -- For_All_Object_Dirs --
1205 -------------------------
1207 procedure For_All_Object_Dirs
1208 (Project : Project_Id;
1209 Tree : Project_Tree_Ref)
1211 procedure For_Project
1213 Tree : Project_Tree_Ref;
1214 Dummy : in out Integer);
1215 -- Get all object directories of Prj
1221 procedure For_Project
1223 Tree : Project_Tree_Ref;
1224 Dummy : in out Integer)
1226 pragma Unreferenced (Dummy, Tree);
1228 -- ??? Set_Ada_Paths has a different behavior for library project
1229 -- files, should we have the same ?
1231 if Prj.Object_Directory /= No_Path_Information then
1232 Get_Name_String (Prj.Object_Directory.Display_Name);
1233 Action (Name_Buffer (1 .. Name_Len));
1237 procedure Get_Object_Dirs is
1238 new For_Every_Project_Imported (Integer, For_Project);
1239 Dummy : Integer := 1;
1241 -- Start of processing for For_All_Object_Dirs
1244 Get_Object_Dirs (Project, Tree, Dummy);
1245 end For_All_Object_Dirs;
1247 -------------------------
1248 -- For_All_Source_Dirs --
1249 -------------------------
1251 procedure For_All_Source_Dirs
1252 (Project : Project_Id;
1253 In_Tree : Project_Tree_Ref)
1255 procedure For_Project
1257 In_Tree : Project_Tree_Ref;
1258 Dummy : in out Integer);
1259 -- Get all object directories of Prj
1265 procedure For_Project
1267 In_Tree : Project_Tree_Ref;
1268 Dummy : in out Integer)
1270 pragma Unreferenced (Dummy);
1271 Current : String_List_Id := Prj.Source_Dirs;
1272 The_String : String_Element;
1275 -- If there are Ada sources, call action with the name of every
1276 -- source directory.
1278 if Has_Ada_Sources (Project) then
1279 while Current /= Nil_String loop
1280 The_String := In_Tree.Shared.String_Elements.Table (Current);
1281 Action (Get_Name_String (The_String.Display_Value));
1282 Current := The_String.Next;
1287 procedure Get_Source_Dirs is
1288 new For_Every_Project_Imported (Integer, For_Project);
1289 Dummy : Integer := 1;
1291 -- Start of processing for For_All_Source_Dirs
1294 Get_Source_Dirs (Project, In_Tree, Dummy);
1295 end For_All_Source_Dirs;
1301 procedure Get_Reference
1302 (Source_File_Name : String;
1303 In_Tree : Project_Tree_Ref;
1304 Project : out Project_Id;
1305 Path : out Path_Name_Type)
1308 -- Body below could use some comments ???
1310 if Current_Verbosity > Default then
1311 Write_Str ("Getting Reference_Of (""");
1312 Write_Str (Source_File_Name);
1313 Write_Str (""") ... ");
1317 Original_Name : String := Source_File_Name;
1321 Canonical_Case_File_Name (Original_Name);
1322 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1324 while Unit /= null loop
1325 if Unit.File_Names (Spec) /= null
1326 and then Unit.File_Names (Spec).File /= No_File
1328 (Namet.Get_Name_String
1329 (Unit.File_Names (Spec).File) = Original_Name
1330 or else (Unit.File_Names (Spec).Path /=
1333 Namet.Get_Name_String
1334 (Unit.File_Names (Spec).Path.Name) =
1337 Project := Ultimate_Extension_Of
1338 (Project => Unit.File_Names (Spec).Project);
1339 Path := Unit.File_Names (Spec).Path.Display_Name;
1341 if Current_Verbosity > Default then
1342 Write_Str ("Done: Spec.");
1348 elsif Unit.File_Names (Impl) /= null
1349 and then Unit.File_Names (Impl).File /= No_File
1351 (Namet.Get_Name_String
1352 (Unit.File_Names (Impl).File) = Original_Name
1353 or else (Unit.File_Names (Impl).Path /=
1355 and then Namet.Get_Name_String
1356 (Unit.File_Names (Impl).Path.Name) =
1359 Project := Ultimate_Extension_Of
1360 (Project => Unit.File_Names (Impl).Project);
1361 Path := Unit.File_Names (Impl).Path.Display_Name;
1363 if Current_Verbosity > Default then
1364 Write_Str ("Done: Body.");
1371 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1375 Project := No_Project;
1378 if Current_Verbosity > Default then
1379 Write_Str ("Cannot be found.");
1388 procedure Initialize (In_Tree : Project_Tree_Ref) is
1390 In_Tree.Private_Part.Current_Source_Path_File := No_Path;
1391 In_Tree.Private_Part.Current_Object_Path_File := No_Path;
1398 -- Could use some comments in this body ???
1400 procedure Print_Sources (In_Tree : Project_Tree_Ref) is
1404 Write_Line ("List of Sources:");
1406 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1408 while Unit /= No_Unit_Index loop
1410 Write_Line (Namet.Get_Name_String (Unit.Name));
1412 if Unit.File_Names (Spec).File /= No_File then
1413 if Unit.File_Names (Spec).Project = No_Project then
1414 Write_Line (" No project");
1417 Write_Str (" Project: ");
1419 (Unit.File_Names (Spec).Project.Path.Name);
1420 Write_Line (Name_Buffer (1 .. Name_Len));
1423 Write_Str (" spec: ");
1425 (Namet.Get_Name_String
1426 (Unit.File_Names (Spec).File));
1429 if Unit.File_Names (Impl).File /= No_File then
1430 if Unit.File_Names (Impl).Project = No_Project then
1431 Write_Line (" No project");
1434 Write_Str (" Project: ");
1436 (Unit.File_Names (Impl).Project.Path.Name);
1437 Write_Line (Name_Buffer (1 .. Name_Len));
1440 Write_Str (" body: ");
1442 (Namet.Get_Name_String (Unit.File_Names (Impl).File));
1445 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1448 Write_Line ("end of List of Sources.");
1457 Main_Project : Project_Id;
1458 In_Tree : Project_Tree_Ref) return Project_Id
1460 Result : Project_Id := No_Project;
1462 Original_Name : String := Name;
1464 Lang : constant Language_Ptr :=
1465 Get_Language_From_Name (Main_Project, "ada");
1469 Current_Name : File_Name_Type;
1470 The_Original_Name : File_Name_Type;
1471 The_Spec_Name : File_Name_Type;
1472 The_Body_Name : File_Name_Type;
1475 -- ??? Same block in File_Name_Of_Library_Unit_Body
1476 Canonical_Case_File_Name (Original_Name);
1477 Name_Len := Original_Name'Length;
1478 Name_Buffer (1 .. Name_Len) := Original_Name;
1479 The_Original_Name := Name_Find;
1481 if Lang /= null then
1483 Naming : Lang_Naming_Data renames Lang.Config.Naming_Data;
1484 Extended_Spec_Name : String :=
1485 Name & Namet.Get_Name_String
1486 (Naming.Spec_Suffix);
1487 Extended_Body_Name : String :=
1488 Name & Namet.Get_Name_String
1489 (Naming.Body_Suffix);
1492 Canonical_Case_File_Name (Extended_Spec_Name);
1493 Name_Len := Extended_Spec_Name'Length;
1494 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1495 The_Spec_Name := Name_Find;
1497 Canonical_Case_File_Name (Extended_Body_Name);
1498 Name_Len := Extended_Body_Name'Length;
1499 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1500 The_Body_Name := Name_Find;
1504 The_Spec_Name := The_Original_Name;
1505 The_Body_Name := The_Original_Name;
1508 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1509 while Unit /= null loop
1511 -- Case of a body present
1513 if Unit.File_Names (Impl) /= null then
1514 Current_Name := Unit.File_Names (Impl).File;
1516 -- If it has the name of the original name or the body name,
1517 -- we have found the project.
1519 if Unit.Name = Name_Id (The_Original_Name)
1520 or else Current_Name = The_Original_Name
1521 or else Current_Name = The_Body_Name
1523 Result := Unit.File_Names (Impl).Project;
1530 if Unit.File_Names (Spec) /= null then
1531 Current_Name := Unit.File_Names (Spec).File;
1533 -- If name same as the original name, or the spec name, we have
1534 -- found the project.
1536 if Unit.Name = Name_Id (The_Original_Name)
1537 or else Current_Name = The_Original_Name
1538 or else Current_Name = The_Spec_Name
1540 Result := Unit.File_Names (Spec).Project;
1545 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1548 -- Get the ultimate extending project
1550 if Result /= No_Project then
1551 while Result.Extended_By /= No_Project loop
1552 Result := Result.Extended_By;
1563 procedure Set_Ada_Paths
1564 (Project : Project_Id;
1565 In_Tree : Project_Tree_Ref;
1566 Including_Libraries : Boolean;
1567 Include_Path : Boolean := True;
1568 Objects_Path : Boolean := True)
1571 Source_Paths : Source_Path_Table.Instance;
1572 Object_Paths : Object_Path_Table.Instance;
1573 -- List of source or object dirs. Only computed the first time this
1574 -- procedure is called (since Source_FD is then reused)
1576 Source_FD : File_Descriptor := Invalid_FD;
1577 Object_FD : File_Descriptor := Invalid_FD;
1578 -- The temporary files to store the paths. These are only created the
1579 -- first time this procedure is called, and reused from then on.
1581 Process_Source_Dirs : Boolean := False;
1582 Process_Object_Dirs : Boolean := False;
1585 -- For calls to Close
1588 Buffer : String_Access := new String (1 .. Buffer_Initial);
1589 Buffer_Last : Natural := 0;
1591 procedure Recursive_Add
1592 (Project : Project_Id;
1593 In_Tree : Project_Tree_Ref;
1594 Dummy : in out Boolean);
1595 -- Recursive procedure to add the source/object paths of extended/
1596 -- imported projects.
1602 procedure Recursive_Add
1603 (Project : Project_Id;
1604 In_Tree : Project_Tree_Ref;
1605 Dummy : in out Boolean)
1607 pragma Unreferenced (Dummy);
1609 Path : Path_Name_Type;
1612 -- ??? This is almost the equivalent of For_All_Source_Dirs
1614 if Process_Source_Dirs then
1616 -- Add to path all source directories of this project if there are
1619 if Has_Ada_Sources (Project) then
1621 (Project.Source_Dirs, In_Tree.Shared, Source_Paths);
1625 if Process_Object_Dirs then
1626 Path := Get_Object_Directory
1628 Including_Libraries => Including_Libraries,
1629 Only_If_Ada => True);
1631 if Path /= No_Path then
1632 Add_To_Object_Path (Path, Object_Paths);
1637 procedure For_All_Projects is
1638 new For_Every_Project_Imported (Boolean, Recursive_Add);
1640 Dummy : Boolean := False;
1642 -- Start of processing for Set_Ada_Paths
1645 -- If it is the first time we call this procedure for this project,
1646 -- compute the source path and/or the object path.
1648 if Include_Path and then Project.Include_Path_File = No_Path then
1649 Source_Path_Table.Init (Source_Paths);
1650 Process_Source_Dirs := True;
1651 Create_New_Path_File
1652 (In_Tree, Source_FD, Project.Include_Path_File);
1655 -- For the object path, we make a distinction depending on
1656 -- Including_Libraries.
1658 if Objects_Path and Including_Libraries then
1659 if Project.Objects_Path_File_With_Libs = No_Path then
1660 Object_Path_Table.Init (Object_Paths);
1661 Process_Object_Dirs := True;
1662 Create_New_Path_File
1663 (In_Tree, Object_FD, Project.Objects_Path_File_With_Libs);
1666 elsif Objects_Path then
1667 if Project.Objects_Path_File_Without_Libs = No_Path then
1668 Object_Path_Table.Init (Object_Paths);
1669 Process_Object_Dirs := True;
1670 Create_New_Path_File
1671 (In_Tree, Object_FD, Project.Objects_Path_File_Without_Libs);
1675 -- If there is something to do, set Seen to False for all projects,
1676 -- then call the recursive procedure Add for Project.
1678 if Process_Source_Dirs or Process_Object_Dirs then
1679 For_All_Projects (Project, In_Tree, Dummy);
1682 -- Write and close any file that has been created. Source_FD is not set
1683 -- when this subprogram is called a second time or more, since we reuse
1684 -- the previous version of the file.
1686 if Source_FD /= Invalid_FD then
1689 for Index in Source_Path_Table.First ..
1690 Source_Path_Table.Last (Source_Paths)
1692 Get_Name_String (Source_Paths.Table (Index));
1693 Name_Len := Name_Len + 1;
1694 Name_Buffer (Name_Len) := ASCII.LF;
1695 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
1698 Last := Write (Source_FD, Buffer (1)'Address, Buffer_Last);
1700 if Last = Buffer_Last then
1701 Close (Source_FD, Status);
1708 Prj.Com.Fail ("could not write temporary file");
1712 if Object_FD /= Invalid_FD then
1715 for Index in Object_Path_Table.First ..
1716 Object_Path_Table.Last (Object_Paths)
1718 Get_Name_String (Object_Paths.Table (Index));
1719 Name_Len := Name_Len + 1;
1720 Name_Buffer (Name_Len) := ASCII.LF;
1721 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
1724 Last := Write (Object_FD, Buffer (1)'Address, Buffer_Last);
1726 if Last = Buffer_Last then
1727 Close (Object_FD, Status);
1733 Prj.Com.Fail ("could not write temporary file");
1737 -- Set the env vars, if they need to be changed, and set the
1738 -- corresponding flags.
1740 if Include_Path and then
1741 In_Tree.Private_Part.Current_Source_Path_File /=
1742 Project.Include_Path_File
1744 In_Tree.Private_Part.Current_Source_Path_File :=
1745 Project.Include_Path_File;
1747 (Project_Include_Path_File,
1748 Get_Name_String (In_Tree.Private_Part.Current_Source_Path_File));
1751 if Objects_Path then
1752 if Including_Libraries then
1753 if In_Tree.Private_Part.Current_Object_Path_File /=
1754 Project.Objects_Path_File_With_Libs
1756 In_Tree.Private_Part.Current_Object_Path_File :=
1757 Project.Objects_Path_File_With_Libs;
1759 (Project_Objects_Path_File,
1761 (In_Tree.Private_Part.Current_Object_Path_File));
1765 if In_Tree.Private_Part.Current_Object_Path_File /=
1766 Project.Objects_Path_File_Without_Libs
1768 In_Tree.Private_Part.Current_Object_Path_File :=
1769 Project.Objects_Path_File_Without_Libs;
1771 (Project_Objects_Path_File,
1773 (In_Tree.Private_Part.Current_Object_Path_File));
1781 -----------------------
1782 -- Set_Path_File_Var --
1783 -----------------------
1785 procedure Set_Path_File_Var (Name : String; Value : String) is
1786 Host_Spec : String_Access := To_Host_File_Spec (Value);
1788 if Host_Spec = null then
1790 ("could not convert file name """ & Value & """ to host spec");
1792 Setenv (Name, Host_Spec.all);
1795 end Set_Path_File_Var;
1797 ---------------------------
1798 -- Ultimate_Extension_Of --
1799 ---------------------------
1801 function Ultimate_Extension_Of
1802 (Project : Project_Id) return Project_Id
1804 Result : Project_Id;
1808 while Result.Extended_By /= No_Project loop
1809 Result := Result.Extended_By;
1813 end Ultimate_Extension_Of;
1815 ---------------------
1816 -- Add_Directories --
1817 ---------------------
1819 procedure Add_Directories
1820 (Self : in out Project_Search_Path;
1823 Tmp : String_Access;
1825 if Self.Path = null then
1826 Self.Path := new String'(Uninitialized_Prefix & Path);
1829 Self.Path := new String'(Tmp.all & Path_Separator & Path);
1832 end Add_Directories;
1834 --------------------
1835 -- Is_Initialized --
1836 --------------------
1838 function Is_Initialized (Self : Project_Search_Path) return Boolean is
1840 return Self.Path /= null
1841 and then (Self.Path'Length = 0
1842 or else Self.Path (Self.Path'First) /= '#');
1845 ----------------------
1846 -- Initialize_Empty --
1847 ----------------------
1849 procedure Initialize_Empty (Self : in out Project_Search_Path) is
1852 Self.Path := new String'("");
1853 end Initialize_Empty;
1855 -------------------------------------
1856 -- Initialize_Default_Project_Path --
1857 -------------------------------------
1859 procedure Initialize_Default_Project_Path
1860 (Self : in out Project_Search_Path;
1861 Target_Name : String)
1863 Add_Default_Dir : Boolean := True;
1867 New_Last : Positive;
1869 Ada_Project_Path : constant String := "ADA_PROJECT_PATH";
1870 Gpr_Project_Path : constant String := "GPR_PROJECT_PATH";
1871 -- Name of alternate env. variable that contain path name(s) of
1872 -- directories where project files may reside. GPR_PROJECT_PATH has
1873 -- precedence over ADA_PROJECT_PATH.
1875 Gpr_Prj_Path : String_Access;
1876 Ada_Prj_Path : String_Access;
1877 -- The path name(s) of directories where project files may reside.
1881 if Is_Initialized (Self) then
1885 -- The current directory is always first in the search path. Since the
1886 -- Project_Path currently starts with '#:' as a sign that it isn't
1887 -- initialized, we simply replace '#' with '.'
1889 if Self.Path = null then
1890 Self.Path := new String'('.' & Path_Separator);
1892 Self.Path (Self.Path'First) := '.';
1895 -- Then the reset of the project path (if any) currently contains the
1896 -- directories added through Add_Search_Project_Directory
1898 -- If environment variables are defined and not empty, add their content
1900 Gpr_Prj_Path := Getenv (Gpr_Project_Path);
1901 Ada_Prj_Path := Getenv (Ada_Project_Path);
1903 if Gpr_Prj_Path.all /= "" then
1904 Add_Directories (Self, Gpr_Prj_Path.all);
1907 Free (Gpr_Prj_Path);
1909 if Ada_Prj_Path.all /= "" then
1910 Add_Directories (Self, Ada_Prj_Path.all);
1913 Free (Ada_Prj_Path);
1915 -- Copy to Name_Buffer, since we will need to manipulate the path
1917 Name_Len := Self.Path'Length;
1918 Name_Buffer (1 .. Name_Len) := Self.Path.all;
1920 -- Scan the directory path to see if "-" is one of the directories.
1921 -- Remove each occurrence of "-" and set Add_Default_Dir to False.
1922 -- Also resolve relative paths and symbolic links.
1926 while First <= Name_Len
1927 and then (Name_Buffer (First) = Path_Separator)
1932 exit when First > Name_Len;
1936 while Last < Name_Len
1937 and then Name_Buffer (Last + 1) /= Path_Separator
1942 -- If the directory is "-", set Add_Default_Dir to False and
1943 -- remove from path.
1945 if Name_Buffer (First .. Last) = No_Project_Default_Dir then
1946 Add_Default_Dir := False;
1948 for J in Last + 1 .. Name_Len loop
1949 Name_Buffer (J - No_Project_Default_Dir'Length - 1) :=
1953 Name_Len := Name_Len - No_Project_Default_Dir'Length - 1;
1955 -- After removing the '-', go back one character to get the next
1956 -- directory correctly.
1960 elsif not Hostparm.OpenVMS
1961 or else not Is_Absolute_Path (Name_Buffer (First .. Last))
1963 -- On VMS, only expand relative path names, as absolute paths
1964 -- may correspond to multi-valued VMS logical names.
1967 New_Dir : constant String :=
1969 (Name_Buffer (First .. Last),
1970 Resolve_Links => Opt.Follow_Links_For_Dirs);
1973 -- If the absolute path was resolved and is different from
1974 -- the original, replace original with the resolved path.
1976 if New_Dir /= Name_Buffer (First .. Last)
1977 and then New_Dir'Length /= 0
1979 New_Len := Name_Len + New_Dir'Length - (Last - First + 1);
1980 New_Last := First + New_Dir'Length - 1;
1981 Name_Buffer (New_Last + 1 .. New_Len) :=
1982 Name_Buffer (Last + 1 .. Name_Len);
1983 Name_Buffer (First .. New_Last) := New_Dir;
1984 Name_Len := New_Len;
1995 -- Set the initial value of Current_Project_Path
1997 if Add_Default_Dir then
1999 Prefix : String_Ptr := Sdefault.Search_Dir_Prefix;
2002 if Prefix = null then
2003 Prefix := new String'(Executable_Prefix_Path);
2005 if Prefix.all /= "" then
2006 if Target_Name /= "" then
2007 Add_Str_To_Name_Buffer
2008 (Path_Separator & Prefix.all &
2009 Target_Name & Directory_Separator &
2010 "lib" & Directory_Separator & "gnat");
2013 Add_Str_To_Name_Buffer
2014 (Path_Separator & Prefix.all &
2015 "share" & Directory_Separator & "gpr");
2016 Add_Str_To_Name_Buffer
2017 (Path_Separator & Prefix.all &
2018 "lib" & Directory_Separator & "gnat");
2023 new String'(Name_Buffer (1 .. Name_Len) & Path_Separator &
2025 ".." & Directory_Separator &
2026 ".." & Directory_Separator &
2027 ".." & Directory_Separator & "gnat");
2034 if Self.Path = null then
2035 Self.Path := new String'(Name_Buffer (1 .. Name_Len));
2037 end Initialize_Default_Project_Path;
2043 procedure Get_Path (Self : Project_Search_Path; Path : out String_Access) is
2045 pragma Assert (Is_Initialized (Self));
2053 procedure Set_Path (Self : in out Project_Search_Path; Path : String) is
2056 Self.Path := new String'(Path);
2057 Projects_Paths.Reset (Self.Cache);
2064 procedure Find_Project
2065 (Self : in out Project_Search_Path;
2066 Project_File_Name : String;
2068 Path : out Namet.Path_Name_Type)
2070 File : constant String := Project_File_Name;
2071 -- Have to do a copy, in case the parameter is Name_Buffer, which we
2074 function Try_Path_Name (Path : String) return String_Access;
2075 pragma Inline (Try_Path_Name);
2076 -- Try the specified Path
2082 function Try_Path_Name (Path : String) return String_Access is
2085 Result : String_Access := null;
2088 if Current_Verbosity = High then
2089 Debug_Output ("Trying " & Path);
2092 if Is_Absolute_Path (Path) then
2093 if Is_Regular_File (Path) then
2094 Result := new String'(Path);
2098 -- Because we don't want to resolve symbolic links, we cannot use
2099 -- Locate_Regular_File. So, we try each possible path
2102 First := Self.Path'First;
2103 while First <= Self.Path'Last loop
2104 while First <= Self.Path'Last
2105 and then Self.Path (First) = Path_Separator
2110 exit when First > Self.Path'Last;
2113 while Last < Self.Path'Last
2114 and then Self.Path (Last + 1) /= Path_Separator
2121 if not Is_Absolute_Path (Self.Path (First .. Last)) then
2122 Add_Str_To_Name_Buffer (Get_Current_Dir); -- ??? System call
2123 Add_Char_To_Name_Buffer (Directory_Separator);
2126 Add_Str_To_Name_Buffer (Self.Path (First .. Last));
2127 Add_Char_To_Name_Buffer (Directory_Separator);
2128 Add_Str_To_Name_Buffer (Path);
2130 if Current_Verbosity = High then
2131 Debug_Output ("Testing file " & Name_Buffer (1 .. Name_Len));
2134 if Is_Regular_File (Name_Buffer (1 .. Name_Len)) then
2135 Result := new String'(Name_Buffer (1 .. Name_Len));
2146 -- Local Declarations
2148 Result : String_Access;
2149 Has_Dot : Boolean := False;
2152 -- Start of processing for Find_Project
2155 pragma Assert (Is_Initialized (Self));
2157 if Current_Verbosity = High then
2158 Debug_Increase_Indent
2159 ("Searching for project """ & File & """ in """
2163 -- Check the project cache
2165 Name_Len := File'Length;
2166 Name_Buffer (1 .. Name_Len) := File;
2168 Path := Projects_Paths.Get (Self.Cache, Key);
2170 if Path /= No_Path then
2171 Debug_Decrease_Indent;
2175 -- Check if File contains an extension (a dot before a
2176 -- directory separator). If it is the case we do not try project file
2177 -- with an added extension as it is not possible to have multiple dots
2178 -- on a project file name.
2180 Check_Dot : for K in reverse File'Range loop
2181 if File (K) = '.' then
2186 exit Check_Dot when File (K) = Directory_Separator
2187 or else File (K) = '/';
2190 if not Is_Absolute_Path (File) then
2192 -- First we try <directory>/<file_name>.<extension>
2195 Result := Try_Path_Name
2196 (Directory & Directory_Separator &
2197 File & Project_File_Extension);
2200 -- Then we try <directory>/<file_name>
2202 if Result = null then
2203 Result := Try_Path_Name (Directory & Directory_Separator & File);
2207 -- Then we try <file_name>.<extension>
2209 if Result = null and then not Has_Dot then
2210 Result := Try_Path_Name (File & Project_File_Extension);
2213 -- Then we try <file_name>
2215 if Result = null then
2216 Result := Try_Path_Name (File);
2219 -- If we cannot find the project file, we return an empty string
2221 if Result = null then
2222 Path := Namet.No_Path;
2227 Final_Result : constant String :=
2228 GNAT.OS_Lib.Normalize_Pathname
2230 Directory => Directory,
2231 Resolve_Links => Opt.Follow_Links_For_Files,
2232 Case_Sensitive => True);
2235 Name_Len := Final_Result'Length;
2236 Name_Buffer (1 .. Name_Len) := Final_Result;
2238 Projects_Paths.Set (Self.Cache, Key, Path);
2242 Debug_Decrease_Indent;
2249 procedure Free (Self : in out Project_Search_Path) is
2252 Projects_Paths.Reset (Self.Cache);
2259 procedure Copy (From : Project_Search_Path; To : out Project_Search_Path) is
2263 if From.Path /= null then
2264 To.Path := new String'(From.Path.all);
2267 -- No need to copy the Cache, it will be recomputed as needed