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 ----------------------
109 -- Ada_Include_Path --
110 ----------------------
112 function Ada_Include_Path
113 (Project : Project_Id;
114 In_Tree : Project_Tree_Ref;
115 Recursive : Boolean := False) return String
117 Buffer : String_Access;
118 Buffer_Last : Natural := 0;
121 (Project : Project_Id;
122 In_Tree : Project_Tree_Ref;
123 Dummy : in out Boolean);
124 -- Add source dirs of Project to the path
131 (Project : Project_Id;
132 In_Tree : Project_Tree_Ref;
133 Dummy : in out Boolean)
135 pragma Unreferenced (Dummy);
138 (Project.Source_Dirs, In_Tree.Shared, Buffer, Buffer_Last);
141 procedure For_All_Projects is
142 new For_Every_Project_Imported (Boolean, Add);
144 Dummy : Boolean := False;
146 -- Start of processing for Ada_Include_Path
151 -- If it is the first time we call this function for
152 -- this project, compute the source path
154 if Project.Ada_Include_Path = null then
155 Buffer := new String (1 .. 4096);
157 (Project, In_Tree, Dummy, Include_Aggregated => True);
158 Project.Ada_Include_Path := new String'(Buffer (1 .. Buffer_Last));
162 return Project.Ada_Include_Path.all;
165 Buffer := new String (1 .. 4096);
167 (Project.Source_Dirs, In_Tree.Shared, Buffer, Buffer_Last);
170 Result : constant String := Buffer (1 .. Buffer_Last);
176 end Ada_Include_Path;
178 ----------------------
179 -- Ada_Objects_Path --
180 ----------------------
182 function Ada_Objects_Path
183 (Project : Project_Id;
184 In_Tree : Project_Tree_Ref;
185 Including_Libraries : Boolean := True) return String_Access
187 Buffer : String_Access;
188 Buffer_Last : Natural := 0;
191 (Project : Project_Id;
192 In_Tree : Project_Tree_Ref;
193 Dummy : in out Boolean);
194 -- Add all the object directories of a project to the path
201 (Project : Project_Id;
202 In_Tree : Project_Tree_Ref;
203 Dummy : in out Boolean)
205 pragma Unreferenced (Dummy, In_Tree);
207 Path : constant Path_Name_Type :=
210 Including_Libraries => Including_Libraries,
211 Only_If_Ada => False);
213 if Path /= No_Path then
214 Add_To_Path (Get_Name_String (Path), Buffer, Buffer_Last);
218 procedure For_All_Projects is
219 new For_Every_Project_Imported (Boolean, Add);
221 Dummy : Boolean := False;
223 -- Start of processing for Ada_Objects_Path
226 -- If it is the first time we call this function for
227 -- this project, compute the objects path
229 if Project.Ada_Objects_Path = null then
230 Buffer := new String (1 .. 4096);
231 For_All_Projects (Project, In_Tree, Dummy);
233 Project.Ada_Objects_Path := new String'(Buffer (1 .. Buffer_Last));
237 return Project.Ada_Objects_Path;
238 end Ada_Objects_Path;
244 procedure Add_To_Buffer
246 Buffer : in out String_Access;
247 Buffer_Last : in out Natural)
249 Last : constant Natural := Buffer_Last + S'Length;
252 while Last > Buffer'Last loop
254 New_Buffer : constant String_Access :=
255 new String (1 .. 2 * Buffer'Last);
257 New_Buffer (1 .. Buffer_Last) := Buffer (1 .. Buffer_Last);
259 Buffer := New_Buffer;
263 Buffer (Buffer_Last + 1 .. Last) := S;
267 ------------------------
268 -- Add_To_Object_Path --
269 ------------------------
271 procedure Add_To_Object_Path
272 (Object_Dir : Path_Name_Type;
273 Object_Paths : in out Object_Path_Table.Instance)
276 -- Check if the directory is already in the table
278 for Index in Object_Path_Table.First ..
279 Object_Path_Table.Last (Object_Paths)
282 -- If it is, remove it, and add it as the last one
284 if Object_Paths.Table (Index) = Object_Dir then
285 for Index2 in Index + 1 ..
286 Object_Path_Table.Last (Object_Paths)
288 Object_Paths.Table (Index2 - 1) := Object_Paths.Table (Index2);
292 (Object_Path_Table.Last (Object_Paths)) := Object_Dir;
297 -- The directory is not already in the table, add it
299 Object_Path_Table.Append (Object_Paths, Object_Dir);
300 end Add_To_Object_Path;
306 procedure Add_To_Path
307 (Source_Dirs : String_List_Id;
308 Shared : Shared_Project_Tree_Data_Access;
309 Buffer : in out String_Access;
310 Buffer_Last : in out Natural)
312 Current : String_List_Id := Source_Dirs;
313 Source_Dir : String_Element;
315 while Current /= Nil_String loop
316 Source_Dir := Shared.String_Elements.Table (Current);
317 Add_To_Path (Get_Name_String (Source_Dir.Display_Value),
318 Buffer, Buffer_Last);
319 Current := Source_Dir.Next;
323 procedure Add_To_Path
325 Buffer : in out String_Access;
326 Buffer_Last : in out Natural)
329 New_Buffer : String_Access;
332 function Is_Present (Path : String; Dir : String) return Boolean;
333 -- Return True if Dir is part of Path
339 function Is_Present (Path : String; Dir : String) return Boolean is
340 Last : constant Integer := Path'Last - Dir'Length + 1;
343 for J in Path'First .. Last loop
345 -- Note: the order of the conditions below is important, since
346 -- it ensures a minimal number of string comparisons.
349 or else Path (J - 1) = Path_Separator)
351 (J + Dir'Length > Path'Last
352 or else Path (J + Dir'Length) = Path_Separator)
353 and then Dir = Path (J .. J + Dir'Length - 1)
362 -- Start of processing for Add_To_Path
365 if Is_Present (Buffer (1 .. Buffer_Last), Dir) then
367 -- Dir is already in the path, nothing to do
372 Min_Len := Buffer_Last + Dir'Length;
374 if Buffer_Last > 0 then
376 -- Add 1 for the Path_Separator character
378 Min_Len := Min_Len + 1;
381 -- If Ada_Path_Buffer is too small, increase it
385 if Len < Min_Len then
388 exit when Len >= Min_Len;
391 New_Buffer := new String (1 .. Len);
392 New_Buffer (1 .. Buffer_Last) := Buffer (1 .. Buffer_Last);
394 Buffer := New_Buffer;
397 if Buffer_Last > 0 then
398 Buffer_Last := Buffer_Last + 1;
399 Buffer (Buffer_Last) := Path_Separator;
402 Buffer (Buffer_Last + 1 .. Buffer_Last + Dir'Length) := Dir;
403 Buffer_Last := Buffer_Last + Dir'Length;
406 ------------------------
407 -- Add_To_Source_Path --
408 ------------------------
410 procedure Add_To_Source_Path
411 (Source_Dirs : String_List_Id;
412 Shared : Shared_Project_Tree_Data_Access;
413 Source_Paths : in out Source_Path_Table.Instance)
415 Current : String_List_Id := Source_Dirs;
416 Source_Dir : String_Element;
420 -- Add each source directory
422 while Current /= Nil_String loop
423 Source_Dir := Shared.String_Elements.Table (Current);
426 -- Check if the source directory is already in the table
428 for Index in Source_Path_Table.First ..
429 Source_Path_Table.Last (Source_Paths)
431 -- If it is already, no need to add it
433 if Source_Paths.Table (Index) = Source_Dir.Value then
440 Source_Path_Table.Append (Source_Paths, Source_Dir.Display_Value);
443 -- Next source directory
445 Current := Source_Dir.Next;
447 end Add_To_Source_Path;
449 --------------------------------
450 -- Create_Config_Pragmas_File --
451 --------------------------------
453 procedure Create_Config_Pragmas_File
454 (For_Project : Project_Id;
455 In_Tree : Project_Tree_Ref)
457 type Naming_Id is new Nat;
458 package Naming_Table is new GNAT.Dynamic_Tables
459 (Table_Component_Type => Lang_Naming_Data,
460 Table_Index_Type => Naming_Id,
461 Table_Low_Bound => 1,
463 Table_Increment => 100);
464 Default_Naming : constant Naming_Id := Naming_Table.First;
465 Namings : Naming_Table.Instance;
466 -- Table storing the naming data for gnatmake/gprmake
468 Buffer : String_Access := new String (1 .. Buffer_Initial);
469 Buffer_Last : Natural := 0;
471 File_Name : Path_Name_Type := No_Path;
472 File : File_Descriptor := Invalid_FD;
474 Current_Naming : Naming_Id;
477 (Project : Project_Id;
478 In_Tree : Project_Tree_Ref;
479 State : in out Integer);
480 -- Recursive procedure that put in the config pragmas file any non
481 -- standard naming schemes, if it is not already in the file, then call
482 -- itself for any imported project.
484 procedure Put (Source : Source_Id);
485 -- Put an SFN pragma in the temporary file
487 procedure Put (S : String);
488 procedure Put_Line (S : String);
489 -- Output procedures, analogous to normal Text_IO procs of same name.
490 -- The text is put in Buffer, then it will be written into a temporary
491 -- file with procedure Write_Temp_File below.
493 procedure Write_Temp_File;
494 -- Create a temporary file and put the content of the buffer in it
501 (Project : Project_Id;
502 In_Tree : Project_Tree_Ref;
503 State : in out Integer)
505 pragma Unreferenced (State);
507 Lang : constant Language_Ptr :=
508 Get_Language_From_Name (Project, "ada");
509 Naming : Lang_Naming_Data;
510 Iter : Source_Iterator;
514 if Current_Verbosity = High then
515 Debug_Output ("Checking project file:", Project.Name);
519 if Current_Verbosity = High then
520 Debug_Output ("Languages does not contain Ada, nothing to do");
526 -- Visit all the files and process those that need an SFN pragma
528 Iter := For_Each_Source (In_Tree, Project);
529 while Element (Iter) /= No_Source loop
530 Source := Element (Iter);
533 and then not Source.Locally_Removed
534 and then Source.Unit /= null
542 Naming := Lang.Config.Naming_Data;
544 -- Is the naming scheme of this project one that we know?
546 Current_Naming := Default_Naming;
547 while Current_Naming <= Naming_Table.Last (Namings)
548 and then Namings.Table (Current_Naming).Dot_Replacement =
549 Naming.Dot_Replacement
550 and then Namings.Table (Current_Naming).Casing =
552 and then Namings.Table (Current_Naming).Separate_Suffix =
553 Naming.Separate_Suffix
555 Current_Naming := Current_Naming + 1;
558 -- If we don't know it, add it
560 if Current_Naming > Naming_Table.Last (Namings) then
561 Naming_Table.Increment_Last (Namings);
562 Namings.Table (Naming_Table.Last (Namings)) := Naming;
564 -- Put the SFN pragmas for the naming scheme
569 ("pragma Source_File_Name_Project");
571 (" (Spec_File_Name => ""*" &
572 Get_Name_String (Naming.Spec_Suffix) & """,");
575 Image (Naming.Casing) & ",");
577 (" Dot_Replacement => """ &
578 Get_Name_String (Naming.Dot_Replacement) & """);");
583 ("pragma Source_File_Name_Project");
585 (" (Body_File_Name => ""*" &
586 Get_Name_String (Naming.Body_Suffix) & """,");
589 Image (Naming.Casing) & ",");
591 (" Dot_Replacement => """ &
592 Get_Name_String (Naming.Dot_Replacement) &
595 -- and maybe separate
597 if Naming.Body_Suffix /= Naming.Separate_Suffix then
598 Put_Line ("pragma Source_File_Name_Project");
600 (" (Subunit_File_Name => ""*" &
601 Get_Name_String (Naming.Separate_Suffix) & """,");
604 Image (Naming.Casing) & ",");
606 (" Dot_Replacement => """ &
607 Get_Name_String (Naming.Dot_Replacement) &
617 procedure Put (Source : Source_Id) is
619 -- Put the pragma SFN for the unit kind (spec or body)
621 Put ("pragma Source_File_Name_Project (");
622 Put (Namet.Get_Name_String (Source.Unit.Name));
624 if Source.Kind = Spec then
625 Put (", Spec_File_Name => """);
627 Put (", Body_File_Name => """);
630 Put (Namet.Get_Name_String (Source.File));
633 if Source.Index /= 0 then
635 Put (Source.Index'Img);
641 procedure Put (S : String) is
643 Add_To_Buffer (S, Buffer, Buffer_Last);
645 if Current_Verbosity = High then
654 procedure Put_Line (S : String) is
656 -- Add an ASCII.LF to the string. As this config file is supposed to
657 -- be used only by the compiler, we don't care about the characters
658 -- for the end of line. In fact we could have put a space, but
659 -- it is more convenient to be able to read gnat.adc during
660 -- development, for which the ASCII.LF is fine.
663 Put (S => (1 => ASCII.LF));
666 ---------------------
667 -- Write_Temp_File --
668 ---------------------
670 procedure Write_Temp_File is
671 Status : Boolean := False;
675 Tempdir.Create_Temp_File (File, File_Name);
677 if File /= Invalid_FD then
678 Last := Write (File, Buffer (1)'Address, Buffer_Last);
680 if Last = Buffer_Last then
681 Close (File, Status);
686 Prj.Com.Fail ("unable to create temporary file");
690 procedure Check_Imported_Projects is
691 new For_Every_Project_Imported (Integer, Check);
693 Dummy : Integer := 0;
695 -- Start of processing for Create_Config_Pragmas_File
698 if not For_Project.Config_Checked then
699 Naming_Table.Init (Namings);
701 -- Check the naming schemes
703 Check_Imported_Projects
704 (For_Project, In_Tree, Dummy, Imported_First => False);
706 -- If there are no non standard naming scheme, issue the GNAT
707 -- standard naming scheme. This will tell the compiler that
708 -- a project file is used and will forbid any pragma SFN.
710 if Buffer_Last = 0 then
712 Put_Line ("pragma Source_File_Name_Project");
713 Put_Line (" (Spec_File_Name => ""*.ads"",");
714 Put_Line (" Dot_Replacement => ""-"",");
715 Put_Line (" Casing => lowercase);");
717 Put_Line ("pragma Source_File_Name_Project");
718 Put_Line (" (Body_File_Name => ""*.adb"",");
719 Put_Line (" Dot_Replacement => ""-"",");
720 Put_Line (" Casing => lowercase);");
723 -- Close the temporary file
727 if Opt.Verbose_Mode then
728 Write_Str ("Created configuration file """);
729 Write_Str (Get_Name_String (File_Name));
733 For_Project.Config_File_Name := File_Name;
734 For_Project.Config_File_Temp := True;
735 For_Project.Config_Checked := True;
739 end Create_Config_Pragmas_File;
745 procedure Create_Mapping (In_Tree : Project_Tree_Ref) is
747 Iter : Source_Iterator;
752 Iter := For_Each_Source (In_Tree);
754 Data := Element (Iter);
755 exit when Data = No_Source;
757 if Data.Unit /= No_Unit_Index then
758 if Data.Locally_Removed then
759 Fmap.Add_Forbidden_File_Name (Data.File);
762 (Unit_Name => Unit_Name_Type (Data.Unit.Name),
763 File_Name => Data.File,
764 Path_Name => File_Name_Type (Data.Path.Display_Name));
772 -------------------------
773 -- Create_Mapping_File --
774 -------------------------
776 procedure Create_Mapping_File
777 (Project : Project_Id;
779 In_Tree : Project_Tree_Ref;
780 Name : out Path_Name_Type)
782 File : File_Descriptor := Invalid_FD;
784 Buffer : String_Access := new String (1 .. Buffer_Initial);
785 Buffer_Last : Natural := 0;
787 procedure Put_Name_Buffer;
788 -- Put the line contained in the Name_Buffer in the global buffer
791 (Project : Project_Id;
792 In_Tree : Project_Tree_Ref;
793 State : in out Integer);
794 -- Generate the mapping file for Project (not recursively)
796 ---------------------
797 -- Put_Name_Buffer --
798 ---------------------
800 procedure Put_Name_Buffer is
802 if Current_Verbosity = High then
803 Debug_Output (Name_Buffer (1 .. Name_Len));
806 Name_Len := Name_Len + 1;
807 Name_Buffer (Name_Len) := ASCII.LF;
808 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
816 (Project : Project_Id;
817 In_Tree : Project_Tree_Ref;
818 State : in out Integer)
820 pragma Unreferenced (State);
823 Suffix : File_Name_Type;
824 Iter : Source_Iterator;
827 Debug_Output ("Add mapping for project", Project.Name);
828 Iter := For_Each_Source (In_Tree, Project, Language => Language);
831 Source := Prj.Element (Iter);
832 exit when Source = No_Source;
834 if Source.Replaced_By = No_Source
835 and then Source.Path.Name /= No_Path
837 (Source.Language.Config.Kind = File_Based
838 or else Source.Unit /= No_Unit_Index)
840 if Source.Unit /= No_Unit_Index then
841 Get_Name_String (Source.Unit.Name);
843 if Source.Language.Config.Kind = Unit_Based then
845 -- ??? Mapping_Spec_Suffix could be set in the case of
848 Add_Char_To_Name_Buffer ('%');
850 if Source.Kind = Spec then
851 Add_Char_To_Name_Buffer ('s');
853 Add_Char_To_Name_Buffer ('b');
860 Source.Language.Config.Mapping_Spec_Suffix;
863 Source.Language.Config.Mapping_Body_Suffix;
866 if Suffix /= No_File then
867 Add_Str_To_Name_Buffer
868 (Get_Name_String (Suffix));
875 Get_Name_String (Source.Display_File);
878 if Source.Locally_Removed then
880 Name_Buffer (1) := '/';
882 Get_Name_String (Source.Path.Display_Name);
892 procedure For_Every_Imported_Project is new
893 For_Every_Project_Imported (State => Integer, Action => Process);
895 Dummy : Integer := 0;
897 -- Start of processing for Create_Mapping_File
900 if Current_Verbosity = High then
901 Debug_Output ("Create mapping file for", Debug_Name (In_Tree));
904 Create_Temp_File (In_Tree.Shared, File, Name, "mapping");
906 if Current_Verbosity = High then
907 Debug_Increase_Indent ("Create mapping file ", Name_Id (Name));
910 For_Every_Imported_Project
911 (Project, In_Tree, Dummy, Include_Aggregated => False);
915 Status : Boolean := False;
918 if File /= Invalid_FD then
919 Last := Write (File, Buffer (1)'Address, Buffer_Last);
921 if Last = Buffer_Last then
922 GNAT.OS_Lib.Close (File, Status);
927 Prj.Com.Fail ("could not write mapping file");
933 Debug_Decrease_Indent ("Done create mapping file");
934 end Create_Mapping_File;
936 ----------------------
937 -- Create_Temp_File --
938 ----------------------
940 procedure Create_Temp_File
941 (Shared : Shared_Project_Tree_Data_Access;
942 Path_FD : out File_Descriptor;
943 Path_Name : out Path_Name_Type;
947 Tempdir.Create_Temp_File (Path_FD, Path_Name);
949 if Path_Name /= No_Path then
950 if Current_Verbosity = High then
951 Write_Line ("Create temp file (" & File_Use & ") "
952 & Get_Name_String (Path_Name));
955 Record_Temp_File (Shared, Path_Name);
959 ("unable to create temporary " & File_Use & " file");
961 end Create_Temp_File;
963 --------------------------
964 -- Create_New_Path_File --
965 --------------------------
967 procedure Create_New_Path_File
968 (Shared : Shared_Project_Tree_Data_Access;
969 Path_FD : out File_Descriptor;
970 Path_Name : out Path_Name_Type)
973 Create_Temp_File (Shared, Path_FD, Path_Name, "path file");
974 end Create_New_Path_File;
976 ------------------------------------
977 -- File_Name_Of_Library_Unit_Body --
978 ------------------------------------
980 function File_Name_Of_Library_Unit_Body
982 Project : Project_Id;
983 In_Tree : Project_Tree_Ref;
984 Main_Project_Only : Boolean := True;
985 Full_Path : Boolean := False) return String
987 The_Project : Project_Id := Project;
988 Original_Name : String := Name;
990 Lang : constant Language_Ptr :=
991 Get_Language_From_Name (Project, "ada");
994 The_Original_Name : Name_Id;
995 The_Spec_Name : Name_Id;
996 The_Body_Name : Name_Id;
999 -- ??? Same block in Project_Of
1000 Canonical_Case_File_Name (Original_Name);
1001 Name_Len := Original_Name'Length;
1002 Name_Buffer (1 .. Name_Len) := Original_Name;
1003 The_Original_Name := Name_Find;
1005 if Lang /= null then
1007 Naming : constant Lang_Naming_Data := Lang.Config.Naming_Data;
1008 Extended_Spec_Name : String :=
1009 Name & Namet.Get_Name_String
1010 (Naming.Spec_Suffix);
1011 Extended_Body_Name : String :=
1012 Name & Namet.Get_Name_String
1013 (Naming.Body_Suffix);
1016 Canonical_Case_File_Name (Extended_Spec_Name);
1017 Name_Len := Extended_Spec_Name'Length;
1018 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1019 The_Spec_Name := Name_Find;
1021 Canonical_Case_File_Name (Extended_Body_Name);
1022 Name_Len := Extended_Body_Name'Length;
1023 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1024 The_Body_Name := Name_Find;
1028 Name_Len := Name'Length;
1029 Name_Buffer (1 .. Name_Len) := Name;
1030 Canonical_Case_File_Name (Name_Buffer);
1031 The_Spec_Name := Name_Find;
1032 The_Body_Name := The_Spec_Name;
1035 if Current_Verbosity = High then
1036 Write_Str ("Looking for file name of """);
1040 Write_Str (" Extended Spec Name = """);
1041 Write_Str (Get_Name_String (The_Spec_Name));
1044 Write_Str (" Extended Body Name = """);
1045 Write_Str (Get_Name_String (The_Body_Name));
1050 -- For extending project, search in the extended project if the source
1051 -- is not found. For non extending projects, this loop will be run only
1055 -- Loop through units
1057 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1058 while Unit /= null loop
1061 if not Main_Project_Only
1063 (Unit.File_Names (Impl) /= null
1064 and then Unit.File_Names (Impl).Project = The_Project)
1067 Current_Name : File_Name_Type;
1069 -- Case of a body present
1071 if Unit.File_Names (Impl) /= null then
1072 Current_Name := Unit.File_Names (Impl).File;
1074 if Current_Verbosity = High then
1075 Write_Str (" Comparing with """);
1076 Write_Str (Get_Name_String (Current_Name));
1081 -- If it has the name of the original name, return the
1084 if Unit.Name = The_Original_Name
1086 Current_Name = File_Name_Type (The_Original_Name)
1088 if Current_Verbosity = High then
1093 return Get_Name_String
1094 (Unit.File_Names (Impl).Path.Name);
1097 return Get_Name_String (Current_Name);
1100 -- If it has the name of the extended body name,
1101 -- return the extended body name
1103 elsif Current_Name = File_Name_Type (The_Body_Name) then
1104 if Current_Verbosity = High then
1109 return Get_Name_String
1110 (Unit.File_Names (Impl).Path.Name);
1113 return Get_Name_String (The_Body_Name);
1117 if Current_Verbosity = High then
1118 Write_Line (" not good");
1127 if not Main_Project_Only
1129 (Unit.File_Names (Spec) /= null
1130 and then Unit.File_Names (Spec).Project =
1134 Current_Name : File_Name_Type;
1137 -- Case of spec present
1139 if Unit.File_Names (Spec) /= null then
1140 Current_Name := Unit.File_Names (Spec).File;
1141 if Current_Verbosity = High then
1142 Write_Str (" Comparing with """);
1143 Write_Str (Get_Name_String (Current_Name));
1148 -- If name same as original name, return original name
1150 if Unit.Name = The_Original_Name
1152 Current_Name = File_Name_Type (The_Original_Name)
1154 if Current_Verbosity = High then
1159 return Get_Name_String
1160 (Unit.File_Names (Spec).Path.Name);
1162 return Get_Name_String (Current_Name);
1165 -- If it has the same name as the extended spec name,
1166 -- return the extended spec name.
1168 elsif Current_Name = File_Name_Type (The_Spec_Name) then
1169 if Current_Verbosity = High then
1174 return Get_Name_String
1175 (Unit.File_Names (Spec).Path.Name);
1177 return Get_Name_String (The_Spec_Name);
1181 if Current_Verbosity = High then
1182 Write_Line (" not good");
1189 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1192 -- If we are not in an extending project, give up
1194 exit when not Main_Project_Only
1195 or else The_Project.Extends = No_Project;
1197 -- Otherwise, look in the project we are extending
1199 The_Project := The_Project.Extends;
1202 -- We don't know this file name, return an empty string
1205 end File_Name_Of_Library_Unit_Body;
1207 -------------------------
1208 -- For_All_Object_Dirs --
1209 -------------------------
1211 procedure For_All_Object_Dirs
1212 (Project : Project_Id;
1213 Tree : Project_Tree_Ref)
1215 procedure For_Project
1217 Tree : Project_Tree_Ref;
1218 Dummy : in out Integer);
1219 -- Get all object directories of Prj
1225 procedure For_Project
1227 Tree : Project_Tree_Ref;
1228 Dummy : in out Integer)
1230 pragma Unreferenced (Dummy, Tree);
1233 -- ??? Set_Ada_Paths has a different behavior for library project
1234 -- files, should we have the same ?
1236 if Prj.Object_Directory /= No_Path_Information then
1237 Get_Name_String (Prj.Object_Directory.Display_Name);
1238 Action (Name_Buffer (1 .. Name_Len));
1242 procedure Get_Object_Dirs is
1243 new For_Every_Project_Imported (Integer, For_Project);
1244 Dummy : Integer := 1;
1246 -- Start of processing for For_All_Object_Dirs
1249 Get_Object_Dirs (Project, Tree, Dummy);
1250 end For_All_Object_Dirs;
1252 -------------------------
1253 -- For_All_Source_Dirs --
1254 -------------------------
1256 procedure For_All_Source_Dirs
1257 (Project : Project_Id;
1258 In_Tree : Project_Tree_Ref)
1260 procedure For_Project
1262 In_Tree : Project_Tree_Ref;
1263 Dummy : in out Integer);
1264 -- Get all object directories of Prj
1270 procedure For_Project
1272 In_Tree : Project_Tree_Ref;
1273 Dummy : in out Integer)
1275 pragma Unreferenced (Dummy);
1277 Current : String_List_Id := Prj.Source_Dirs;
1278 The_String : String_Element;
1281 -- If there are Ada sources, call action with the name of every
1282 -- source directory.
1284 if Has_Ada_Sources (Project) then
1285 while Current /= Nil_String loop
1286 The_String := In_Tree.Shared.String_Elements.Table (Current);
1287 Action (Get_Name_String (The_String.Display_Value));
1288 Current := The_String.Next;
1293 procedure Get_Source_Dirs is
1294 new For_Every_Project_Imported (Integer, For_Project);
1295 Dummy : Integer := 1;
1297 -- Start of processing for For_All_Source_Dirs
1300 Get_Source_Dirs (Project, In_Tree, Dummy);
1301 end For_All_Source_Dirs;
1307 procedure Get_Reference
1308 (Source_File_Name : String;
1309 In_Tree : Project_Tree_Ref;
1310 Project : out Project_Id;
1311 Path : out Path_Name_Type)
1314 -- Body below could use some comments ???
1316 if Current_Verbosity > Default then
1317 Write_Str ("Getting Reference_Of (""");
1318 Write_Str (Source_File_Name);
1319 Write_Str (""") ... ");
1323 Original_Name : String := Source_File_Name;
1327 Canonical_Case_File_Name (Original_Name);
1328 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1330 while Unit /= null loop
1331 if Unit.File_Names (Spec) /= null
1332 and then Unit.File_Names (Spec).File /= No_File
1334 (Namet.Get_Name_String
1335 (Unit.File_Names (Spec).File) = Original_Name
1336 or else (Unit.File_Names (Spec).Path /=
1339 Namet.Get_Name_String
1340 (Unit.File_Names (Spec).Path.Name) =
1343 Project := Ultimate_Extending_Project_Of
1344 (Unit.File_Names (Spec).Project);
1345 Path := Unit.File_Names (Spec).Path.Display_Name;
1347 if Current_Verbosity > Default then
1348 Write_Str ("Done: Spec.");
1354 elsif Unit.File_Names (Impl) /= null
1355 and then Unit.File_Names (Impl).File /= No_File
1357 (Namet.Get_Name_String
1358 (Unit.File_Names (Impl).File) = Original_Name
1359 or else (Unit.File_Names (Impl).Path /=
1361 and then Namet.Get_Name_String
1362 (Unit.File_Names (Impl).Path.Name) =
1365 Project := Ultimate_Extending_Project_Of
1366 (Unit.File_Names (Impl).Project);
1367 Path := Unit.File_Names (Impl).Path.Display_Name;
1369 if Current_Verbosity > Default then
1370 Write_Str ("Done: Body.");
1377 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1381 Project := No_Project;
1384 if Current_Verbosity > Default then
1385 Write_Str ("Cannot be found.");
1394 procedure Initialize (In_Tree : Project_Tree_Ref) is
1396 In_Tree.Shared.Private_Part.Current_Source_Path_File := No_Path;
1397 In_Tree.Shared.Private_Part.Current_Object_Path_File := No_Path;
1404 -- Could use some comments in this body ???
1406 procedure Print_Sources (In_Tree : Project_Tree_Ref) is
1410 Write_Line ("List of Sources:");
1412 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1414 while Unit /= No_Unit_Index loop
1416 Write_Line (Namet.Get_Name_String (Unit.Name));
1418 if Unit.File_Names (Spec).File /= No_File then
1419 if Unit.File_Names (Spec).Project = No_Project then
1420 Write_Line (" No project");
1423 Write_Str (" Project: ");
1425 (Unit.File_Names (Spec).Project.Path.Name);
1426 Write_Line (Name_Buffer (1 .. Name_Len));
1429 Write_Str (" spec: ");
1431 (Namet.Get_Name_String
1432 (Unit.File_Names (Spec).File));
1435 if Unit.File_Names (Impl).File /= No_File then
1436 if Unit.File_Names (Impl).Project = No_Project then
1437 Write_Line (" No project");
1440 Write_Str (" Project: ");
1442 (Unit.File_Names (Impl).Project.Path.Name);
1443 Write_Line (Name_Buffer (1 .. Name_Len));
1446 Write_Str (" body: ");
1448 (Namet.Get_Name_String (Unit.File_Names (Impl).File));
1451 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1454 Write_Line ("end of List of Sources.");
1463 Main_Project : Project_Id;
1464 In_Tree : Project_Tree_Ref) return Project_Id
1466 Result : Project_Id := No_Project;
1468 Original_Name : String := Name;
1470 Lang : constant Language_Ptr :=
1471 Get_Language_From_Name (Main_Project, "ada");
1475 Current_Name : File_Name_Type;
1476 The_Original_Name : File_Name_Type;
1477 The_Spec_Name : File_Name_Type;
1478 The_Body_Name : File_Name_Type;
1481 -- ??? Same block in File_Name_Of_Library_Unit_Body
1482 Canonical_Case_File_Name (Original_Name);
1483 Name_Len := Original_Name'Length;
1484 Name_Buffer (1 .. Name_Len) := Original_Name;
1485 The_Original_Name := Name_Find;
1487 if Lang /= null then
1489 Naming : Lang_Naming_Data renames Lang.Config.Naming_Data;
1490 Extended_Spec_Name : String :=
1491 Name & Namet.Get_Name_String
1492 (Naming.Spec_Suffix);
1493 Extended_Body_Name : String :=
1494 Name & Namet.Get_Name_String
1495 (Naming.Body_Suffix);
1498 Canonical_Case_File_Name (Extended_Spec_Name);
1499 Name_Len := Extended_Spec_Name'Length;
1500 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1501 The_Spec_Name := Name_Find;
1503 Canonical_Case_File_Name (Extended_Body_Name);
1504 Name_Len := Extended_Body_Name'Length;
1505 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1506 The_Body_Name := Name_Find;
1510 The_Spec_Name := The_Original_Name;
1511 The_Body_Name := The_Original_Name;
1514 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1515 while Unit /= null loop
1517 -- Case of a body present
1519 if Unit.File_Names (Impl) /= null then
1520 Current_Name := Unit.File_Names (Impl).File;
1522 -- If it has the name of the original name or the body name,
1523 -- we have found the project.
1525 if Unit.Name = Name_Id (The_Original_Name)
1526 or else Current_Name = The_Original_Name
1527 or else Current_Name = The_Body_Name
1529 Result := Unit.File_Names (Impl).Project;
1536 if Unit.File_Names (Spec) /= null then
1537 Current_Name := Unit.File_Names (Spec).File;
1539 -- If name same as the original name, or the spec name, we have
1540 -- found the project.
1542 if Unit.Name = Name_Id (The_Original_Name)
1543 or else Current_Name = The_Original_Name
1544 or else Current_Name = The_Spec_Name
1546 Result := Unit.File_Names (Spec).Project;
1551 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1554 return Ultimate_Extending_Project_Of (Result);
1561 procedure Set_Ada_Paths
1562 (Project : Project_Id;
1563 In_Tree : Project_Tree_Ref;
1564 Including_Libraries : Boolean;
1565 Include_Path : Boolean := True;
1566 Objects_Path : Boolean := True)
1569 Shared : constant Shared_Project_Tree_Data_Access := In_Tree.Shared;
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, In_Tree);
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
1620 Add_To_Source_Path (Project.Source_Dirs, Shared, Source_Paths);
1624 if Process_Object_Dirs then
1625 Path := Get_Object_Directory
1627 Including_Libraries => Including_Libraries,
1628 Only_If_Ada => True);
1630 if Path /= No_Path then
1631 Add_To_Object_Path (Path, Object_Paths);
1636 procedure For_All_Projects is
1637 new For_Every_Project_Imported (Boolean, Recursive_Add);
1639 Dummy : Boolean := False;
1641 -- Start of processing for Set_Ada_Paths
1644 -- If it is the first time we call this procedure for this project,
1645 -- compute the source path and/or the object path.
1647 if Include_Path and then Project.Include_Path_File = No_Path then
1648 Source_Path_Table.Init (Source_Paths);
1649 Process_Source_Dirs := True;
1650 Create_New_Path_File (Shared, Source_FD, Project.Include_Path_File);
1653 -- For the object path, we make a distinction depending on
1654 -- Including_Libraries.
1656 if Objects_Path and Including_Libraries then
1657 if Project.Objects_Path_File_With_Libs = No_Path then
1658 Object_Path_Table.Init (Object_Paths);
1659 Process_Object_Dirs := True;
1660 Create_New_Path_File
1661 (Shared, Object_FD, Project.Objects_Path_File_With_Libs);
1664 elsif Objects_Path then
1665 if Project.Objects_Path_File_Without_Libs = No_Path then
1666 Object_Path_Table.Init (Object_Paths);
1667 Process_Object_Dirs := True;
1668 Create_New_Path_File
1669 (Shared, Object_FD, Project.Objects_Path_File_Without_Libs);
1673 -- If there is something to do, set Seen to False for all projects,
1674 -- then call the recursive procedure Add for Project.
1676 if Process_Source_Dirs or Process_Object_Dirs then
1677 For_All_Projects (Project, In_Tree, Dummy);
1680 -- Write and close any file that has been created. Source_FD is not set
1681 -- when this subprogram is called a second time or more, since we reuse
1682 -- the previous version of the file.
1684 if Source_FD /= Invalid_FD then
1687 for Index in Source_Path_Table.First ..
1688 Source_Path_Table.Last (Source_Paths)
1690 Get_Name_String (Source_Paths.Table (Index));
1691 Name_Len := Name_Len + 1;
1692 Name_Buffer (Name_Len) := ASCII.LF;
1693 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
1696 Last := Write (Source_FD, Buffer (1)'Address, Buffer_Last);
1698 if Last = Buffer_Last then
1699 Close (Source_FD, Status);
1706 Prj.Com.Fail ("could not write temporary file");
1710 if Object_FD /= Invalid_FD then
1713 for Index in Object_Path_Table.First ..
1714 Object_Path_Table.Last (Object_Paths)
1716 Get_Name_String (Object_Paths.Table (Index));
1717 Name_Len := Name_Len + 1;
1718 Name_Buffer (Name_Len) := ASCII.LF;
1719 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
1722 Last := Write (Object_FD, Buffer (1)'Address, Buffer_Last);
1724 if Last = Buffer_Last then
1725 Close (Object_FD, Status);
1731 Prj.Com.Fail ("could not write temporary file");
1735 -- Set the env vars, if they need to be changed, and set the
1736 -- corresponding flags.
1738 if Include_Path and then
1739 Shared.Private_Part.Current_Source_Path_File /=
1740 Project.Include_Path_File
1742 Shared.Private_Part.Current_Source_Path_File :=
1743 Project.Include_Path_File;
1745 (Project_Include_Path_File,
1746 Get_Name_String (Shared.Private_Part.Current_Source_Path_File));
1749 if Objects_Path then
1750 if Including_Libraries then
1751 if Shared.Private_Part.Current_Object_Path_File /=
1752 Project.Objects_Path_File_With_Libs
1754 Shared.Private_Part.Current_Object_Path_File :=
1755 Project.Objects_Path_File_With_Libs;
1757 (Project_Objects_Path_File,
1759 (Shared.Private_Part.Current_Object_Path_File));
1763 if Shared.Private_Part.Current_Object_Path_File /=
1764 Project.Objects_Path_File_Without_Libs
1766 Shared.Private_Part.Current_Object_Path_File :=
1767 Project.Objects_Path_File_Without_Libs;
1769 (Project_Objects_Path_File,
1771 (Shared.Private_Part.Current_Object_Path_File));
1779 -----------------------
1780 -- Set_Path_File_Var --
1781 -----------------------
1783 procedure Set_Path_File_Var (Name : String; Value : String) is
1784 Host_Spec : String_Access := To_Host_File_Spec (Value);
1786 if Host_Spec = null then
1788 ("could not convert file name """ & Value & """ to host spec");
1790 Setenv (Name, Host_Spec.all);
1793 end Set_Path_File_Var;
1795 ---------------------
1796 -- Add_Directories --
1797 ---------------------
1799 procedure Add_Directories
1800 (Self : in out Project_Search_Path;
1803 Tmp : String_Access;
1805 if Self.Path = null then
1806 Self.Path := new String'(Uninitialized_Prefix & Path);
1809 Self.Path := new String'(Tmp.all & Path_Separator & Path);
1813 if Current_Verbosity = High then
1814 Debug_Output ("Adding directories to Project_Path: """
1817 end Add_Directories;
1819 --------------------
1820 -- Is_Initialized --
1821 --------------------
1823 function Is_Initialized (Self : Project_Search_Path) return Boolean is
1825 return Self.Path /= null
1826 and then (Self.Path'Length = 0
1827 or else Self.Path (Self.Path'First) /= '#');
1830 ----------------------
1831 -- Initialize_Empty --
1832 ----------------------
1834 procedure Initialize_Empty (Self : in out Project_Search_Path) is
1837 Self.Path := new String'("");
1838 end Initialize_Empty;
1840 -------------------------------------
1841 -- Initialize_Default_Project_Path --
1842 -------------------------------------
1844 procedure Initialize_Default_Project_Path
1845 (Self : in out Project_Search_Path;
1846 Target_Name : String)
1848 Add_Default_Dir : Boolean := True;
1852 New_Last : Positive;
1854 Ada_Project_Path : constant String := "ADA_PROJECT_PATH";
1855 Gpr_Project_Path : constant String := "GPR_PROJECT_PATH";
1856 -- Name of alternate env. variable that contain path name(s) of
1857 -- directories where project files may reside. GPR_PROJECT_PATH has
1858 -- precedence over ADA_PROJECT_PATH.
1860 Gpr_Prj_Path : String_Access;
1861 Ada_Prj_Path : String_Access;
1862 -- The path name(s) of directories where project files may reside.
1866 if Is_Initialized (Self) then
1870 -- The current directory is always first in the search path. Since the
1871 -- Project_Path currently starts with '#:' as a sign that it isn't
1872 -- initialized, we simply replace '#' with '.'
1874 if Self.Path = null then
1875 Self.Path := new String'('.' & Path_Separator);
1877 Self.Path (Self.Path'First) := '.';
1880 -- Then the reset of the project path (if any) currently contains the
1881 -- directories added through Add_Search_Project_Directory
1883 -- If environment variables are defined and not empty, add their content
1885 Gpr_Prj_Path := Getenv (Gpr_Project_Path);
1886 Ada_Prj_Path := Getenv (Ada_Project_Path);
1888 if Gpr_Prj_Path.all /= "" then
1889 Add_Directories (Self, Gpr_Prj_Path.all);
1892 Free (Gpr_Prj_Path);
1894 if Ada_Prj_Path.all /= "" then
1895 Add_Directories (Self, Ada_Prj_Path.all);
1898 Free (Ada_Prj_Path);
1900 -- Copy to Name_Buffer, since we will need to manipulate the path
1902 Name_Len := Self.Path'Length;
1903 Name_Buffer (1 .. Name_Len) := Self.Path.all;
1905 -- Scan the directory path to see if "-" is one of the directories.
1906 -- Remove each occurrence of "-" and set Add_Default_Dir to False.
1907 -- Also resolve relative paths and symbolic links.
1911 while First <= Name_Len
1912 and then (Name_Buffer (First) = Path_Separator)
1917 exit when First > Name_Len;
1921 while Last < Name_Len
1922 and then Name_Buffer (Last + 1) /= Path_Separator
1927 -- If the directory is "-", set Add_Default_Dir to False and
1928 -- remove from path.
1930 if Name_Buffer (First .. Last) = No_Project_Default_Dir then
1931 Add_Default_Dir := False;
1933 for J in Last + 1 .. Name_Len loop
1934 Name_Buffer (J - No_Project_Default_Dir'Length - 1) :=
1938 Name_Len := Name_Len - No_Project_Default_Dir'Length - 1;
1940 -- After removing the '-', go back one character to get the next
1941 -- directory correctly.
1945 elsif not Hostparm.OpenVMS
1946 or else not Is_Absolute_Path (Name_Buffer (First .. Last))
1948 -- On VMS, only expand relative path names, as absolute paths
1949 -- may correspond to multi-valued VMS logical names.
1952 New_Dir : constant String :=
1954 (Name_Buffer (First .. Last),
1955 Resolve_Links => Opt.Follow_Links_For_Dirs);
1958 -- If the absolute path was resolved and is different from
1959 -- the original, replace original with the resolved path.
1961 if New_Dir /= Name_Buffer (First .. Last)
1962 and then New_Dir'Length /= 0
1964 New_Len := Name_Len + New_Dir'Length - (Last - First + 1);
1965 New_Last := First + New_Dir'Length - 1;
1966 Name_Buffer (New_Last + 1 .. New_Len) :=
1967 Name_Buffer (Last + 1 .. Name_Len);
1968 Name_Buffer (First .. New_Last) := New_Dir;
1969 Name_Len := New_Len;
1980 -- Set the initial value of Current_Project_Path
1982 if Add_Default_Dir then
1984 Prefix : String_Ptr := Sdefault.Search_Dir_Prefix;
1987 if Prefix = null then
1988 Prefix := new String'(Executable_Prefix_Path);
1990 if Prefix.all /= "" then
1991 if Target_Name /= "" then
1992 Add_Str_To_Name_Buffer
1993 (Path_Separator & Prefix.all &
1994 Target_Name & Directory_Separator &
1995 "lib" & Directory_Separator & "gnat");
1998 Add_Str_To_Name_Buffer
1999 (Path_Separator & Prefix.all &
2000 "share" & Directory_Separator & "gpr");
2001 Add_Str_To_Name_Buffer
2002 (Path_Separator & Prefix.all &
2003 "lib" & Directory_Separator & "gnat");
2008 new String'(Name_Buffer (1 .. Name_Len) & Path_Separator &
2010 ".." & Directory_Separator &
2011 ".." & Directory_Separator &
2012 ".." & Directory_Separator & "gnat");
2019 if Self.Path = null then
2020 Self.Path := new String'(Name_Buffer (1 .. Name_Len));
2022 end Initialize_Default_Project_Path;
2028 procedure Get_Path (Self : Project_Search_Path; Path : out String_Access) is
2030 pragma Assert (Is_Initialized (Self));
2038 procedure Set_Path (Self : in out Project_Search_Path; Path : String) is
2041 Self.Path := new String'(Path);
2042 Projects_Paths.Reset (Self.Cache);
2049 procedure Find_Project
2050 (Self : in out Project_Search_Path;
2051 Project_File_Name : String;
2053 Path : out Namet.Path_Name_Type)
2055 File : constant String := Project_File_Name;
2056 -- Have to do a copy, in case the parameter is Name_Buffer, which we
2059 function Try_Path_Name (Path : String) return String_Access;
2060 pragma Inline (Try_Path_Name);
2061 -- Try the specified Path
2067 function Try_Path_Name (Path : String) return String_Access is
2070 Result : String_Access := null;
2073 if Current_Verbosity = High then
2074 Debug_Output ("Trying " & Path);
2077 if Is_Absolute_Path (Path) then
2078 if Is_Regular_File (Path) then
2079 Result := new String'(Path);
2083 -- Because we don't want to resolve symbolic links, we cannot use
2084 -- Locate_Regular_File. So, we try each possible path
2087 First := Self.Path'First;
2088 while First <= Self.Path'Last loop
2089 while First <= Self.Path'Last
2090 and then Self.Path (First) = Path_Separator
2095 exit when First > Self.Path'Last;
2098 while Last < Self.Path'Last
2099 and then Self.Path (Last + 1) /= Path_Separator
2106 if not Is_Absolute_Path (Self.Path (First .. Last)) then
2107 Add_Str_To_Name_Buffer (Get_Current_Dir); -- ??? System call
2108 Add_Char_To_Name_Buffer (Directory_Separator);
2111 Add_Str_To_Name_Buffer (Self.Path (First .. Last));
2112 Add_Char_To_Name_Buffer (Directory_Separator);
2113 Add_Str_To_Name_Buffer (Path);
2115 if Current_Verbosity = High then
2116 Debug_Output ("Testing file " & Name_Buffer (1 .. Name_Len));
2119 if Is_Regular_File (Name_Buffer (1 .. Name_Len)) then
2120 Result := new String'(Name_Buffer (1 .. Name_Len));
2131 -- Local Declarations
2133 Result : String_Access;
2134 Has_Dot : Boolean := False;
2137 -- Start of processing for Find_Project
2140 pragma Assert (Is_Initialized (Self));
2142 if Current_Verbosity = High then
2143 Debug_Increase_Indent
2144 ("Searching for project """ & File & """ in """
2148 -- Check the project cache
2150 Name_Len := File'Length;
2151 Name_Buffer (1 .. Name_Len) := File;
2153 Path := Projects_Paths.Get (Self.Cache, Key);
2155 if Path /= No_Path then
2156 Debug_Decrease_Indent;
2160 -- Check if File contains an extension (a dot before a
2161 -- directory separator). If it is the case we do not try project file
2162 -- with an added extension as it is not possible to have multiple dots
2163 -- on a project file name.
2165 Check_Dot : for K in reverse File'Range loop
2166 if File (K) = '.' then
2171 exit Check_Dot when File (K) = Directory_Separator
2172 or else File (K) = '/';
2175 if not Is_Absolute_Path (File) then
2177 -- First we try <directory>/<file_name>.<extension>
2180 Result := Try_Path_Name
2181 (Directory & Directory_Separator &
2182 File & Project_File_Extension);
2185 -- Then we try <directory>/<file_name>
2187 if Result = null then
2188 Result := Try_Path_Name (Directory & Directory_Separator & File);
2192 -- Then we try <file_name>.<extension>
2194 if Result = null and then not Has_Dot then
2195 Result := Try_Path_Name (File & Project_File_Extension);
2198 -- Then we try <file_name>
2200 if Result = null then
2201 Result := Try_Path_Name (File);
2204 -- If we cannot find the project file, we return an empty string
2206 if Result = null then
2207 Path := Namet.No_Path;
2212 Final_Result : constant String :=
2213 GNAT.OS_Lib.Normalize_Pathname
2215 Directory => Directory,
2216 Resolve_Links => Opt.Follow_Links_For_Files,
2217 Case_Sensitive => True);
2220 Name_Len := Final_Result'Length;
2221 Name_Buffer (1 .. Name_Len) := Final_Result;
2223 Projects_Paths.Set (Self.Cache, Key, Path);
2227 Debug_Decrease_Indent;
2234 procedure Free (Self : in out Project_Search_Path) is
2237 Projects_Paths.Reset (Self.Cache);
2244 procedure Copy (From : Project_Search_Path; To : out Project_Search_Path) is
2248 if From.Path /= null then
2249 To.Path := new String'(From.Path.all);
2252 -- No need to copy the Cache, it will be recomputed as needed