1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2001-2014, 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 ------------------------------------------------------------------------------
27 with Makeutl
; use Makeutl
;
29 with Osint
; use Osint
;
30 with Output
; use Output
;
31 with Prj
.Com
; use Prj
.Com
;
35 with Ada
.Text_IO
; use Ada
.Text_IO
;
37 with GNAT
.Directory_Operations
; use GNAT
.Directory_Operations
;
39 package body Prj
.Env
is
41 Buffer_Initial
: constant := 1_000
;
42 -- Initial arbitrary size of buffers
44 Uninitialized_Prefix
: constant String := '#' & Path_Separator
;
45 -- Prefix to indicate that the project path has not been initialized yet.
46 -- Must be two characters long
48 No_Project_Default_Dir
: constant String := "-";
49 -- Indicator in the project path to indicate that the default search
50 -- directories should not be added to the path
52 -----------------------
53 -- Local Subprograms --
54 -----------------------
56 package Source_Path_Table
is new GNAT
.Dynamic_Tables
57 (Table_Component_Type
=> Name_Id
,
58 Table_Index_Type
=> Natural,
61 Table_Increment
=> 100);
62 -- A table to store the source dirs before creating the source path file
64 package Object_Path_Table
is new GNAT
.Dynamic_Tables
65 (Table_Component_Type
=> Path_Name_Type
,
66 Table_Index_Type
=> Natural,
69 Table_Increment
=> 100);
70 -- A table to store the object dirs, before creating the object path file
72 procedure Add_To_Buffer
74 Buffer
: in out String_Access
;
75 Buffer_Last
: in out Natural);
76 -- Add a string to Buffer, extending Buffer if needed
79 (Source_Dirs
: String_List_Id
;
80 Shared
: Shared_Project_Tree_Data_Access
;
81 Buffer
: in out String_Access
;
82 Buffer_Last
: in out Natural);
83 -- Add to Ada_Path_Buffer all the source directories in string list
84 -- Source_Dirs, if any.
88 Buffer
: in out String_Access
;
89 Buffer_Last
: in out Natural);
90 -- If Dir is not already in the global variable Ada_Path_Buffer, add it.
91 -- If Buffer_Last /= 0, prepend a Path_Separator character to Path.
93 procedure Add_To_Source_Path
94 (Source_Dirs
: String_List_Id
;
95 Shared
: Shared_Project_Tree_Data_Access
;
96 Source_Paths
: in out Source_Path_Table
.Instance
);
97 -- Add to Ada_Path_B all the source directories in string list
98 -- Source_Dirs, if any. Increment Ada_Path_Length.
100 procedure Add_To_Object_Path
101 (Object_Dir
: Path_Name_Type
;
102 Object_Paths
: in out Object_Path_Table
.Instance
);
103 -- Add Object_Dir to object path table. Make sure it is not duplicate
104 -- and it is the last one in the current table.
106 ----------------------
107 -- Ada_Include_Path --
108 ----------------------
110 function Ada_Include_Path
111 (Project
: Project_Id
;
112 In_Tree
: Project_Tree_Ref
;
113 Recursive
: Boolean := False) return String
115 Buffer
: String_Access
;
116 Buffer_Last
: Natural := 0;
119 (Project
: Project_Id
;
120 In_Tree
: Project_Tree_Ref
;
121 Dummy
: in out Boolean);
122 -- Add source dirs of Project to the path
129 (Project
: Project_Id
;
130 In_Tree
: Project_Tree_Ref
;
131 Dummy
: in out Boolean)
135 (Project
.Source_Dirs
, In_Tree
.Shared
, Buffer
, Buffer_Last
);
138 procedure For_All_Projects
is
139 new For_Every_Project_Imported
(Boolean, Add
);
141 Dummy
: Boolean := False;
143 -- Start of processing for Ada_Include_Path
148 -- If it is the first time we call this function for this project,
149 -- compute the source path.
151 if Project
.Ada_Include_Path
= null then
152 Buffer
:= new String (1 .. Buffer_Initial
);
154 (Project
, In_Tree
, Dummy
, Include_Aggregated
=> True);
155 Project
.Ada_Include_Path
:= new String'(Buffer (1 .. Buffer_Last));
159 return Project.Ada_Include_Path.all;
162 Buffer := new String (1 .. Buffer_Initial);
164 (Project.Source_Dirs, In_Tree.Shared, Buffer, Buffer_Last);
167 Result : constant String := Buffer (1 .. Buffer_Last);
173 end Ada_Include_Path;
175 ----------------------
176 -- Ada_Objects_Path --
177 ----------------------
179 function Ada_Objects_Path
180 (Project : Project_Id;
181 In_Tree : Project_Tree_Ref;
182 Including_Libraries : Boolean := True) return String_Access
184 Buffer : String_Access;
185 Buffer_Last : Natural := 0;
188 (Project : Project_Id;
189 In_Tree : Project_Tree_Ref;
190 Dummy : in out Boolean);
191 -- Add all the object directories of a project to the path
198 (Project : Project_Id;
199 In_Tree : Project_Tree_Ref;
200 Dummy : in out Boolean)
202 pragma Unreferenced (In_Tree);
204 Path : constant Path_Name_Type :=
207 Including_Libraries => Including_Libraries,
208 Only_If_Ada => False);
210 if Path /= No_Path then
211 Add_To_Path (Get_Name_String (Path), Buffer, Buffer_Last);
215 procedure For_All_Projects is
216 new For_Every_Project_Imported (Boolean, Add);
218 Dummy : Boolean := False;
220 Result : String_Access;
222 -- Start of processing for Ada_Objects_Path
225 -- If it is the first time we call this function for
226 -- this project, compute the objects path
228 if Including_Libraries and then Project.Ada_Objects_Path /= null then
229 return Project.Ada_Objects_Path;
231 elsif not Including_Libraries
232 and then Project.Ada_Objects_Path_No_Libs /= null
234 return Project.Ada_Objects_Path_No_Libs;
237 Buffer := new String (1 .. Buffer_Initial);
238 For_All_Projects (Project, In_Tree, Dummy);
239 Result := new String'(Buffer
(1 .. Buffer_Last
));
242 if Including_Libraries
then
243 Project
.Ada_Objects_Path
:= Result
;
245 Project
.Ada_Objects_Path_No_Libs
:= Result
;
250 end Ada_Objects_Path
;
256 procedure Add_To_Buffer
258 Buffer
: in out String_Access
;
259 Buffer_Last
: in out Natural)
261 Last
: constant Natural := Buffer_Last
+ S
'Length;
264 while Last
> Buffer
'Last loop
266 New_Buffer
: constant String_Access
:=
267 new String (1 .. 2 * Buffer
'Last);
269 New_Buffer
(1 .. Buffer_Last
) := Buffer
(1 .. Buffer_Last
);
271 Buffer
:= New_Buffer
;
275 Buffer
(Buffer_Last
+ 1 .. Last
) := S
;
279 ------------------------
280 -- Add_To_Object_Path --
281 ------------------------
283 procedure Add_To_Object_Path
284 (Object_Dir
: Path_Name_Type
;
285 Object_Paths
: in out Object_Path_Table
.Instance
)
288 -- Check if the directory is already in the table
291 Object_Path_Table
.First
.. Object_Path_Table
.Last
(Object_Paths
)
293 -- If it is, remove it, and add it as the last one
295 if Object_Paths
.Table
(Index
) = Object_Dir
then
297 Index
+ 1 .. Object_Path_Table
.Last
(Object_Paths
)
299 Object_Paths
.Table
(Index2
- 1) := Object_Paths
.Table
(Index2
);
303 (Object_Path_Table
.Last
(Object_Paths
)) := Object_Dir
;
308 -- The directory is not already in the table, add it
310 Object_Path_Table
.Append
(Object_Paths
, Object_Dir
);
311 end Add_To_Object_Path
;
317 procedure Add_To_Path
318 (Source_Dirs
: String_List_Id
;
319 Shared
: Shared_Project_Tree_Data_Access
;
320 Buffer
: in out String_Access
;
321 Buffer_Last
: in out Natural)
323 Current
: String_List_Id
;
324 Source_Dir
: String_Element
;
326 Current
:= Source_Dirs
;
327 while Current
/= Nil_String
loop
328 Source_Dir
:= Shared
.String_Elements
.Table
(Current
);
329 Add_To_Path
(Get_Name_String
(Source_Dir
.Display_Value
),
330 Buffer
, Buffer_Last
);
331 Current
:= Source_Dir
.Next
;
335 procedure Add_To_Path
337 Buffer
: in out String_Access
;
338 Buffer_Last
: in out Natural)
341 New_Buffer
: String_Access
;
344 function Is_Present
(Path
: String; Dir
: String) return Boolean;
345 -- Return True if Dir is part of Path
351 function Is_Present
(Path
: String; Dir
: String) return Boolean is
352 Last
: constant Integer := Path
'Last - Dir
'Length + 1;
355 for J
in Path
'First .. Last
loop
357 -- Note: the order of the conditions below is important, since
358 -- it ensures a minimal number of string comparisons.
360 if (J
= Path
'First or else Path
(J
- 1) = Path_Separator
)
362 (J
+ Dir
'Length > Path
'Last
363 or else Path
(J
+ Dir
'Length) = Path_Separator
)
364 and then Dir
= Path
(J
.. J
+ Dir
'Length - 1)
373 -- Start of processing for Add_To_Path
376 if Is_Present
(Buffer
(1 .. Buffer_Last
), Dir
) then
378 -- Dir is already in the path, nothing to do
383 Min_Len
:= Buffer_Last
+ Dir
'Length;
385 if Buffer_Last
> 0 then
387 -- Add 1 for the Path_Separator character
389 Min_Len
:= Min_Len
+ 1;
392 -- If Ada_Path_Buffer is too small, increase it
396 if Len
< Min_Len
then
399 exit when Len
>= Min_Len
;
402 New_Buffer
:= new String (1 .. Len
);
403 New_Buffer
(1 .. Buffer_Last
) := Buffer
(1 .. Buffer_Last
);
405 Buffer
:= New_Buffer
;
408 if Buffer_Last
> 0 then
409 Buffer_Last
:= Buffer_Last
+ 1;
410 Buffer
(Buffer_Last
) := Path_Separator
;
413 Buffer
(Buffer_Last
+ 1 .. Buffer_Last
+ Dir
'Length) := Dir
;
414 Buffer_Last
:= Buffer_Last
+ Dir
'Length;
417 ------------------------
418 -- Add_To_Source_Path --
419 ------------------------
421 procedure Add_To_Source_Path
422 (Source_Dirs
: String_List_Id
;
423 Shared
: Shared_Project_Tree_Data_Access
;
424 Source_Paths
: in out Source_Path_Table
.Instance
)
426 Current
: String_List_Id
;
427 Source_Dir
: String_Element
;
431 -- Add each source directory
433 Current
:= Source_Dirs
;
434 while Current
/= Nil_String
loop
435 Source_Dir
:= Shared
.String_Elements
.Table
(Current
);
438 -- Check if the source directory is already in the table
441 Source_Path_Table
.First
.. Source_Path_Table
.Last
(Source_Paths
)
443 -- If it is already, no need to add it
445 if Source_Paths
.Table
(Index
) = Source_Dir
.Value
then
452 Source_Path_Table
.Append
(Source_Paths
, Source_Dir
.Display_Value
);
455 -- Next source directory
457 Current
:= Source_Dir
.Next
;
459 end Add_To_Source_Path
;
461 --------------------------------
462 -- Create_Config_Pragmas_File --
463 --------------------------------
465 procedure Create_Config_Pragmas_File
466 (For_Project
: Project_Id
;
467 In_Tree
: Project_Tree_Ref
)
469 type Naming_Id
is new Nat
;
470 package Naming_Table
is new GNAT
.Dynamic_Tables
471 (Table_Component_Type
=> Lang_Naming_Data
,
472 Table_Index_Type
=> Naming_Id
,
473 Table_Low_Bound
=> 1,
475 Table_Increment
=> 100);
477 Default_Naming
: constant Naming_Id
:= Naming_Table
.First
;
478 Namings
: Naming_Table
.Instance
;
479 -- Table storing the naming data for gnatmake/gprmake
481 Buffer
: String_Access
:= new String (1 .. Buffer_Initial
);
482 Buffer_Last
: Natural := 0;
484 File_Name
: Path_Name_Type
:= No_Path
;
485 File
: File_Descriptor
:= Invalid_FD
;
487 Current_Naming
: Naming_Id
;
490 (Project
: Project_Id
;
491 In_Tree
: Project_Tree_Ref
;
492 State
: in out Integer);
493 -- Recursive procedure that put in the config pragmas file any non
494 -- standard naming schemes, if it is not already in the file, then call
495 -- itself for any imported project.
497 procedure Put
(Source
: Source_Id
);
498 -- Put an SFN pragma in the temporary file
500 procedure Put
(S
: String);
501 procedure Put_Line
(S
: String);
502 -- Output procedures, analogous to normal Text_IO procs of same name.
503 -- The text is put in Buffer, then it will be written into a temporary
504 -- file with procedure Write_Temp_File below.
506 procedure Write_Temp_File
;
507 -- Create a temporary file and put the content of the buffer in it
514 (Project
: Project_Id
;
515 In_Tree
: Project_Tree_Ref
;
516 State
: in out Integer)
518 pragma Unreferenced
(State
);
520 Lang
: constant Language_Ptr
:=
521 Get_Language_From_Name
(Project
, "ada");
522 Naming
: Lang_Naming_Data
;
523 Iter
: Source_Iterator
;
527 if Current_Verbosity
= High
then
528 Debug_Output
("Checking project file:", Project
.Name
);
532 if Current_Verbosity
= High
then
533 Debug_Output
("Languages does not contain Ada, nothing to do");
539 -- Visit all the files and process those that need an SFN pragma
541 Iter
:= For_Each_Source
(In_Tree
, Project
);
542 while Element
(Iter
) /= No_Source
loop
543 Source
:= Element
(Iter
);
545 if not Source
.Locally_Removed
546 and then Source
.Unit
/= null
548 (Source
.Index
>= 1 or else Source
.Naming_Exception
/= No
)
556 Naming
:= Lang
.Config
.Naming_Data
;
558 -- Is the naming scheme of this project one that we know?
560 Current_Naming
:= Default_Naming
;
561 while Current_Naming
<= Naming_Table
.Last
(Namings
)
562 and then Namings
.Table
(Current_Naming
).Dot_Replacement
=
563 Naming
.Dot_Replacement
564 and then Namings
.Table
(Current_Naming
).Casing
=
566 and then Namings
.Table
(Current_Naming
).Separate_Suffix
=
567 Naming
.Separate_Suffix
569 Current_Naming
:= Current_Naming
+ 1;
572 -- If we don't know it, add it
574 if Current_Naming
> Naming_Table
.Last
(Namings
) then
575 Naming_Table
.Increment_Last
(Namings
);
576 Namings
.Table
(Naming_Table
.Last
(Namings
)) := Naming
;
578 -- Put the SFN pragmas for the naming scheme
583 ("pragma Source_File_Name_Project");
585 (" (Spec_File_Name => ""*" &
586 Get_Name_String
(Naming
.Spec_Suffix
) & """,");
589 Image
(Naming
.Casing
) & ",");
591 (" Dot_Replacement => """ &
592 Get_Name_String
(Naming
.Dot_Replacement
) & """);");
597 ("pragma Source_File_Name_Project");
599 (" (Body_File_Name => ""*" &
600 Get_Name_String
(Naming
.Body_Suffix
) & """,");
603 Image
(Naming
.Casing
) & ",");
605 (" Dot_Replacement => """ &
606 Get_Name_String
(Naming
.Dot_Replacement
) &
609 -- and maybe separate
611 if Naming
.Body_Suffix
/= Naming
.Separate_Suffix
then
612 Put_Line
("pragma Source_File_Name_Project");
614 (" (Subunit_File_Name => ""*" &
615 Get_Name_String
(Naming
.Separate_Suffix
) & """,");
618 Image
(Naming
.Casing
) & ",");
620 (" Dot_Replacement => """ &
621 Get_Name_String
(Naming
.Dot_Replacement
) &
631 procedure Put
(Source
: Source_Id
) is
633 -- Put the pragma SFN for the unit kind (spec or body)
635 Put
("pragma Source_File_Name_Project (");
636 Put
(Namet
.Get_Name_String
(Source
.Unit
.Name
));
638 if Source
.Kind
= Spec
then
639 Put
(", Spec_File_Name => """);
641 Put
(", Body_File_Name => """);
644 Put
(Namet
.Get_Name_String
(Source
.File
));
647 if Source
.Index
/= 0 then
649 Put
(Source
.Index
'Img);
655 procedure Put
(S
: String) is
657 Add_To_Buffer
(S
, Buffer
, Buffer_Last
);
659 if Current_Verbosity
= High
then
668 procedure Put_Line
(S
: String) is
670 -- Add an ASCII.LF to the string. As this config file is supposed to
671 -- be used only by the compiler, we don't care about the characters
672 -- for the end of line. In fact we could have put a space, but
673 -- it is more convenient to be able to read gnat.adc during
674 -- development, for which the ASCII.LF is fine.
677 Put
(S
=> (1 => ASCII
.LF
));
680 ---------------------
681 -- Write_Temp_File --
682 ---------------------
684 procedure Write_Temp_File
is
685 Status
: Boolean := False;
689 Tempdir
.Create_Temp_File
(File
, File_Name
);
691 if File
/= Invalid_FD
then
692 Last
:= Write
(File
, Buffer
(1)'Address, Buffer_Last
);
694 if Last
= Buffer_Last
then
695 Close
(File
, Status
);
700 Prj
.Com
.Fail
("unable to create temporary file");
704 procedure Check_Imported_Projects
is
705 new For_Every_Project_Imported
(Integer, Check
);
707 Dummy
: Integer := 0;
709 -- Start of processing for Create_Config_Pragmas_File
712 if not For_Project
.Config_Checked
then
713 Naming_Table
.Init
(Namings
);
715 -- Check the naming schemes
717 Check_Imported_Projects
718 (For_Project
, In_Tree
, Dummy
, Imported_First
=> False);
720 -- If there are no non standard naming scheme, issue the GNAT
721 -- standard naming scheme. This will tell the compiler that
722 -- a project file is used and will forbid any pragma SFN.
724 if Buffer_Last
= 0 then
726 Put_Line
("pragma Source_File_Name_Project");
727 Put_Line
(" (Spec_File_Name => ""*.ads"",");
728 Put_Line
(" Dot_Replacement => ""-"",");
729 Put_Line
(" Casing => lowercase);");
731 Put_Line
("pragma Source_File_Name_Project");
732 Put_Line
(" (Body_File_Name => ""*.adb"",");
733 Put_Line
(" Dot_Replacement => ""-"",");
734 Put_Line
(" Casing => lowercase);");
737 -- Close the temporary file
741 if Opt
.Verbose_Mode
then
742 Write_Str
("Created configuration file """);
743 Write_Str
(Get_Name_String
(File_Name
));
747 For_Project
.Config_File_Name
:= File_Name
;
748 For_Project
.Config_File_Temp
:= True;
749 For_Project
.Config_Checked
:= True;
753 end Create_Config_Pragmas_File
;
759 procedure Create_Mapping
(In_Tree
: Project_Tree_Ref
) is
761 Iter
: Source_Iterator
;
766 Iter
:= For_Each_Source
(In_Tree
);
768 Data
:= Element
(Iter
);
769 exit when Data
= No_Source
;
771 if Data
.Unit
/= No_Unit_Index
then
772 if Data
.Locally_Removed
and then not Data
.Suppressed
then
773 Fmap
.Add_Forbidden_File_Name
(Data
.File
);
776 (Unit_Name
=> Unit_Name_Type
(Data
.Unit
.Name
),
777 File_Name
=> Data
.File
,
778 Path_Name
=> File_Name_Type
(Data
.Path
.Display_Name
));
786 -------------------------
787 -- Create_Mapping_File --
788 -------------------------
790 procedure Create_Mapping_File
791 (Project
: Project_Id
;
793 In_Tree
: Project_Tree_Ref
;
794 Name
: out Path_Name_Type
)
796 File
: File_Descriptor
:= Invalid_FD
;
797 Buffer
: String_Access
:= new String (1 .. Buffer_Initial
);
798 Buffer_Last
: Natural := 0;
800 procedure Put_Name_Buffer
;
801 -- Put the line contained in the Name_Buffer in the global buffer
804 (Project
: Project_Id
;
805 In_Tree
: Project_Tree_Ref
;
806 State
: in out Integer);
807 -- Generate the mapping file for Project (not recursively)
809 ---------------------
810 -- Put_Name_Buffer --
811 ---------------------
813 procedure Put_Name_Buffer
is
815 if Current_Verbosity
= High
then
816 Debug_Output
(Name_Buffer
(1 .. Name_Len
));
819 Name_Len
:= Name_Len
+ 1;
820 Name_Buffer
(Name_Len
) := ASCII
.LF
;
821 Add_To_Buffer
(Name_Buffer
(1 .. Name_Len
), Buffer
, Buffer_Last
);
829 (Project
: Project_Id
;
830 In_Tree
: Project_Tree_Ref
;
831 State
: in out Integer)
833 pragma Unreferenced
(State
);
836 Suffix
: File_Name_Type
;
837 Iter
: Source_Iterator
;
840 Debug_Output
("Add mapping for project", Project
.Name
);
841 Iter
:= For_Each_Source
(In_Tree
, Project
, Language
=> Language
);
844 Source
:= Prj
.Element
(Iter
);
845 exit when Source
= No_Source
;
847 if not Source
.Suppressed
848 and then Source
.Replaced_By
= No_Source
849 and then Source
.Path
.Name
/= No_Path
850 and then (Source
.Language
.Config
.Kind
= File_Based
851 or else Source
.Unit
/= No_Unit_Index
)
853 if Source
.Unit
/= No_Unit_Index
then
855 -- Put the encoded unit name in the name buffer
858 Uname
: constant String :=
859 Get_Name_String
(Source
.Unit
.Name
);
863 for J
in Uname
'Range loop
864 if Uname
(J
) in Upper_Half_Character
then
865 Store_Encoded_Character
(Get_Char_Code
(Uname
(J
)));
867 Add_Char_To_Name_Buffer
(Uname
(J
));
872 if Source
.Language
.Config
.Kind
= Unit_Based
then
874 -- ??? Mapping_Spec_Suffix could be set in the case of
877 Add_Char_To_Name_Buffer
('%');
879 if Source
.Kind
= Spec
then
880 Add_Char_To_Name_Buffer
('s');
882 Add_Char_To_Name_Buffer
('b');
889 Source
.Language
.Config
.Mapping_Spec_Suffix
;
892 Source
.Language
.Config
.Mapping_Body_Suffix
;
895 if Suffix
/= No_File
then
896 Add_Str_To_Name_Buffer
(Get_Name_String
(Suffix
));
903 Get_Name_String
(Source
.Display_File
);
906 if Source
.Locally_Removed
then
908 Name_Buffer
(1) := '/';
910 Get_Name_String
(Source
.Path
.Display_Name
);
920 procedure For_Every_Imported_Project
is new
921 For_Every_Project_Imported
(State
=> Integer, Action
=> Process
);
925 Dummy
: Integer := 0;
927 -- Start of processing for Create_Mapping_File
930 if Current_Verbosity
= High
then
931 Debug_Output
("Create mapping file for", Debug_Name
(In_Tree
));
934 Create_Temp_File
(In_Tree
.Shared
, File
, Name
, "mapping");
936 if Current_Verbosity
= High
then
937 Debug_Increase_Indent
("Create mapping file ", Name_Id
(Name
));
940 For_Every_Imported_Project
941 (Project
, In_Tree
, Dummy
, Include_Aggregated
=> False);
945 Status
: Boolean := False;
948 if File
/= Invalid_FD
then
949 Last
:= Write
(File
, Buffer
(1)'Address, Buffer_Last
);
951 if Last
= Buffer_Last
then
952 GNAT
.OS_Lib
.Close
(File
, Status
);
957 Prj
.Com
.Fail
("could not write mapping file");
963 Debug_Decrease_Indent
("Done create mapping file");
964 end Create_Mapping_File
;
966 ----------------------
967 -- Create_Temp_File --
968 ----------------------
970 procedure Create_Temp_File
971 (Shared
: Shared_Project_Tree_Data_Access
;
972 Path_FD
: out File_Descriptor
;
973 Path_Name
: out Path_Name_Type
;
977 Tempdir
.Create_Temp_File
(Path_FD
, Path_Name
);
979 if Path_Name
/= No_Path
then
980 if Current_Verbosity
= High
then
981 Write_Line
("Create temp file (" & File_Use
& ") "
982 & Get_Name_String
(Path_Name
));
985 Record_Temp_File
(Shared
, Path_Name
);
989 ("unable to create temporary " & File_Use
& " file");
991 end Create_Temp_File
;
993 --------------------------
994 -- Create_New_Path_File --
995 --------------------------
997 procedure Create_New_Path_File
998 (Shared
: Shared_Project_Tree_Data_Access
;
999 Path_FD
: out File_Descriptor
;
1000 Path_Name
: out Path_Name_Type
)
1003 Create_Temp_File
(Shared
, Path_FD
, Path_Name
, "path file");
1004 end Create_New_Path_File
;
1006 ------------------------------------
1007 -- File_Name_Of_Library_Unit_Body --
1008 ------------------------------------
1010 function File_Name_Of_Library_Unit_Body
1012 Project
: Project_Id
;
1013 In_Tree
: Project_Tree_Ref
;
1014 Main_Project_Only
: Boolean := True;
1015 Full_Path
: Boolean := False) return String
1018 Lang
: constant Language_Ptr
:=
1019 Get_Language_From_Name
(Project
, "ada");
1020 The_Project
: Project_Id
:= Project
;
1021 Original_Name
: String := Name
;
1024 The_Original_Name
: Name_Id
;
1025 The_Spec_Name
: Name_Id
;
1026 The_Body_Name
: Name_Id
;
1029 -- ??? Same block in Project_Of
1030 Canonical_Case_File_Name
(Original_Name
);
1031 Name_Len
:= Original_Name
'Length;
1032 Name_Buffer
(1 .. Name_Len
) := Original_Name
;
1033 The_Original_Name
:= Name_Find
;
1035 if Lang
/= null then
1037 Naming
: constant Lang_Naming_Data
:= Lang
.Config
.Naming_Data
;
1038 Extended_Spec_Name
: String :=
1039 Name
& Namet
.Get_Name_String
1040 (Naming
.Spec_Suffix
);
1041 Extended_Body_Name
: String :=
1042 Name
& Namet
.Get_Name_String
1043 (Naming
.Body_Suffix
);
1046 Canonical_Case_File_Name
(Extended_Spec_Name
);
1047 Name_Len
:= Extended_Spec_Name
'Length;
1048 Name_Buffer
(1 .. Name_Len
) := Extended_Spec_Name
;
1049 The_Spec_Name
:= Name_Find
;
1051 Canonical_Case_File_Name
(Extended_Body_Name
);
1052 Name_Len
:= Extended_Body_Name
'Length;
1053 Name_Buffer
(1 .. Name_Len
) := Extended_Body_Name
;
1054 The_Body_Name
:= Name_Find
;
1058 Name_Len
:= Name
'Length;
1059 Name_Buffer
(1 .. Name_Len
) := Name
;
1060 Canonical_Case_File_Name
(Name_Buffer
);
1061 The_Spec_Name
:= Name_Find
;
1062 The_Body_Name
:= The_Spec_Name
;
1065 if Current_Verbosity
= High
then
1066 Write_Str
("Looking for file name of """);
1070 Write_Str
(" Extended Spec Name = """);
1071 Write_Str
(Get_Name_String
(The_Spec_Name
));
1074 Write_Str
(" Extended Body Name = """);
1075 Write_Str
(Get_Name_String
(The_Body_Name
));
1080 -- For extending project, search in the extended project if the source
1081 -- is not found. For non extending projects, this loop will be run only
1085 -- Loop through units
1087 Unit
:= Units_Htable
.Get_First
(In_Tree
.Units_HT
);
1088 while Unit
/= null loop
1092 if not Main_Project_Only
1094 (Unit
.File_Names
(Impl
) /= null
1095 and then Unit
.File_Names
(Impl
).Project
= The_Project
)
1098 Current_Name
: File_Name_Type
;
1101 -- Case of a body present
1103 if Unit
.File_Names
(Impl
) /= null then
1104 Current_Name
:= Unit
.File_Names
(Impl
).File
;
1106 if Current_Verbosity
= High
then
1107 Write_Str
(" Comparing with """);
1108 Write_Str
(Get_Name_String
(Current_Name
));
1113 -- If it has the name of the original name, return the
1116 if Unit
.Name
= The_Original_Name
1118 Current_Name
= File_Name_Type
(The_Original_Name
)
1120 if Current_Verbosity
= High
then
1125 return Get_Name_String
1126 (Unit
.File_Names
(Impl
).Path
.Name
);
1129 return Get_Name_String
(Current_Name
);
1132 -- If it has the name of the extended body name,
1133 -- return the extended body name
1135 elsif Current_Name
= File_Name_Type
(The_Body_Name
) then
1136 if Current_Verbosity
= High
then
1141 return Get_Name_String
1142 (Unit
.File_Names
(Impl
).Path
.Name
);
1145 return Get_Name_String
(The_Body_Name
);
1149 if Current_Verbosity
= High
then
1150 Write_Line
(" not good");
1159 if not Main_Project_Only
1160 or else (Unit
.File_Names
(Spec
) /= null
1161 and then Unit
.File_Names
(Spec
).Project
= The_Project
)
1164 Current_Name
: File_Name_Type
;
1167 -- Case of spec present
1169 if Unit
.File_Names
(Spec
) /= null then
1170 Current_Name
:= Unit
.File_Names
(Spec
).File
;
1171 if Current_Verbosity
= High
then
1172 Write_Str
(" Comparing with """);
1173 Write_Str
(Get_Name_String
(Current_Name
));
1178 -- If name same as original name, return original name
1180 if Unit
.Name
= The_Original_Name
1182 Current_Name
= File_Name_Type
(The_Original_Name
)
1184 if Current_Verbosity
= High
then
1189 return Get_Name_String
1190 (Unit
.File_Names
(Spec
).Path
.Name
);
1192 return Get_Name_String
(Current_Name
);
1195 -- If it has the same name as the extended spec name,
1196 -- return the extended spec name.
1198 elsif Current_Name
= File_Name_Type
(The_Spec_Name
) then
1199 if Current_Verbosity
= High
then
1204 return Get_Name_String
1205 (Unit
.File_Names
(Spec
).Path
.Name
);
1207 return Get_Name_String
(The_Spec_Name
);
1211 if Current_Verbosity
= High
then
1212 Write_Line
(" not good");
1219 Unit
:= Units_Htable
.Get_Next
(In_Tree
.Units_HT
);
1222 -- If we are not in an extending project, give up
1224 exit when not Main_Project_Only
1225 or else The_Project
.Extends
= No_Project
;
1227 -- Otherwise, look in the project we are extending
1229 The_Project
:= The_Project
.Extends
;
1232 -- We don't know this file name, return an empty string
1235 end File_Name_Of_Library_Unit_Body
;
1237 -------------------------
1238 -- For_All_Object_Dirs --
1239 -------------------------
1241 procedure For_All_Object_Dirs
1242 (Project
: Project_Id
;
1243 Tree
: Project_Tree_Ref
)
1245 procedure For_Project
1247 Tree
: Project_Tree_Ref
;
1248 Dummy
: in out Integer);
1249 -- Get all object directories of Prj
1255 procedure For_Project
1257 Tree
: Project_Tree_Ref
;
1258 Dummy
: in out Integer)
1260 pragma Unreferenced
(Tree
);
1263 -- ??? Set_Ada_Paths has a different behavior for library project
1264 -- files, should we have the same ?
1266 if Prj
.Object_Directory
/= No_Path_Information
then
1267 Get_Name_String
(Prj
.Object_Directory
.Display_Name
);
1268 Action
(Name_Buffer
(1 .. Name_Len
));
1272 procedure Get_Object_Dirs
is
1273 new For_Every_Project_Imported
(Integer, For_Project
);
1274 Dummy
: Integer := 1;
1276 -- Start of processing for For_All_Object_Dirs
1279 Get_Object_Dirs
(Project
, Tree
, Dummy
);
1280 end For_All_Object_Dirs
;
1282 -------------------------
1283 -- For_All_Source_Dirs --
1284 -------------------------
1286 procedure For_All_Source_Dirs
1287 (Project
: Project_Id
;
1288 In_Tree
: Project_Tree_Ref
)
1290 procedure For_Project
1292 In_Tree
: Project_Tree_Ref
;
1293 Dummy
: in out Integer);
1294 -- Get all object directories of Prj
1300 procedure For_Project
1302 In_Tree
: Project_Tree_Ref
;
1303 Dummy
: in out Integer)
1305 Current
: String_List_Id
:= Prj
.Source_Dirs
;
1306 The_String
: String_Element
;
1309 -- If there are Ada sources, call action with the name of every
1310 -- source directory.
1312 if Has_Ada_Sources
(Prj
) then
1313 while Current
/= Nil_String
loop
1314 The_String
:= In_Tree
.Shared
.String_Elements
.Table
(Current
);
1315 Action
(Get_Name_String
(The_String
.Display_Value
));
1316 Current
:= The_String
.Next
;
1321 procedure Get_Source_Dirs
is
1322 new For_Every_Project_Imported
(Integer, For_Project
);
1323 Dummy
: Integer := 1;
1325 -- Start of processing for For_All_Source_Dirs
1328 Get_Source_Dirs
(Project
, In_Tree
, Dummy
);
1329 end For_All_Source_Dirs
;
1335 procedure Get_Reference
1336 (Source_File_Name
: String;
1337 In_Tree
: Project_Tree_Ref
;
1338 Project
: out Project_Id
;
1339 Path
: out Path_Name_Type
)
1342 -- Body below could use some comments ???
1344 if Current_Verbosity
> Default
then
1345 Write_Str
("Getting Reference_Of (""");
1346 Write_Str
(Source_File_Name
);
1347 Write_Str
(""") ... ");
1351 Original_Name
: String := Source_File_Name
;
1355 Canonical_Case_File_Name
(Original_Name
);
1356 Unit
:= Units_Htable
.Get_First
(In_Tree
.Units_HT
);
1358 while Unit
/= null loop
1359 if Unit
.File_Names
(Spec
) /= null
1360 and then not Unit
.File_Names
(Spec
).Locally_Removed
1361 and then Unit
.File_Names
(Spec
).File
/= No_File
1363 (Namet
.Get_Name_String
1364 (Unit
.File_Names
(Spec
).File
) = Original_Name
1365 or else (Unit
.File_Names
(Spec
).Path
/= No_Path_Information
1367 Namet
.Get_Name_String
1368 (Unit
.File_Names
(Spec
).Path
.Name
) =
1372 Ultimate_Extending_Project_Of
1373 (Unit
.File_Names
(Spec
).Project
);
1374 Path
:= Unit
.File_Names
(Spec
).Path
.Display_Name
;
1376 if Current_Verbosity
> Default
then
1377 Write_Str
("Done: Spec.");
1383 elsif Unit
.File_Names
(Impl
) /= null
1384 and then Unit
.File_Names
(Impl
).File
/= No_File
1385 and then not Unit
.File_Names
(Impl
).Locally_Removed
1387 (Namet
.Get_Name_String
1388 (Unit
.File_Names
(Impl
).File
) = Original_Name
1389 or else (Unit
.File_Names
(Impl
).Path
/= No_Path_Information
1390 and then Namet
.Get_Name_String
1391 (Unit
.File_Names
(Impl
).Path
.Name
) =
1395 Ultimate_Extending_Project_Of
1396 (Unit
.File_Names
(Impl
).Project
);
1397 Path
:= Unit
.File_Names
(Impl
).Path
.Display_Name
;
1399 if Current_Verbosity
> Default
then
1400 Write_Str
("Done: Body.");
1407 Unit
:= Units_Htable
.Get_Next
(In_Tree
.Units_HT
);
1411 Project
:= No_Project
;
1414 if Current_Verbosity
> Default
then
1415 Write_Str
("Cannot be found.");
1420 ----------------------
1421 -- Get_Runtime_Path --
1422 ----------------------
1424 function Get_Runtime_Path
1425 (Self
: Project_Search_Path
;
1426 Name
: String) return String_Access
1428 function Find_Rts_In_Path
is
1429 new Prj
.Env
.Find_Name_In_Path
(Check_Filename
=> Is_Directory
);
1431 return Find_Rts_In_Path
(Self
, Name
);
1432 end Get_Runtime_Path
;
1438 procedure Initialize
(In_Tree
: Project_Tree_Ref
) is
1440 In_Tree
.Shared
.Private_Part
.Current_Source_Path_File
:= No_Path
;
1441 In_Tree
.Shared
.Private_Part
.Current_Object_Path_File
:= No_Path
;
1448 -- Could use some comments in this body ???
1450 procedure Print_Sources
(In_Tree
: Project_Tree_Ref
) is
1454 Write_Line
("List of Sources:");
1456 Unit
:= Units_Htable
.Get_First
(In_Tree
.Units_HT
);
1457 while Unit
/= No_Unit_Index
loop
1459 Write_Line
(Namet
.Get_Name_String
(Unit
.Name
));
1461 if Unit
.File_Names
(Spec
).File
/= No_File
then
1462 if Unit
.File_Names
(Spec
).Project
= No_Project
then
1463 Write_Line
(" No project");
1466 Write_Str
(" Project: ");
1468 (Unit
.File_Names
(Spec
).Project
.Path
.Name
);
1469 Write_Line
(Name_Buffer
(1 .. Name_Len
));
1472 Write_Str
(" spec: ");
1474 (Namet
.Get_Name_String
1475 (Unit
.File_Names
(Spec
).File
));
1478 if Unit
.File_Names
(Impl
).File
/= No_File
then
1479 if Unit
.File_Names
(Impl
).Project
= No_Project
then
1480 Write_Line
(" No project");
1483 Write_Str
(" Project: ");
1485 (Unit
.File_Names
(Impl
).Project
.Path
.Name
);
1486 Write_Line
(Name_Buffer
(1 .. Name_Len
));
1489 Write_Str
(" body: ");
1491 (Namet
.Get_Name_String
(Unit
.File_Names
(Impl
).File
));
1494 Unit
:= Units_Htable
.Get_Next
(In_Tree
.Units_HT
);
1497 Write_Line
("end of List of Sources.");
1506 Main_Project
: Project_Id
;
1507 In_Tree
: Project_Tree_Ref
) return Project_Id
1509 Result
: Project_Id
:= No_Project
;
1511 Original_Name
: String := Name
;
1513 Lang
: constant Language_Ptr
:=
1514 Get_Language_From_Name
(Main_Project
, "ada");
1518 Current_Name
: File_Name_Type
;
1519 The_Original_Name
: File_Name_Type
;
1520 The_Spec_Name
: File_Name_Type
;
1521 The_Body_Name
: File_Name_Type
;
1524 -- ??? Same block in File_Name_Of_Library_Unit_Body
1525 Canonical_Case_File_Name
(Original_Name
);
1526 Name_Len
:= Original_Name
'Length;
1527 Name_Buffer
(1 .. Name_Len
) := Original_Name
;
1528 The_Original_Name
:= Name_Find
;
1530 if Lang
/= null then
1532 Naming
: Lang_Naming_Data
renames Lang
.Config
.Naming_Data
;
1533 Extended_Spec_Name
: String :=
1534 Name
& Namet
.Get_Name_String
1535 (Naming
.Spec_Suffix
);
1536 Extended_Body_Name
: String :=
1537 Name
& Namet
.Get_Name_String
1538 (Naming
.Body_Suffix
);
1541 Canonical_Case_File_Name
(Extended_Spec_Name
);
1542 Name_Len
:= Extended_Spec_Name
'Length;
1543 Name_Buffer
(1 .. Name_Len
) := Extended_Spec_Name
;
1544 The_Spec_Name
:= Name_Find
;
1546 Canonical_Case_File_Name
(Extended_Body_Name
);
1547 Name_Len
:= Extended_Body_Name
'Length;
1548 Name_Buffer
(1 .. Name_Len
) := Extended_Body_Name
;
1549 The_Body_Name
:= Name_Find
;
1553 The_Spec_Name
:= The_Original_Name
;
1554 The_Body_Name
:= The_Original_Name
;
1557 Unit
:= Units_Htable
.Get_First
(In_Tree
.Units_HT
);
1558 while Unit
/= null loop
1560 -- Case of a body present
1562 if Unit
.File_Names
(Impl
) /= null then
1563 Current_Name
:= Unit
.File_Names
(Impl
).File
;
1565 -- If it has the name of the original name or the body name,
1566 -- we have found the project.
1568 if Unit
.Name
= Name_Id
(The_Original_Name
)
1569 or else Current_Name
= The_Original_Name
1570 or else Current_Name
= The_Body_Name
1572 Result
:= Unit
.File_Names
(Impl
).Project
;
1579 if Unit
.File_Names
(Spec
) /= null then
1580 Current_Name
:= Unit
.File_Names
(Spec
).File
;
1582 -- If name same as the original name, or the spec name, we have
1583 -- found the project.
1585 if Unit
.Name
= Name_Id
(The_Original_Name
)
1586 or else Current_Name
= The_Original_Name
1587 or else Current_Name
= The_Spec_Name
1589 Result
:= Unit
.File_Names
(Spec
).Project
;
1594 Unit
:= Units_Htable
.Get_Next
(In_Tree
.Units_HT
);
1597 return Ultimate_Extending_Project_Of
(Result
);
1604 procedure Set_Ada_Paths
1605 (Project
: Project_Id
;
1606 In_Tree
: Project_Tree_Ref
;
1607 Including_Libraries
: Boolean;
1608 Include_Path
: Boolean := True;
1609 Objects_Path
: Boolean := True)
1612 Shared
: constant Shared_Project_Tree_Data_Access
:= In_Tree
.Shared
;
1614 Source_Paths
: Source_Path_Table
.Instance
;
1615 Object_Paths
: Object_Path_Table
.Instance
;
1616 -- List of source or object dirs. Only computed the first time this
1617 -- procedure is called (since Source_FD is then reused)
1619 Source_FD
: File_Descriptor
:= Invalid_FD
;
1620 Object_FD
: File_Descriptor
:= Invalid_FD
;
1621 -- The temporary files to store the paths. These are only created the
1622 -- first time this procedure is called, and reused from then on.
1624 Process_Source_Dirs
: Boolean := False;
1625 Process_Object_Dirs
: Boolean := False;
1628 -- For calls to Close
1631 Buffer
: String_Access
:= new String (1 .. Buffer_Initial
);
1632 Buffer_Last
: Natural := 0;
1634 procedure Recursive_Add
1635 (Project
: Project_Id
;
1636 In_Tree
: Project_Tree_Ref
;
1637 Dummy
: in out Boolean);
1638 -- Recursive procedure to add the source/object paths of extended/
1639 -- imported projects.
1645 procedure Recursive_Add
1646 (Project
: Project_Id
;
1647 In_Tree
: Project_Tree_Ref
;
1648 Dummy
: in out Boolean)
1650 pragma Unreferenced
(In_Tree
);
1652 Path
: Path_Name_Type
;
1655 if Process_Source_Dirs
then
1657 -- Add to path all source directories of this project if there are
1660 if Has_Ada_Sources
(Project
) then
1661 Add_To_Source_Path
(Project
.Source_Dirs
, Shared
, Source_Paths
);
1665 if Process_Object_Dirs
then
1666 Path
:= Get_Object_Directory
1668 Including_Libraries
=> Including_Libraries
,
1669 Only_If_Ada
=> True);
1671 if Path
/= No_Path
then
1672 Add_To_Object_Path
(Path
, Object_Paths
);
1677 procedure For_All_Projects
is
1678 new For_Every_Project_Imported
(Boolean, Recursive_Add
);
1680 Dummy
: Boolean := False;
1682 -- Start of processing for Set_Ada_Paths
1685 -- If it is the first time we call this procedure for this project,
1686 -- compute the source path and/or the object path.
1688 if Include_Path
and then Project
.Include_Path_File
= No_Path
then
1689 Source_Path_Table
.Init
(Source_Paths
);
1690 Process_Source_Dirs
:= True;
1691 Create_New_Path_File
(Shared
, Source_FD
, Project
.Include_Path_File
);
1694 -- For the object path, we make a distinction depending on
1695 -- Including_Libraries.
1697 if Objects_Path
and Including_Libraries
then
1698 if Project
.Objects_Path_File_With_Libs
= No_Path
then
1699 Object_Path_Table
.Init
(Object_Paths
);
1700 Process_Object_Dirs
:= True;
1701 Create_New_Path_File
1702 (Shared
, Object_FD
, Project
.Objects_Path_File_With_Libs
);
1705 elsif Objects_Path
then
1706 if Project
.Objects_Path_File_Without_Libs
= No_Path
then
1707 Object_Path_Table
.Init
(Object_Paths
);
1708 Process_Object_Dirs
:= True;
1709 Create_New_Path_File
1710 (Shared
, Object_FD
, Project
.Objects_Path_File_Without_Libs
);
1714 -- If there is something to do, set Seen to False for all projects,
1715 -- then call the recursive procedure Add for Project.
1717 if Process_Source_Dirs
or Process_Object_Dirs
then
1718 For_All_Projects
(Project
, In_Tree
, Dummy
);
1721 -- Write and close any file that has been created. Source_FD is not set
1722 -- when this subprogram is called a second time or more, since we reuse
1723 -- the previous version of the file.
1725 if Source_FD
/= Invalid_FD
then
1729 Source_Path_Table
.First
.. Source_Path_Table
.Last
(Source_Paths
)
1731 Get_Name_String
(Source_Paths
.Table
(Index
));
1732 Name_Len
:= Name_Len
+ 1;
1733 Name_Buffer
(Name_Len
) := ASCII
.LF
;
1734 Add_To_Buffer
(Name_Buffer
(1 .. Name_Len
), Buffer
, Buffer_Last
);
1737 Last
:= Write
(Source_FD
, Buffer
(1)'Address, Buffer_Last
);
1739 if Last
= Buffer_Last
then
1740 Close
(Source_FD
, Status
);
1747 Prj
.Com
.Fail
("could not write temporary file");
1751 if Object_FD
/= Invalid_FD
then
1755 Object_Path_Table
.First
.. Object_Path_Table
.Last
(Object_Paths
)
1757 Get_Name_String
(Object_Paths
.Table
(Index
));
1758 Name_Len
:= Name_Len
+ 1;
1759 Name_Buffer
(Name_Len
) := ASCII
.LF
;
1760 Add_To_Buffer
(Name_Buffer
(1 .. Name_Len
), Buffer
, Buffer_Last
);
1763 Last
:= Write
(Object_FD
, Buffer
(1)'Address, Buffer_Last
);
1765 if Last
= Buffer_Last
then
1766 Close
(Object_FD
, Status
);
1772 Prj
.Com
.Fail
("could not write temporary file");
1776 -- Set the env vars, if they need to be changed, and set the
1777 -- corresponding flags.
1781 Shared
.Private_Part
.Current_Source_Path_File
/=
1782 Project
.Include_Path_File
1784 Shared
.Private_Part
.Current_Source_Path_File
:=
1785 Project
.Include_Path_File
;
1787 (Project_Include_Path_File
,
1788 Get_Name_String
(Shared
.Private_Part
.Current_Source_Path_File
));
1791 if Objects_Path
then
1792 if Including_Libraries
then
1793 if Shared
.Private_Part
.Current_Object_Path_File
/=
1794 Project
.Objects_Path_File_With_Libs
1796 Shared
.Private_Part
.Current_Object_Path_File
:=
1797 Project
.Objects_Path_File_With_Libs
;
1799 (Project_Objects_Path_File
,
1801 (Shared
.Private_Part
.Current_Object_Path_File
));
1805 if Shared
.Private_Part
.Current_Object_Path_File
/=
1806 Project
.Objects_Path_File_Without_Libs
1808 Shared
.Private_Part
.Current_Object_Path_File
:=
1809 Project
.Objects_Path_File_Without_Libs
;
1811 (Project_Objects_Path_File
,
1813 (Shared
.Private_Part
.Current_Object_Path_File
));
1821 ---------------------
1822 -- Add_Directories --
1823 ---------------------
1825 procedure Add_Directories
1826 (Self
: in out Project_Search_Path
;
1828 Prepend
: Boolean := False)
1830 Tmp
: String_Access
;
1832 if Self
.Path
= null then
1833 Self
.Path
:= new String'(Uninitialized_Prefix & Path);
1837 Self.Path := new String'(Path
& Path_Separator
& Tmp
.all);
1839 Self
.Path
:= new String'(Tmp.all & Path_Separator & Path);
1844 if Current_Verbosity = High then
1845 Debug_Output ("Adding directories to Project_Path: """
1848 end Add_Directories;
1850 --------------------
1851 -- Is_Initialized --
1852 --------------------
1854 function Is_Initialized (Self : Project_Search_Path) return Boolean is
1856 return Self.Path /= null
1857 and then (Self.Path'Length = 0
1858 or else Self.Path (Self.Path'First) /= '#');
1861 ----------------------
1862 -- Initialize_Empty --
1863 ----------------------
1865 procedure Initialize_Empty (Self : in out Project_Search_Path) is
1868 Self.Path := new String'("");
1869 end Initialize_Empty;
1871 -------------------------------------
1872 -- Initialize_Default_Project_Path --
1873 -------------------------------------
1875 procedure Initialize_Default_Project_Path
1876 (Self : in out Project_Search_Path;
1877 Target_Name : String;
1878 Runtime_Name : String := "")
1880 Add_Default_Dir : Boolean := Target_Name /= "-";
1884 Ada_Project_Path : constant String := "ADA_PROJECT_PATH
";
1885 Gpr_Project_Path : constant String := "GPR_PROJECT_PATH
";
1886 Gpr_Project_Path_File : constant String := "GPR_PROJECT_PATH_FILE
";
1887 -- Names of alternate env. variable that contain path name(s) of
1888 -- directories where project files may reside. They are taken into
1889 -- account in this order: GPR_PROJECT_PATH_FILE, GPR_PROJECT_PATH,
1890 -- ADA_PROJECT_PATH.
1892 Gpr_Prj_Path_File : String_Access;
1893 Gpr_Prj_Path : String_Access;
1894 Ada_Prj_Path : String_Access;
1895 -- The path name(s) of directories where project files may reside.
1898 Prefix : String_Ptr;
1899 Runtime : String_Ptr;
1901 procedure Add_Target;
1902 -- Add :<prefix>/<target> to the project path
1908 procedure Add_Target is
1910 Add_Str_To_Name_Buffer
1911 (Path_Separator & Prefix.all & Target_Name);
1913 -- Note: Target_Name has a trailing / when it comes from Sdefault
1915 if Name_Buffer (Name_Len) /= '/' then
1916 Add_Char_To_Name_Buffer (Directory_Separator);
1920 -- Start of processing for Initialize_Default_Project_Path
1923 if Is_Initialized (Self) then
1927 -- The current directory is always first in the search path. Since the
1928 -- Project_Path currently starts with '#:' as a sign that it isn't
1929 -- initialized, we simply replace '#' with '.'
1931 if Self.Path = null then
1932 Self.Path := new String'('.' & Path_Separator);
1934 Self.Path (Self.Path'First) := '.';
1937 -- Then the reset of the project path (if any) currently contains the
1938 -- directories added through Add_Search_Project_Directory
1940 -- If environment variables are defined and not empty, add their content
1942 Gpr_Prj_Path_File := Getenv (Gpr_Project_Path_File);
1943 Gpr_Prj_Path := Getenv (Gpr_Project_Path);
1944 Ada_Prj_Path := Getenv (Ada_Project_Path);
1946 if Gpr_Prj_Path_File.all /= "" then
1948 File : Ada.Text_IO.File_Type;
1949 Line : String (1 .. 10_000);
1952 Tmp : String_Access;
1955 Open (File, In_File, Gpr_Prj_Path_File.all);
1957 while not End_Of_File (File) loop
1958 Get_Line (File, Line, Last);
1961 and then (Last = 1 or else Line (1 .. 2) /= "--")
1966 (Tmp.all & Path_Separator & Line (1 .. Last));
1970 if Current_Verbosity = High then
1971 Debug_Output ("Adding directory to Project_Path: """
1972 & Line (1 .. Last) & '"');
1980 Write_Str ("warning
: could
not read project path file
""");
1981 Write_Str (Gpr_Prj_Path_File.all);
1987 if Gpr_Prj_Path.all /= "" then
1988 Add_Directories (Self, Gpr_Prj_Path.all);
1991 Free (Gpr_Prj_Path);
1993 if Ada_Prj_Path.all /= "" then
1994 Add_Directories (Self, Ada_Prj_Path.all);
1997 Free (Ada_Prj_Path);
1999 -- Copy to Name_Buffer, since we will need to manipulate the path
2001 Name_Len := Self.Path'Length;
2002 Name_Buffer (1 .. Name_Len) := Self.Path.all;
2004 -- Scan the directory path to see if "-" is one of the directories.
2005 -- Remove each occurrence of "-" and set Add_Default_Dir to False.
2006 -- Also resolve relative paths and symbolic links.
2010 while First <= Name_Len
2011 and then (Name_Buffer (First) = Path_Separator)
2016 exit when First > Name_Len;
2020 while Last < Name_Len
2021 and then Name_Buffer (Last + 1) /= Path_Separator
2026 -- If the directory is "-", set Add_Default_Dir to False and
2027 -- remove from path.
2029 if Name_Buffer (First .. Last) = No_Project_Default_Dir then
2030 Add_Default_Dir := False;
2032 for J in Last + 1 .. Name_Len loop
2033 Name_Buffer (J - No_Project_Default_Dir'Length - 1) :=
2037 Name_Len := Name_Len - No_Project_Default_Dir'Length - 1;
2039 -- After removing the '-', go back one character to get the next
2040 -- directory correctly.
2046 New_Dir : constant String :=
2048 (Name_Buffer (First .. Last),
2049 Resolve_Links => Opt.Follow_Links_For_Dirs);
2051 New_Last : Positive;
2054 -- If the absolute path was resolved and is different from
2055 -- the original, replace original with the resolved path.
2057 if New_Dir /= Name_Buffer (First .. Last)
2058 and then New_Dir'Length /= 0
2060 New_Len := Name_Len + New_Dir'Length - (Last - First + 1);
2061 New_Last := First + New_Dir'Length - 1;
2062 Name_Buffer (New_Last + 1 .. New_Len) :=
2063 Name_Buffer (Last + 1 .. Name_Len);
2064 Name_Buffer (First .. New_Last) := New_Dir;
2065 Name_Len := New_Len;
2076 -- Set the initial value of Current_Project_Path
2078 if Add_Default_Dir then
2079 if Sdefault.Search_Dir_Prefix = null then
2083 Prefix := new String'(Executable_Prefix_Path);
2086 Prefix := new String'(Sdefault.Search_Dir_Prefix.all
2087 & ".." & Dir_Separator
2088 & ".." & Dir_Separator
2089 & ".." & Dir_Separator
2090 & ".." & Dir_Separator);
2093 if Prefix.all /= "" then
2094 if Target_Name /= "" then
2096 if Runtime_Name /= "" then
2097 if Base_Name (Runtime_Name) = Runtime_Name then
2099 -- $prefix/$target/$runtime/lib/gnat
2101 Add_Str_To_Name_Buffer
2102 (Runtime_Name & Directory_Separator &
2103 "lib
" & Directory_Separator & "gnat
");
2105 -- $prefix/$target/$runtime/share/gpr
2107 Add_Str_To_Name_Buffer
2108 (Runtime_Name & Directory_Separator &
2109 "share
" & Directory_Separator & "gpr
");
2113 new String'(Normalize_Pathname (Runtime_Name));
2115 -- $runtime_dir/lib/gnat
2116 Add_Str_To_Name_Buffer
2117 (Path_Separator & Runtime.all & Directory_Separator &
2118 "lib
" & Directory_Separator & "gnat
");
2120 -- $runtime_dir/share/gpr
2121 Add_Str_To_Name_Buffer
2122 (Path_Separator & Runtime.all & Directory_Separator &
2123 "share
" & Directory_Separator & "gpr
");
2127 -- $prefix/$target/lib/gnat
2130 Add_Str_To_Name_Buffer
2131 ("lib
" & Directory_Separator & "gnat
");
2133 -- $prefix/$target/share/gpr
2136 Add_Str_To_Name_Buffer
2137 ("share
" & Directory_Separator & "gpr
");
2140 -- $prefix/share/gpr
2142 Add_Str_To_Name_Buffer
2143 (Path_Separator & Prefix.all & "share
"
2144 & Directory_Separator & "gpr
");
2148 Add_Str_To_Name_Buffer
2149 (Path_Separator & Prefix.all & "lib
"
2150 & Directory_Separator & "gnat
");
2156 Self.Path := new String'(Name_Buffer (1 .. Name_Len));
2157 end Initialize_Default_Project_Path;
2163 procedure Get_Path (Self : Project_Search_Path; Path : out String_Access) is
2165 pragma Assert (Is_Initialized (Self));
2173 procedure Set_Path (Self : in out Project_Search_Path; Path : String) is
2176 Self.Path := new String'(Path);
2177 Projects_Paths.Reset (Self.Cache);
2180 -----------------------
2181 -- Find_Name_In_Path --
2182 -----------------------
2184 function Find_Name_In_Path
2185 (Self : Project_Search_Path;
2186 Path : String) return String_Access
2192 if Current_Verbosity = High then
2193 Debug_Output ("Trying
" & Path);
2196 if Is_Absolute_Path (Path) then
2197 if Check_Filename (Path) then
2198 return new String'(Path);
2204 -- Because we don't want to resolve symbolic links, we cannot use
2205 -- Locate_Regular_File. So, we try each possible path successively.
2207 First := Self.Path'First;
2208 while First <= Self.Path'Last loop
2209 while First <= Self.Path'Last
2210 and then Self.Path (First) = Path_Separator
2215 exit when First > Self.Path'Last;
2218 while Last < Self.Path'Last
2219 and then Self.Path (Last + 1) /= Path_Separator
2226 if not Is_Absolute_Path (Self.Path (First .. Last)) then
2227 Add_Str_To_Name_Buffer (Get_Current_Dir); -- ??? System call
2228 Add_Char_To_Name_Buffer (Directory_Separator);
2231 Add_Str_To_Name_Buffer (Self.Path (First .. Last));
2232 Add_Char_To_Name_Buffer (Directory_Separator);
2233 Add_Str_To_Name_Buffer (Path);
2235 if Current_Verbosity = High then
2236 Debug_Output ("Testing file
" & Name_Buffer (1 .. Name_Len));
2239 if Check_Filename (Name_Buffer (1 .. Name_Len)) then
2240 return new String'(Name_Buffer (1 .. Name_Len));
2248 end Find_Name_In_Path;
2254 procedure Find_Project
2255 (Self : in out Project_Search_Path;
2256 Project_File_Name : String;
2258 Path : out Namet.Path_Name_Type)
2260 Result : String_Access;
2261 Has_Dot : Boolean := False;
2264 File : constant String := Project_File_Name;
2265 -- Have to do a copy, in case the parameter is Name_Buffer, which we
2268 Cached_Path : Namet.Path_Name_Type;
2269 -- This should be commented rather than making us guess from the name???
2271 function Try_Path_Name is new
2272 Find_Name_In_Path (Check_Filename => Is_Regular_File);
2273 -- Find a file in the project search path
2275 -- Start of processing for Find_Project
2278 pragma Assert (Is_Initialized (Self));
2280 if Current_Verbosity = High then
2281 Debug_Increase_Indent
2282 ("Searching
for project
""" & File & """ in """
2286 -- Check the project cache
2288 Name_Len := File'Length;
2289 Name_Buffer (1 .. Name_Len) := File;
2291 Cached_Path := Projects_Paths.Get (Self.Cache, Key);
2293 -- Check if File contains an extension (a dot before a
2294 -- directory separator). If it is the case we do not try project file
2295 -- with an added extension as it is not possible to have multiple dots
2296 -- on a project file name.
2298 Check_Dot : for K in reverse File'Range loop
2299 if File (K) = '.' then
2304 exit Check_Dot when Is_Directory_Separator (File (K));
2307 if not Is_Absolute_Path (File) then
2309 -- If we have found project in the cache, check if in the directory
2311 if Cached_Path /= No_Path then
2313 Cached : constant String := Get_Name_String (Cached_Path);
2317 GNAT.OS_Lib.Normalize_Pathname
2318 (File & Project_File_Extension,
2319 Directory => Directory,
2320 Resolve_Links => Opt.Follow_Links_For_Files,
2321 Case_Sensitive => True))
2324 GNAT.OS_Lib.Normalize_Pathname
2326 Directory => Directory,
2327 Resolve_Links => Opt.Follow_Links_For_Files,
2328 Case_Sensitive => True)
2330 Path := Cached_Path;
2331 Debug_Decrease_Indent;
2337 -- First we try <directory>/<file_name>.<extension>
2343 Directory & Directory_Separator
2344 & File & Project_File_Extension);
2347 -- Then we try <directory>/<file_name>
2349 if Result = null then
2351 Try_Path_Name (Self, Directory & Directory_Separator & File);
2355 -- If we found the path in the cache, this is the one
2357 if Result = null and then Cached_Path /= No_Path then
2358 Path := Cached_Path;
2359 Debug_Decrease_Indent;
2363 -- Then we try <file_name>.<extension>
2365 if Result = null and then not Has_Dot then
2366 Result := Try_Path_Name (Self, File & Project_File_Extension);
2369 -- Then we try <file_name>
2371 if Result = null then
2372 Result := Try_Path_Name (Self, File);
2375 -- If we cannot find the project file, we return an empty string
2377 if Result = null then
2378 Path := Namet.No_Path;
2383 Final_Result : constant String :=
2384 GNAT.OS_Lib.Normalize_Pathname
2386 Directory => Directory,
2387 Resolve_Links => Opt.Follow_Links_For_Files,
2388 Case_Sensitive => True);
2391 Name_Len := Final_Result'Length;
2392 Name_Buffer (1 .. Name_Len) := Final_Result;
2394 Projects_Paths.Set (Self.Cache, Key, Path);
2398 Debug_Decrease_Indent;
2405 procedure Free (Self : in out Project_Search_Path) is
2408 Projects_Paths.Reset (Self.Cache);
2415 procedure Copy (From : Project_Search_Path; To : out Project_Search_Path) is
2419 if From.Path /= null then
2420 To.Path := new String'(From
.Path
.all);
2423 -- No need to copy the Cache, it will be recomputed as needed