1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2001-2006, 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 2, 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 COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
22 -- GNAT was originally developed by the GNAT team at New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc. --
25 ------------------------------------------------------------------------------
27 with Err_Vars
; use Err_Vars
;
28 with Namet
; use Namet
;
30 with Osint
; use Osint
;
31 with Output
; use Output
;
32 with Prj
.Com
; use Prj
.Com
;
34 with Prj
.Err
; use Prj
.Err
;
35 with Prj
.Ext
; use Prj
.Ext
;
36 with Sinput
; use Sinput
;
37 with Sinput
.P
; use Sinput
.P
;
41 with Ada
.Characters
.Handling
; use Ada
.Characters
.Handling
;
42 with Ada
.Exceptions
; use Ada
.Exceptions
;
44 with GNAT
.Directory_Operations
; use GNAT
.Directory_Operations
;
46 with System
.HTable
; use System
.HTable
;
48 package body Prj
.Part
is
50 Buffer
: String_Access
;
51 Buffer_Last
: Natural := 0;
53 Dir_Sep
: Character renames GNAT
.OS_Lib
.Directory_Separator
;
55 type Extension_Origin
is (None
, Extending_Simple
, Extending_All
);
56 -- Type of parameter From_Extended for procedures Parse_Single_Project and
57 -- Post_Parse_Context_Clause. Extending_All means that we are parsing the
58 -- tree rooted at an extending all project.
60 ------------------------------------
61 -- Local Packages and Subprograms --
62 ------------------------------------
64 type With_Id
is new Nat
;
65 No_With
: constant With_Id
:= 0;
67 type With_Record
is record
69 Location
: Source_Ptr
;
70 Limited_With
: Boolean;
71 Node
: Project_Node_Id
;
74 -- Information about an imported project, to be put in table Withs below
76 package Withs
is new Table
.Table
77 (Table_Component_Type
=> With_Record
,
78 Table_Index_Type
=> With_Id
,
81 Table_Increment
=> 50,
82 Table_Name
=> "Prj.Part.Withs");
83 -- Table used to store temporarily paths and locations of imported
84 -- projects. These imported projects will be effectively parsed after the
85 -- name of the current project has been extablished.
87 type Names_And_Id
is record
89 Canonical_Path_Name
: Name_Id
;
93 package Project_Stack
is new Table
.Table
94 (Table_Component_Type
=> Names_And_Id
,
95 Table_Index_Type
=> Nat
,
98 Table_Increment
=> 50,
99 Table_Name
=> "Prj.Part.Project_Stack");
100 -- This table is used to detect circular dependencies
101 -- for imported and extended projects and to get the project ids of
102 -- limited imported projects when there is a circularity with at least
103 -- one limited imported project file.
105 package Virtual_Hash
is new System
.HTable
.Simple_HTable
106 (Header_Num
=> Header_Num
,
107 Element
=> Project_Node_Id
,
108 No_Element
=> Empty_Node
,
109 Key
=> Project_Node_Id
,
110 Hash
=> Prj
.Tree
.Hash
,
112 -- Hash table to store the node id of the project for which a virtual
113 -- extending project need to be created.
115 package Processed_Hash
is new System
.HTable
.Simple_HTable
116 (Header_Num
=> Header_Num
,
119 Key
=> Project_Node_Id
,
120 Hash
=> Prj
.Tree
.Hash
,
122 -- Hash table to store the project process when looking for project that
123 -- need to have a virtual extending project, to avoid processing the same
126 procedure Create_Virtual_Extending_Project
127 (For_Project
: Project_Node_Id
;
128 Main_Project
: Project_Node_Id
;
129 In_Tree
: Project_Node_Tree_Ref
);
130 -- Create a virtual extending project of For_Project. Main_Project is
131 -- the extending all project.
133 -- The String_Value_Of is not set for the automatically added with
134 -- clause and keeps the default value of No_Name. This enables Prj.PP
135 -- to skip these automatically added with clauses to be processed.
137 procedure Look_For_Virtual_Projects_For
138 (Proj
: Project_Node_Id
;
139 In_Tree
: Project_Node_Tree_Ref
;
140 Potentially_Virtual
: Boolean);
141 -- Look for projects that need to have a virtual extending project.
142 -- This procedure is recursive. If called with Potentially_Virtual set to
143 -- True, then Proj may need an virtual extending project; otherwise it
144 -- does not (because it is already extended), but other projects that it
145 -- imports may need to be virtually extended.
147 procedure Pre_Parse_Context_Clause
148 (In_Tree
: Project_Node_Tree_Ref
;
149 Context_Clause
: out With_Id
);
150 -- Parse the context clause of a project.
151 -- Store the paths and locations of the imported projects in table Withs.
152 -- Does nothing if there is no context clause (if the current
153 -- token is not "with" or "limited" followed by "with").
155 procedure Post_Parse_Context_Clause
156 (Context_Clause
: With_Id
;
157 In_Tree
: Project_Node_Tree_Ref
;
158 Imported_Projects
: out Project_Node_Id
;
159 Project_Directory
: Name_Id
;
160 From_Extended
: Extension_Origin
;
161 In_Limited
: Boolean;
162 Packages_To_Check
: String_List_Access
);
163 -- Parse the imported projects that have been stored in table Withs,
164 -- if any. From_Extended is used for the call to Parse_Single_Project
165 -- below. When In_Limited is True, the importing path includes at least
166 -- one "limited with".
168 procedure Parse_Single_Project
169 (In_Tree
: Project_Node_Tree_Ref
;
170 Project
: out Project_Node_Id
;
171 Extends_All
: out Boolean;
174 From_Extended
: Extension_Origin
;
175 In_Limited
: Boolean;
176 Packages_To_Check
: String_List_Access
);
177 -- Parse a project file.
178 -- Recursive procedure: it calls itself for imported and extended
179 -- projects. When From_Extended is not None, if the project has already
180 -- been parsed and is an extended project A, return the ultimate
181 -- (not extended) project that extends A. When In_Limited is True,
182 -- the importing path includes at least one "limited with".
184 function Project_Path_Name_Of
185 (Project_File_Name
: String;
186 Directory
: String) return String;
187 -- Returns the path name of a project file. Returns an empty string
188 -- if project file cannot be found.
190 function Immediate_Directory_Of
(Path_Name
: Name_Id
) return Name_Id
;
191 -- Get the directory of the file with the specified path name.
192 -- This includes the directory separator as the last character.
193 -- Returns "./" if Path_Name contains no directory separator.
195 function Project_Name_From
(Path_Name
: String) return Name_Id
;
196 -- Returns the name of the project that corresponds to its path name.
197 -- Returns No_Name if the path name is invalid, because the corresponding
198 -- project name does not have the syntax of an ada identifier.
200 --------------------------------------
201 -- Create_Virtual_Extending_Project --
202 --------------------------------------
204 procedure Create_Virtual_Extending_Project
205 (For_Project
: Project_Node_Id
;
206 Main_Project
: Project_Node_Id
;
207 In_Tree
: Project_Node_Tree_Ref
)
210 Virtual_Name
: constant String :=
212 Get_Name_String
(Name_Of
(For_Project
, In_Tree
));
213 -- The name of the virtual extending project
215 Virtual_Name_Id
: Name_Id
;
216 -- Virtual extending project name id
218 Virtual_Path_Id
: Name_Id
;
219 -- Fake path name of the virtual extending project. The directory is
220 -- the same directory as the extending all project.
222 Virtual_Dir_Id
: constant Name_Id
:=
223 Immediate_Directory_Of
(Path_Name_Of
(Main_Project
, In_Tree
));
224 -- The directory of the extending all project
226 -- The source of the virtual extending project is something like:
228 -- project V$<project name> extends <project path> is
230 -- for Source_Dirs use ();
232 -- end V$<project name>;
234 -- The project directory cannot be specified during parsing; it will be
235 -- put directly in the virtual extending project data during processing.
237 -- Nodes that made up the virtual extending project
239 Virtual_Project
: constant Project_Node_Id
:=
241 (In_Tree
, N_Project
);
242 With_Clause
: constant Project_Node_Id
:=
244 (In_Tree
, N_With_Clause
);
245 Project_Declaration
: constant Project_Node_Id
:=
247 (In_Tree
, N_Project_Declaration
);
248 Source_Dirs_Declaration
: constant Project_Node_Id
:=
250 (In_Tree
, N_Declarative_Item
);
251 Source_Dirs_Attribute
: constant Project_Node_Id
:=
253 (In_Tree
, N_Attribute_Declaration
, List
);
254 Source_Dirs_Expression
: constant Project_Node_Id
:=
256 (In_Tree
, N_Expression
, List
);
257 Source_Dirs_Term
: constant Project_Node_Id
:=
259 (In_Tree
, N_Term
, List
);
260 Source_Dirs_List
: constant Project_Node_Id
:=
262 (In_Tree
, N_Literal_String_List
, List
);
265 -- Get the virtual name id
267 Name_Len
:= Virtual_Name
'Length;
268 Name_Buffer
(1 .. Name_Len
) := Virtual_Name
;
269 Virtual_Name_Id
:= Name_Find
;
271 -- Get the virtual path name
273 Get_Name_String
(Path_Name_Of
(Main_Project
, In_Tree
));
276 and then Name_Buffer
(Name_Len
) /= Directory_Separator
277 and then Name_Buffer
(Name_Len
) /= '/'
279 Name_Len
:= Name_Len
- 1;
282 Name_Buffer
(Name_Len
+ 1 .. Name_Len
+ Virtual_Name
'Length) :=
284 Name_Len
:= Name_Len
+ Virtual_Name
'Length;
285 Virtual_Path_Id
:= Name_Find
;
289 Set_Name_Of
(With_Clause
, In_Tree
, Virtual_Name_Id
);
290 Set_Path_Name_Of
(With_Clause
, In_Tree
, Virtual_Path_Id
);
291 Set_Project_Node_Of
(With_Clause
, In_Tree
, Virtual_Project
);
292 Set_Next_With_Clause_Of
293 (With_Clause
, In_Tree
, First_With_Clause_Of
(Main_Project
, In_Tree
));
294 Set_First_With_Clause_Of
(Main_Project
, In_Tree
, With_Clause
);
296 -- Virtual project node
298 Set_Name_Of
(Virtual_Project
, In_Tree
, Virtual_Name_Id
);
299 Set_Path_Name_Of
(Virtual_Project
, In_Tree
, Virtual_Path_Id
);
301 (Virtual_Project
, In_Tree
, Location_Of
(Main_Project
, In_Tree
));
302 Set_Directory_Of
(Virtual_Project
, In_Tree
, Virtual_Dir_Id
);
303 Set_Project_Declaration_Of
304 (Virtual_Project
, In_Tree
, Project_Declaration
);
305 Set_Extended_Project_Path_Of
306 (Virtual_Project
, In_Tree
, Path_Name_Of
(For_Project
, In_Tree
));
308 -- Project declaration
310 Set_First_Declarative_Item_Of
311 (Project_Declaration
, In_Tree
, Source_Dirs_Declaration
);
312 Set_Extended_Project_Of
(Project_Declaration
, In_Tree
, For_Project
);
314 -- Source_Dirs declaration
316 Set_Current_Item_Node
317 (Source_Dirs_Declaration
, In_Tree
, Source_Dirs_Attribute
);
319 -- Source_Dirs attribute
321 Set_Name_Of
(Source_Dirs_Attribute
, In_Tree
, Snames
.Name_Source_Dirs
);
323 (Source_Dirs_Attribute
, In_Tree
, Source_Dirs_Expression
);
325 -- Source_Dirs expression
327 Set_First_Term
(Source_Dirs_Expression
, In_Tree
, Source_Dirs_Term
);
331 Set_Current_Term
(Source_Dirs_Term
, In_Tree
, Source_Dirs_List
);
333 -- Source_Dirs empty list: nothing to do
335 -- Put virtual project into Projects_Htable
337 Prj
.Tree
.Tree_Private_Part
.Projects_Htable
.Set
338 (T
=> In_Tree
.Projects_HT
,
339 K
=> Virtual_Name_Id
,
340 E
=> (Name
=> Virtual_Name_Id
,
341 Node
=> Virtual_Project
,
342 Canonical_Path
=> No_Name
,
344 end Create_Virtual_Extending_Project
;
346 ----------------------------
347 -- Immediate_Directory_Of --
348 ----------------------------
350 function Immediate_Directory_Of
(Path_Name
: Name_Id
) return Name_Id
is
352 Get_Name_String
(Path_Name
);
354 for Index
in reverse 1 .. Name_Len
loop
355 if Name_Buffer
(Index
) = '/'
356 or else Name_Buffer
(Index
) = Dir_Sep
358 -- Remove all chars after last directory separator from name
361 Name_Len
:= Index
- 1;
371 -- There is no directory separator in name. Return "./" or ".\"
374 Name_Buffer
(1) := '.';
375 Name_Buffer
(2) := Dir_Sep
;
377 end Immediate_Directory_Of
;
379 -----------------------------------
380 -- Look_For_Virtual_Projects_For --
381 -----------------------------------
383 procedure Look_For_Virtual_Projects_For
384 (Proj
: Project_Node_Id
;
385 In_Tree
: Project_Node_Tree_Ref
;
386 Potentially_Virtual
: Boolean)
389 Declaration
: Project_Node_Id
:= Empty_Node
;
390 -- Node for the project declaration of Proj
392 With_Clause
: Project_Node_Id
:= Empty_Node
;
393 -- Node for a with clause of Proj
395 Imported
: Project_Node_Id
:= Empty_Node
;
396 -- Node for a project imported by Proj
398 Extended
: Project_Node_Id
:= Empty_Node
;
399 -- Node for the eventual project extended by Proj
402 -- Nothing to do if Proj is not defined or if it has already been
405 if Proj
/= Empty_Node
and then not Processed_Hash
.Get
(Proj
) then
406 -- Make sure the project will not be processed again
408 Processed_Hash
.Set
(Proj
, True);
410 Declaration
:= Project_Declaration_Of
(Proj
, In_Tree
);
412 if Declaration
/= Empty_Node
then
413 Extended
:= Extended_Project_Of
(Declaration
, In_Tree
);
416 -- If this is a project that may need a virtual extending project
417 -- and it is not itself an extending project, put it in the list.
419 if Potentially_Virtual
and then Extended
= Empty_Node
then
420 Virtual_Hash
.Set
(Proj
, Proj
);
423 -- Now check the projects it imports
425 With_Clause
:= First_With_Clause_Of
(Proj
, In_Tree
);
427 while With_Clause
/= Empty_Node
loop
428 Imported
:= Project_Node_Of
(With_Clause
, In_Tree
);
430 if Imported
/= Empty_Node
then
431 Look_For_Virtual_Projects_For
432 (Imported
, In_Tree
, Potentially_Virtual
=> True);
435 With_Clause
:= Next_With_Clause_Of
(With_Clause
, In_Tree
);
438 -- Check also the eventual project extended by Proj. As this project
439 -- is already extended, call recursively with Potentially_Virtual
442 Look_For_Virtual_Projects_For
443 (Extended
, In_Tree
, Potentially_Virtual
=> False);
445 end Look_For_Virtual_Projects_For
;
452 (In_Tree
: Project_Node_Tree_Ref
;
453 Project
: out Project_Node_Id
;
454 Project_File_Name
: String;
455 Always_Errout_Finalize
: Boolean;
456 Packages_To_Check
: String_List_Access
:= All_Packages
;
457 Store_Comments
: Boolean := False)
459 Current_Directory
: constant String := Get_Current_Dir
;
463 Project
:= Empty_Node
;
465 if Current_Verbosity
>= Medium
then
466 Write_Str
("ADA_PROJECT_PATH=""");
467 Write_Str
(Project_Path
);
472 Path_Name
: constant String :=
473 Project_Path_Name_Of
(Project_File_Name
,
474 Directory
=> Current_Directory
);
478 Prj
.Err
.Scanner
.Set_Comment_As_Token
(Store_Comments
);
479 Prj
.Err
.Scanner
.Set_End_Of_Line_As_Token
(Store_Comments
);
481 -- Parse the main project file
483 if Path_Name
= "" then
485 ("project file """, Project_File_Name
, """ not found");
486 Project
:= Empty_Node
;
493 Extends_All
=> Dummy
,
494 Path_Name
=> Path_Name
,
496 From_Extended
=> None
,
498 Packages_To_Check
=> Packages_To_Check
);
500 -- If Project is an extending-all project, create the eventual
501 -- virtual extending projects and check that there are no illegally
502 -- imported projects.
504 if Project
/= Empty_Node
505 and then Is_Extending_All
(Project
, In_Tree
)
507 -- First look for projects that potentially need a virtual
508 -- extending project.
511 Processed_Hash
.Reset
;
513 -- Mark the extending all project as processed, to avoid checking
514 -- the imported projects in case of a "limited with" on this
515 -- extending all project.
517 Processed_Hash
.Set
(Project
, True);
520 Declaration
: constant Project_Node_Id
:=
521 Project_Declaration_Of
(Project
, In_Tree
);
523 Look_For_Virtual_Projects_For
524 (Extended_Project_Of
(Declaration
, In_Tree
), In_Tree
,
525 Potentially_Virtual
=> False);
528 -- Now, check the projects directly imported by the main project.
529 -- Remove from the potentially virtual any project extended by one
530 -- of these imported projects. For non extending imported
531 -- projects, check that they do not belong to the project tree of
532 -- the project being "extended-all" by the main project.
535 With_Clause
: Project_Node_Id
;
536 Imported
: Project_Node_Id
:= Empty_Node
;
537 Declaration
: Project_Node_Id
:= Empty_Node
;
540 With_Clause
:= First_With_Clause_Of
(Project
, In_Tree
);
541 while With_Clause
/= Empty_Node
loop
542 Imported
:= Project_Node_Of
(With_Clause
, In_Tree
);
544 if Imported
/= Empty_Node
then
545 Declaration
:= Project_Declaration_Of
(Imported
, In_Tree
);
547 if Extended_Project_Of
(Declaration
, In_Tree
) /=
552 Extended_Project_Of
(Declaration
, In_Tree
);
553 exit when Imported
= Empty_Node
;
554 Virtual_Hash
.Remove
(Imported
);
556 Project_Declaration_Of
(Imported
, In_Tree
);
561 With_Clause
:= Next_With_Clause_Of
(With_Clause
, In_Tree
);
565 -- Now create all the virtual extending projects
568 Proj
: Project_Node_Id
:= Virtual_Hash
.Get_First
;
570 while Proj
/= Empty_Node
loop
571 Create_Virtual_Extending_Project
(Proj
, Project
, In_Tree
);
572 Proj
:= Virtual_Hash
.Get_Next
;
577 -- If there were any kind of error during the parsing, serious
578 -- or not, then the parsing fails.
580 if Err_Vars
.Total_Errors_Detected
> 0 then
581 Project
:= Empty_Node
;
584 if Project
= Empty_Node
or else Always_Errout_Finalize
then
594 Write_Line
(Exception_Information
(X
));
595 Write_Str
("Exception ");
596 Write_Str
(Exception_Name
(X
));
597 Write_Line
(" raised, while processing project file");
598 Project
:= Empty_Node
;
601 ------------------------------
602 -- Pre_Parse_Context_Clause --
603 ------------------------------
605 procedure Pre_Parse_Context_Clause
606 (In_Tree
: Project_Node_Tree_Ref
;
607 Context_Clause
: out With_Id
)
609 Current_With_Clause
: With_Id
:= No_With
;
610 Limited_With
: Boolean := False;
612 Current_With
: With_Record
;
614 Current_With_Node
: Project_Node_Id
:= Empty_Node
;
617 -- Assume no context clause
619 Context_Clause
:= No_With
;
622 -- If Token is not WITH or LIMITED, there is no context clause, or we
623 -- have exhausted the with clauses.
625 while Token
= Tok_With
or else Token
= Tok_Limited
loop
627 Default_Project_Node
(Of_Kind
=> N_With_Clause
, In_Tree
=> In_Tree
);
628 Limited_With
:= Token
= Tok_Limited
;
631 Scan
(In_Tree
); -- scan past LIMITED
632 Expect
(Tok_With
, "WITH");
633 exit With_Loop
when Token
/= Tok_With
;
638 Scan
(In_Tree
); -- scan past WITH or ","
640 Expect
(Tok_String_Literal
, "literal string");
642 if Token
/= Tok_String_Literal
then
646 -- Store path and location in table Withs
650 Location
=> Token_Ptr
,
651 Limited_With
=> Limited_With
,
652 Node
=> Current_With_Node
,
655 Withs
.Increment_Last
;
656 Withs
.Table
(Withs
.Last
) := Current_With
;
658 if Current_With_Clause
= No_With
then
659 Context_Clause
:= Withs
.Last
;
662 Withs
.Table
(Current_With_Clause
).Next
:= Withs
.Last
;
665 Current_With_Clause
:= Withs
.Last
;
669 if Token
= Tok_Semicolon
then
670 Set_End_Of_Line
(Current_With_Node
);
671 Set_Previous_Line_Node
(Current_With_Node
);
673 -- End of (possibly multiple) with clause;
675 Scan
(In_Tree
); -- scan past the semicolon.
678 elsif Token
= Tok_Comma
then
679 Set_Is_Not_Last_In_List
(Current_With_Node
, In_Tree
);
682 Error_Msg
("expected comma or semi colon", Token_Ptr
);
688 (Of_Kind
=> N_With_Clause
, In_Tree
=> In_Tree
);
691 end Pre_Parse_Context_Clause
;
693 -------------------------------
694 -- Post_Parse_Context_Clause --
695 -------------------------------
697 procedure Post_Parse_Context_Clause
698 (Context_Clause
: With_Id
;
699 In_Tree
: Project_Node_Tree_Ref
;
700 Imported_Projects
: out Project_Node_Id
;
701 Project_Directory
: Name_Id
;
702 From_Extended
: Extension_Origin
;
703 In_Limited
: Boolean;
704 Packages_To_Check
: String_List_Access
)
706 Current_With_Clause
: With_Id
:= Context_Clause
;
708 Current_Project
: Project_Node_Id
:= Empty_Node
;
709 Previous_Project
: Project_Node_Id
:= Empty_Node
;
710 Next_Project
: Project_Node_Id
:= Empty_Node
;
712 Project_Directory_Path
: constant String :=
713 Get_Name_String
(Project_Directory
);
715 Current_With
: With_Record
;
716 Limited_With
: Boolean := False;
717 Extends_All
: Boolean := False;
720 Imported_Projects
:= Empty_Node
;
722 while Current_With_Clause
/= No_With
loop
723 Current_With
:= Withs
.Table
(Current_With_Clause
);
724 Current_With_Clause
:= Current_With
.Next
;
726 Limited_With
:= In_Limited
or Current_With
.Limited_With
;
729 Original_Path
: constant String :=
730 Get_Name_String
(Current_With
.Path
);
732 Imported_Path_Name
: constant String :=
734 (Original_Path
, Project_Directory_Path
);
736 Resolved_Path
: constant String :=
739 Resolve_Links
=> True,
740 Case_Sensitive
=> True);
742 Withed_Project
: Project_Node_Id
:= Empty_Node
;
745 if Imported_Path_Name
= "" then
747 -- The project file cannot be found
749 Error_Msg_Name_1
:= Current_With
.Path
;
751 Error_Msg
("unknown project file: {", Current_With
.Location
);
753 -- If this is not imported by the main project file,
754 -- display the import path.
756 if Project_Stack
.Last
> 1 then
757 for Index
in reverse 1 .. Project_Stack
.Last
loop
758 Error_Msg_Name_1
:= Project_Stack
.Table
(Index
).Path_Name
;
759 Error_Msg
("\imported by {", Current_With
.Location
);
766 Previous_Project
:= Current_Project
;
768 if Current_Project
= Empty_Node
then
770 -- First with clause of the context clause
772 Current_Project
:= Current_With
.Node
;
773 Imported_Projects
:= Current_Project
;
776 Next_Project
:= Current_With
.Node
;
777 Set_Next_With_Clause_Of
778 (Current_Project
, In_Tree
, Next_Project
);
779 Current_Project
:= Next_Project
;
783 (Current_Project
, In_Tree
, Current_With
.Path
);
785 (Current_Project
, In_Tree
, Current_With
.Location
);
787 -- If this is a "limited with", check if we have a circularity.
788 -- If we have one, get the project id of the limited imported
789 -- project file, and do not parse it.
791 if Limited_With
and then Project_Stack
.Last
> 1 then
793 Canonical_Path_Name
: Name_Id
;
796 Name_Len
:= Resolved_Path
'Length;
797 Name_Buffer
(1 .. Name_Len
) := Resolved_Path
;
798 Canonical_Case_File_Name
(Name_Buffer
(1 .. Name_Len
));
799 Canonical_Path_Name
:= Name_Find
;
801 for Index
in 1 .. Project_Stack
.Last
loop
802 if Project_Stack
.Table
(Index
).Canonical_Path_Name
=
805 -- We have found the limited imported project,
806 -- get its project id, and do not parse it.
808 Withed_Project
:= Project_Stack
.Table
(Index
).Id
;
815 -- Parse the imported project, if its project id is unknown
817 if Withed_Project
= Empty_Node
then
820 Project
=> Withed_Project
,
821 Extends_All
=> Extends_All
,
822 Path_Name
=> Imported_Path_Name
,
824 From_Extended
=> From_Extended
,
825 In_Limited
=> Limited_With
,
826 Packages_To_Check
=> Packages_To_Check
);
829 Extends_All
:= Is_Extending_All
(Withed_Project
, In_Tree
);
832 if Withed_Project
= Empty_Node
then
833 -- If parsing was not successful, remove the
836 Current_Project
:= Previous_Project
;
838 if Current_Project
= Empty_Node
then
839 Imported_Projects
:= Empty_Node
;
842 Set_Next_With_Clause_Of
843 (Current_Project
, In_Tree
, Empty_Node
);
846 -- If parsing was successful, record project name
847 -- and path name in with clause
850 (Node
=> Current_Project
,
852 To
=> Withed_Project
,
853 Limited_With
=> Current_With
.Limited_With
);
857 Name_Of
(Withed_Project
, In_Tree
));
859 Name_Len
:= Resolved_Path
'Length;
860 Name_Buffer
(1 .. Name_Len
) := Resolved_Path
;
861 Set_Path_Name_Of
(Current_Project
, In_Tree
, Name_Find
);
864 Set_Is_Extending_All
(Current_Project
, In_Tree
);
870 end Post_Parse_Context_Clause
;
872 --------------------------
873 -- Parse_Single_Project --
874 --------------------------
876 procedure Parse_Single_Project
877 (In_Tree
: Project_Node_Tree_Ref
;
878 Project
: out Project_Node_Id
;
879 Extends_All
: out Boolean;
882 From_Extended
: Extension_Origin
;
883 In_Limited
: Boolean;
884 Packages_To_Check
: String_List_Access
)
886 Normed_Path_Name
: Name_Id
;
887 Canonical_Path_Name
: Name_Id
;
888 Project_Directory
: Name_Id
;
889 Project_Scan_State
: Saved_Project_Scan_State
;
890 Source_Index
: Source_File_Index
;
892 Extending
: Boolean := False;
894 Extended_Project
: Project_Node_Id
:= Empty_Node
;
896 A_Project_Name_And_Node
: Tree_Private_Part
.Project_Name_And_Node
:=
897 Tree_Private_Part
.Projects_Htable
.Get_First
898 (In_Tree
.Projects_HT
);
900 Name_From_Path
: constant Name_Id
:= Project_Name_From
(Path_Name
);
902 Name_Of_Project
: Name_Id
:= No_Name
;
904 First_With
: With_Id
;
906 use Tree_Private_Part
;
908 Project_Comment_State
: Tree
.Comment_State
;
911 Extends_All
:= False;
914 Normed_Path
: constant String := Normalize_Pathname
915 (Path_Name
, Resolve_Links
=> False,
916 Case_Sensitive
=> True);
917 Canonical_Path
: constant String := Normalize_Pathname
918 (Normed_Path
, Resolve_Links
=> True,
919 Case_Sensitive
=> False);
922 Name_Len
:= Normed_Path
'Length;
923 Name_Buffer
(1 .. Name_Len
) := Normed_Path
;
924 Normed_Path_Name
:= Name_Find
;
925 Name_Len
:= Canonical_Path
'Length;
926 Name_Buffer
(1 .. Name_Len
) := Canonical_Path
;
927 Canonical_Path_Name
:= Name_Find
;
930 -- Check for a circular dependency
932 for Index
in 1 .. Project_Stack
.Last
loop
933 if Canonical_Path_Name
=
934 Project_Stack
.Table
(Index
).Canonical_Path_Name
936 Error_Msg
("circular dependency detected", Token_Ptr
);
937 Error_Msg_Name_1
:= Normed_Path_Name
;
938 Error_Msg
("\ { is imported by", Token_Ptr
);
940 for Current
in reverse 1 .. Project_Stack
.Last
loop
941 Error_Msg_Name_1
:= Project_Stack
.Table
(Current
).Path_Name
;
943 if Project_Stack
.Table
(Current
).Canonical_Path_Name
/=
947 ("\ { which itself is imported by", Token_Ptr
);
950 Error_Msg
("\ {", Token_Ptr
);
955 Project
:= Empty_Node
;
960 -- Put the new path name on the stack
962 Project_Stack
.Increment_Last
;
963 Project_Stack
.Table
(Project_Stack
.Last
).Path_Name
:= Normed_Path_Name
;
964 Project_Stack
.Table
(Project_Stack
.Last
).Canonical_Path_Name
:=
967 -- Check if the project file has already been parsed
970 A_Project_Name_And_Node
/= Tree_Private_Part
.No_Project_Name_And_Node
972 if A_Project_Name_And_Node
.Canonical_Path
= Canonical_Path_Name
then
975 if A_Project_Name_And_Node
.Extended
then
977 ("cannot extend the same project file several times",
981 ("cannot extend an already imported project file",
985 elsif A_Project_Name_And_Node
.Extended
then
987 Is_Extending_All
(A_Project_Name_And_Node
.Node
, In_Tree
);
989 -- If the imported project is an extended project A,
990 -- and we are in an extended project, replace A with the
991 -- ultimate project extending A.
993 if From_Extended
/= None
then
995 Decl
: Project_Node_Id
:=
996 Project_Declaration_Of
997 (A_Project_Name_And_Node
.Node
, In_Tree
);
999 Prj
: Project_Node_Id
:=
1000 Extending_Project_Of
(Decl
, In_Tree
);
1004 Decl
:= Project_Declaration_Of
(Prj
, In_Tree
);
1005 exit when Extending_Project_Of
(Decl
, In_Tree
) =
1007 Prj
:= Extending_Project_Of
(Decl
, In_Tree
);
1010 A_Project_Name_And_Node
.Node
:= Prj
;
1014 ("cannot import an already extended project file",
1019 Project
:= A_Project_Name_And_Node
.Node
;
1020 Project_Stack
.Decrement_Last
;
1024 A_Project_Name_And_Node
:=
1025 Tree_Private_Part
.Projects_Htable
.Get_Next
(In_Tree
.Projects_HT
);
1028 -- We never encountered this project file
1029 -- Save the scan state, load the project file and start to scan it.
1031 Save_Project_Scan_State
(Project_Scan_State
);
1032 Source_Index
:= Load_Project_File
(Path_Name
);
1033 Tree
.Save
(Project_Comment_State
);
1035 -- If we cannot find it, we stop
1037 if Source_Index
= No_Source_File
then
1038 Project
:= Empty_Node
;
1039 Project_Stack
.Decrement_Last
;
1043 Prj
.Err
.Scanner
.Initialize_Scanner
(Source_Index
);
1047 if Name_From_Path
= No_Name
then
1049 -- The project file name is not correct (no or bad extension,
1050 -- or not following Ada identifier's syntax).
1052 Error_Msg_Name_1
:= Canonical_Path_Name
;
1053 Error_Msg
("?{ is not a valid path name for a project file",
1057 if Current_Verbosity
>= Medium
then
1058 Write_Str
("Parsing """);
1059 Write_Str
(Path_Name
);
1064 -- Is there any imported project?
1066 Pre_Parse_Context_Clause
(In_Tree
, First_With
);
1068 Project_Directory
:= Immediate_Directory_Of
(Normed_Path_Name
);
1069 Project
:= Default_Project_Node
1070 (Of_Kind
=> N_Project
, In_Tree
=> In_Tree
);
1071 Project_Stack
.Table
(Project_Stack
.Last
).Id
:= Project
;
1072 Set_Directory_Of
(Project
, In_Tree
, Project_Directory
);
1073 Set_Path_Name_Of
(Project
, In_Tree
, Normed_Path_Name
);
1074 Set_Location_Of
(Project
, In_Tree
, Token_Ptr
);
1076 Expect
(Tok_Project
, "PROJECT");
1078 -- Mark location of PROJECT token if present
1080 if Token
= Tok_Project
then
1081 Scan
(In_Tree
); -- scan past PROJECT
1082 Set_Location_Of
(Project
, In_Tree
, Token_Ptr
);
1089 Expect
(Tok_Identifier
, "identifier");
1091 -- If the token is not an identifier, clear the buffer before
1092 -- exiting to indicate that the name of the project is ill-formed.
1094 if Token
/= Tok_Identifier
then
1099 -- Add the identifier name to the buffer
1101 Get_Name_String
(Token_Name
);
1102 Add_To_Buffer
(Name_Buffer
(1 .. Name_Len
), Buffer
, Buffer_Last
);
1104 -- Scan past the identifier
1108 -- If we have a dot, add a dot the the Buffer and look for the next
1111 exit when Token
/= Tok_Dot
;
1112 Add_To_Buffer
(".", Buffer
, Buffer_Last
);
1114 -- Scan past the dot
1119 -- See if this is an extending project
1121 if Token
= Tok_Extends
then
1123 -- Make sure that gnatmake will use mapping files
1125 Create_Mapping_File
:= True;
1127 -- We are extending another project
1131 Scan
(In_Tree
); -- scan past EXTENDS
1133 if Token
= Tok_All
then
1134 Extends_All
:= True;
1135 Set_Is_Extending_All
(Project
, In_Tree
);
1136 Scan
(In_Tree
); -- scan past ALL
1140 -- If the name is well formed, Buffer_Last is > 0
1142 if Buffer_Last
> 0 then
1144 -- The Buffer contains the name of the project
1146 Name_Len
:= Buffer_Last
;
1147 Name_Buffer
(1 .. Name_Len
) := Buffer
(1 .. Buffer_Last
);
1148 Name_Of_Project
:= Name_Find
;
1149 Set_Name_Of
(Project
, In_Tree
, Name_Of_Project
);
1151 -- To get expected name of the project file, replace dots by dashes
1153 Name_Len
:= Buffer_Last
;
1154 Name_Buffer
(1 .. Name_Len
) := Buffer
(1 .. Buffer_Last
);
1156 for Index
in 1 .. Name_Len
loop
1157 if Name_Buffer
(Index
) = '.' then
1158 Name_Buffer
(Index
) := '-';
1162 Canonical_Case_File_Name
(Name_Buffer
(1 .. Name_Len
));
1165 Expected_Name
: constant Name_Id
:= Name_Find
;
1168 -- Output a warning if the actual name is not the expected name
1170 if Name_From_Path
/= No_Name
1171 and then Expected_Name
/= Name_From_Path
1173 Error_Msg_Name_1
:= Expected_Name
;
1174 Error_Msg
("?file name does not match unit name, " &
1175 "should be `{" & Project_File_Extension
& "`",
1181 Imported_Projects
: Project_Node_Id
:= Empty_Node
;
1182 From_Ext
: Extension_Origin
:= None
;
1185 -- Extending_All is always propagated
1187 if From_Extended
= Extending_All
or else Extends_All
then
1188 From_Ext
:= Extending_All
;
1190 -- Otherwise, From_Extended is set to Extending_Single if the
1191 -- current project is an extending project.
1194 From_Ext
:= Extending_Simple
;
1197 Post_Parse_Context_Clause
1198 (In_Tree
=> In_Tree
,
1199 Context_Clause
=> First_With
,
1200 Imported_Projects
=> Imported_Projects
,
1201 Project_Directory
=> Project_Directory
,
1202 From_Extended
=> From_Ext
,
1203 In_Limited
=> In_Limited
,
1204 Packages_To_Check
=> Packages_To_Check
);
1205 Set_First_With_Clause_Of
(Project
, In_Tree
, Imported_Projects
);
1209 Name_And_Node
: Tree_Private_Part
.Project_Name_And_Node
:=
1210 Tree_Private_Part
.Projects_Htable
.Get_First
1211 (In_Tree
.Projects_HT
);
1212 Project_Name
: Name_Id
:= Name_And_Node
.Name
;
1215 -- Check if we already have a project with this name
1217 while Project_Name
/= No_Name
1218 and then Project_Name
/= Name_Of_Project
1221 Tree_Private_Part
.Projects_Htable
.Get_Next
1222 (In_Tree
.Projects_HT
);
1223 Project_Name
:= Name_And_Node
.Name
;
1226 -- Report an error if we already have a project with this name
1228 if Project_Name
/= No_Name
then
1229 Error_Msg_Name_1
:= Project_Name
;
1231 ("duplicate project name {", Location_Of
(Project
, In_Tree
));
1233 Path_Name_Of
(Name_And_Node
.Node
, In_Tree
);
1235 ("\already in {", Location_Of
(Project
, In_Tree
));
1238 -- Otherwise, add the name of the project to the hash table, so
1239 -- that we can check that no other subsequent project will have
1242 Tree_Private_Part
.Projects_Htable
.Set
1243 (T
=> In_Tree
.Projects_HT
,
1244 K
=> Name_Of_Project
,
1245 E
=> (Name
=> Name_Of_Project
,
1247 Canonical_Path
=> Canonical_Path_Name
,
1248 Extended
=> Extended
));
1255 Expect
(Tok_String_Literal
, "literal string");
1257 if Token
= Tok_String_Literal
then
1258 Set_Extended_Project_Path_Of
(Project
, In_Tree
, Token_Name
);
1261 Original_Path_Name
: constant String :=
1262 Get_Name_String
(Token_Name
);
1264 Extended_Project_Path_Name
: constant String :=
1265 Project_Path_Name_Of
1266 (Original_Path_Name
,
1268 (Project_Directory
));
1271 if Extended_Project_Path_Name
= "" then
1273 -- We could not find the project file to extend
1275 Error_Msg_Name_1
:= Token_Name
;
1277 Error_Msg
("unknown project file: {", Token_Ptr
);
1279 -- If we are not in the main project file, display the
1282 if Project_Stack
.Last
> 1 then
1284 Project_Stack
.Table
(Project_Stack
.Last
).Path_Name
;
1285 Error_Msg
("\extended by {", Token_Ptr
);
1287 for Index
in reverse 1 .. Project_Stack
.Last
- 1 loop
1289 Project_Stack
.Table
(Index
).Path_Name
;
1290 Error_Msg
("\imported by {", Token_Ptr
);
1296 From_Ext
: Extension_Origin
:= None
;
1299 if From_Extended
= Extending_All
or else Extends_All
then
1300 From_Ext
:= Extending_All
;
1303 Parse_Single_Project
1304 (In_Tree
=> In_Tree
,
1305 Project
=> Extended_Project
,
1306 Extends_All
=> Extends_All
,
1307 Path_Name
=> Extended_Project_Path_Name
,
1309 From_Extended
=> From_Ext
,
1310 In_Limited
=> In_Limited
,
1311 Packages_To_Check
=> Packages_To_Check
);
1314 -- A project that extends an extending-all project is also
1315 -- an extending-all project.
1317 if Extended_Project
/= Empty_Node
1318 and then Is_Extending_All
(Extended_Project
, In_Tree
)
1320 Set_Is_Extending_All
(Project
, In_Tree
);
1325 Scan
(In_Tree
); -- scan past the extended project path
1329 -- Check that a non extending-all project does not import an
1330 -- extending-all project.
1332 if not Is_Extending_All
(Project
, In_Tree
) then
1334 With_Clause
: Project_Node_Id
:=
1335 First_With_Clause_Of
(Project
, In_Tree
);
1336 Imported
: Project_Node_Id
:= Empty_Node
;
1340 while With_Clause
/= Empty_Node
loop
1341 Imported
:= Project_Node_Of
(With_Clause
, In_Tree
);
1343 if Is_Extending_All
(With_Clause
, In_Tree
) then
1344 Error_Msg_Name_1
:= Name_Of
(Imported
, In_Tree
);
1345 Error_Msg
("cannot import extending-all project {",
1347 exit With_Clause_Loop
;
1350 With_Clause
:= Next_With_Clause_Of
(With_Clause
, In_Tree
);
1351 end loop With_Clause_Loop
;
1355 -- Check that a project with a name including a dot either imports
1356 -- or extends the project whose name precedes the last dot.
1358 if Name_Of_Project
/= No_Name
then
1359 Get_Name_String
(Name_Of_Project
);
1365 -- Look for the last dot
1367 while Name_Len
> 0 and then Name_Buffer
(Name_Len
) /= '.' loop
1368 Name_Len
:= Name_Len
- 1;
1371 -- If a dot was find, check if the parent project is imported
1374 if Name_Len
> 0 then
1375 Name_Len
:= Name_Len
- 1;
1378 Parent_Name
: constant Name_Id
:= Name_Find
;
1379 Parent_Found
: Boolean := False;
1380 With_Clause
: Project_Node_Id
:=
1381 First_With_Clause_Of
(Project
, In_Tree
);
1384 -- If there is an extended project, check its name
1386 if Extended_Project
/= Empty_Node
then
1388 Name_Of
(Extended_Project
, In_Tree
) = Parent_Name
;
1391 -- If the parent project is not the extended project,
1392 -- check each imported project until we find the parent project.
1394 while not Parent_Found
and then With_Clause
/= Empty_Node
loop
1396 Name_Of
(Project_Node_Of
(With_Clause
, In_Tree
), In_Tree
) =
1398 With_Clause
:= Next_With_Clause_Of
(With_Clause
, In_Tree
);
1401 -- If the parent project was not found, report an error
1403 if not Parent_Found
then
1404 Error_Msg_Name_1
:= Name_Of_Project
;
1405 Error_Msg_Name_2
:= Parent_Name
;
1406 Error_Msg
("project { does not import or extend project {",
1407 Location_Of
(Project
, In_Tree
));
1412 Expect
(Tok_Is
, "IS");
1413 Set_End_Of_Line
(Project
);
1414 Set_Previous_Line_Node
(Project
);
1415 Set_Next_End_Node
(Project
);
1418 Project_Declaration
: Project_Node_Id
:= Empty_Node
;
1421 -- No need to Scan past "is", Prj.Dect.Parse will do it
1424 (In_Tree
=> In_Tree
,
1425 Declarations
=> Project_Declaration
,
1426 Current_Project
=> Project
,
1427 Extends
=> Extended_Project
,
1428 Packages_To_Check
=> Packages_To_Check
);
1429 Set_Project_Declaration_Of
(Project
, In_Tree
, Project_Declaration
);
1431 if Extended_Project
/= Empty_Node
then
1432 Set_Extending_Project_Of
1433 (Project_Declaration_Of
(Extended_Project
, In_Tree
), In_Tree
,
1438 Expect
(Tok_End
, "END");
1439 Remove_Next_End_Node
;
1441 -- Skip "end" if present
1443 if Token
= Tok_End
then
1451 -- Store the name following "end" in the Buffer. The name may be made of
1452 -- several simple names.
1455 Expect
(Tok_Identifier
, "identifier");
1457 -- If we don't have an identifier, clear the buffer before exiting to
1458 -- avoid checking the name.
1460 if Token
/= Tok_Identifier
then
1465 -- Add the identifier to the Buffer
1466 Get_Name_String
(Token_Name
);
1467 Add_To_Buffer
(Name_Buffer
(1 .. Name_Len
), Buffer
, Buffer_Last
);
1469 -- Scan past the identifier
1472 exit when Token
/= Tok_Dot
;
1473 Add_To_Buffer
(".", Buffer
, Buffer_Last
);
1477 -- If we have a valid name, check if it is the name of the project
1479 if Name_Of_Project
/= No_Name
and then Buffer_Last
> 0 then
1480 if To_Lower
(Buffer
(1 .. Buffer_Last
)) /=
1481 Get_Name_String
(Name_Of
(Project
, In_Tree
))
1483 -- Invalid name: report an error
1485 Error_Msg
("expected """ &
1486 Get_Name_String
(Name_Of
(Project
, In_Tree
)) & """",
1491 Expect
(Tok_Semicolon
, "`;`");
1493 -- Check that there is no more text following the end of the project
1496 if Token
= Tok_Semicolon
then
1497 Set_Previous_End_Node
(Project
);
1500 if Token
/= Tok_EOF
then
1502 ("unexpected text following end of project", Token_Ptr
);
1506 -- Restore the scan state, in case we are not the main project
1508 Restore_Project_Scan_State
(Project_Scan_State
);
1510 -- And remove the project from the project stack
1512 Project_Stack
.Decrement_Last
;
1514 -- Indicate if there are unkept comments
1516 Tree
.Set_Project_File_Includes_Unkept_Comments
1519 To
=> Tree
.There_Are_Unkept_Comments
);
1521 -- And restore the comment state that was saved
1523 Tree
.Restore
(Project_Comment_State
);
1524 end Parse_Single_Project
;
1526 -----------------------
1527 -- Project_Name_From --
1528 -----------------------
1530 function Project_Name_From
(Path_Name
: String) return Name_Id
is
1531 Canonical
: String (1 .. Path_Name
'Length) := Path_Name
;
1532 First
: Natural := Canonical
'Last;
1533 Last
: Natural := First
;
1537 if Current_Verbosity
= High
then
1538 Write_Str
("Project_Name_From (""");
1539 Write_Str
(Canonical
);
1543 -- If the path name is empty, return No_Name to indicate failure
1549 Canonical_Case_File_Name
(Canonical
);
1551 -- Look for the last dot in the path name
1555 Canonical
(First
) /= '.'
1560 -- If we have a dot, check that it is followed by the correct extension
1562 if First
> 0 and then Canonical
(First
) = '.' then
1563 if Canonical
(First
.. Last
) = Project_File_Extension
1566 -- Look for the last directory separator, if any
1572 and then Canonical
(First
) /= '/'
1573 and then Canonical
(First
) /= Dir_Sep
1579 -- Not the correct extension, return No_Name to indicate failure
1584 -- If no dot in the path name, return No_Name to indicate failure
1592 -- If the extension is the file name, return No_Name to indicate failure
1594 if First
> Last
then
1598 -- Put the name in lower case into Name_Buffer
1600 Name_Len
:= Last
- First
+ 1;
1601 Name_Buffer
(1 .. Name_Len
) := To_Lower
(Canonical
(First
.. Last
));
1605 -- Check if it is a well formed project name. Return No_Name if it is
1609 if not Is_Letter
(Name_Buffer
(Index
)) then
1616 exit when Index
>= Name_Len
;
1618 if Name_Buffer
(Index
) = '_' then
1619 if Name_Buffer
(Index
+ 1) = '_' then
1624 exit when Name_Buffer
(Index
) = '-';
1626 if Name_Buffer
(Index
) /= '_'
1627 and then not Is_Alphanumeric
(Name_Buffer
(Index
))
1635 if Index
>= Name_Len
then
1636 if Is_Alphanumeric
(Name_Buffer
(Name_Len
)) then
1638 -- All checks have succeeded. Return name in Name_Buffer
1646 elsif Name_Buffer
(Index
) = '-' then
1650 end Project_Name_From
;
1652 --------------------------
1653 -- Project_Path_Name_Of --
1654 --------------------------
1656 function Project_Path_Name_Of
1657 (Project_File_Name
: String;
1658 Directory
: String) return String
1660 Result
: String_Access
;
1663 if Current_Verbosity
= High
then
1664 Write_Str
("Project_Path_Name_Of (""");
1665 Write_Str
(Project_File_Name
);
1666 Write_Str
(""", """);
1667 Write_Str
(Directory
);
1668 Write_Line
(""");");
1671 if not Is_Absolute_Path
(Project_File_Name
) then
1672 -- First we try <directory>/<file_name>.<extension>
1674 if Current_Verbosity
= High
then
1675 Write_Str
(" Trying ");
1676 Write_Str
(Directory
);
1677 Write_Char
(Directory_Separator
);
1678 Write_Str
(Project_File_Name
);
1679 Write_Line
(Project_File_Extension
);
1684 (File_Name
=> Directory
& Directory_Separator
&
1685 Project_File_Name
& Project_File_Extension
,
1686 Path
=> Project_Path
);
1688 -- Then we try <directory>/<file_name>
1690 if Result
= null then
1691 if Current_Verbosity
= High
then
1692 Write_Str
(" Trying ");
1693 Write_Str
(Directory
);
1694 Write_Char
(Directory_Separator
);
1695 Write_Line
(Project_File_Name
);
1700 (File_Name
=> Directory
& Directory_Separator
&
1702 Path
=> Project_Path
);
1706 if Result
= null then
1708 -- Then we try <file_name>.<extension>
1710 if Current_Verbosity
= High
then
1711 Write_Str
(" Trying ");
1712 Write_Str
(Project_File_Name
);
1713 Write_Line
(Project_File_Extension
);
1718 (File_Name
=> Project_File_Name
& Project_File_Extension
,
1719 Path
=> Project_Path
);
1722 if Result
= null then
1724 -- Then we try <file_name>
1726 if Current_Verbosity
= High
then
1727 Write_Str
(" Trying ");
1728 Write_Line
(Project_File_Name
);
1733 (File_Name
=> Project_File_Name
,
1734 Path
=> Project_Path
);
1737 -- If we cannot find the project file, we return an empty string
1739 if Result
= null then
1744 Final_Result
: constant String :=
1745 GNAT
.OS_Lib
.Normalize_Pathname
1747 Resolve_Links
=> False,
1748 Case_Sensitive
=> True);
1751 return Final_Result
;
1754 end Project_Path_Name_Of
;