1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2001-2005 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, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, 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 ------------------------------------------------------------------------------
28 with Namet; use Namet;
31 with Osint; use Osint;
36 with Prj.Tree; use Prj.Tree;
37 with Prj.Util; use Prj.Util;
38 with Snames; use Snames;
39 with Table; use Table;
41 with Ada.Characters.Handling; use Ada.Characters.Handling;
42 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
43 with GNAT.OS_Lib; use GNAT.OS_Lib;
44 with GNAT.Regexp; use GNAT.Regexp;
46 with System.Case_Util; use System.Case_Util;
49 package body Prj.Makr is
51 function Dup (Fd : File_Descriptor) return File_Descriptor;
53 procedure Dup2 (Old_Fd, New_Fd : File_Descriptor);
55 Gcc : constant String := "gcc";
56 Gcc_Path : String_Access := null;
58 Non_Empty_Node : constant Project_Node_Id := 1;
59 -- Used for the With_Clause of the naming project
61 type Matched_Type is (True, False, Excluded);
63 Naming_File_Suffix : constant String := "_naming";
64 Source_List_File_Suffix : constant String := "_source_list.txt";
66 Output_FD : File_Descriptor;
67 -- To save the project file and its naming project file
70 -- Output an empty line
72 procedure Write_A_Char (C : Character);
73 -- Write one character to Output_FD
75 procedure Write_A_String (S : String);
76 -- Write a String to Output_FD
78 package Processed_Directories is new Table.Table
79 (Table_Component_Type => String_Access,
80 Table_Index_Type => Natural,
83 Table_Increment => 10,
84 Table_Name => "Prj.Makr.Processed_Directories");
90 function Dup (Fd : File_Descriptor) return File_Descriptor is
92 return File_Descriptor (System.CRTL.dup (Integer (Fd)));
99 procedure Dup2 (Old_Fd, New_Fd : File_Descriptor) is
101 pragma Warnings (Off, Fd);
103 Fd := System.CRTL.dup2 (Integer (Old_Fd), Integer (New_Fd));
112 Project_File : Boolean;
113 Directories : Argument_List;
114 Name_Patterns : Argument_List;
115 Excluded_Patterns : Argument_List;
116 Foreign_Patterns : Argument_List;
117 Preproc_Switches : Argument_List;
118 Very_Verbose : Boolean)
120 Tree : constant Project_Node_Tree_Ref := new Project_Node_Tree_Data;
122 Path_Name : String (1 .. File_Path'Length +
123 Project_File_Extension'Length);
124 Path_Last : Natural := File_Path'Length;
126 Directory_Last : Natural := 0;
128 Output_Name : String (Path_Name'Range);
129 Output_Name_Last : Natural;
130 Output_Name_Id : Name_Id;
132 Project_Node : Project_Node_Id := Empty_Node;
133 Project_Declaration : Project_Node_Id := Empty_Node;
134 Source_Dirs_List : Project_Node_Id := Empty_Node;
135 Current_Source_Dir : Project_Node_Id := Empty_Node;
137 Project_Naming_Node : Project_Node_Id := Empty_Node;
138 Project_Naming_Decl : Project_Node_Id := Empty_Node;
139 Naming_Package : Project_Node_Id := Empty_Node;
141 Project_Naming_File_Name : String (1 .. Output_Name'Length +
142 Naming_File_Suffix'Length);
144 Project_Naming_Last : Natural;
145 Project_Naming_Id : Name_Id := No_Name;
147 Excluded_Expressions : array (Excluded_Patterns'Range) of Regexp;
148 Regular_Expressions : array (Name_Patterns'Range) of Regexp;
149 Foreign_Expressions : array (Foreign_Patterns'Range) of Regexp;
151 Source_List_Path : String (1 .. Output_Name'Length +
152 Source_List_File_Suffix'Length);
153 Source_List_Last : Natural;
155 Source_List_FD : File_Descriptor;
157 Args : Argument_List (1 .. Preproc_Switches'Length + 6);
159 type SFN_Pragma is record
166 package SFN_Pragmas is new Table.Table
167 (Table_Component_Type => SFN_Pragma,
168 Table_Index_Type => Natural,
169 Table_Low_Bound => 0,
171 Table_Increment => 50,
172 Table_Name => "Prj.Makr.SFN_Pragmas");
174 procedure Process_Directory (Dir_Name : String; Recursively : Boolean);
175 -- Look for Ada and foreign sources in a directory, according to the
176 -- patterns. When Recursively is True, after looking for sources in
177 -- Dir_Name, look also in its subdirectories, if any.
179 -----------------------
180 -- Process_Directory --
181 -----------------------
183 procedure Process_Directory (Dir_Name : String; Recursively : Boolean) is
184 Matched : Matched_Type := False;
185 Str : String (1 .. 2_000);
186 Canon : String (1 .. 2_000);
189 Process : Boolean := True;
191 Temp_File_Name : String_Access := null;
192 Save_Last_Pragma_Index : Natural := 0;
193 File_Name_Id : Name_Id := No_Name;
194 SFN_Prag : SFN_Pragma;
197 -- Avoid processing the same directory more than once
199 for Index in 1 .. Processed_Directories.Last loop
200 if Processed_Directories.Table (Index).all = Dir_Name then
207 if Opt.Verbose_Mode then
208 Output.Write_Str ("Processing directory """);
209 Output.Write_Str (Dir_Name);
210 Output.Write_Line ("""");
213 Processed_Directories. Increment_Last;
214 Processed_Directories.Table (Processed_Directories.Last) :=
215 new String'(Dir_Name);
217 -- Get the source file names from the directory. Fails if the
218 -- directory does not exist.
221 Open (Dir, Dir_Name);
223 when Directory_Error =>
224 Prj.Com.Fail ("cannot open directory """, Dir_Name, """");
227 -- Process each regular file in the directory
230 Read (Dir, Str, Last);
231 exit File_Loop when Last = 0;
233 -- Copy the file name and put it in canonical case to match
234 -- against the patterns that have themselves already been put
235 -- in canonical case.
237 Canon (1 .. Last) := Str (1 .. Last);
238 Canonical_Case_File_Name (Canon (1 .. Last));
241 (Dir_Name & Directory_Separator & Str (1 .. Last))
246 Name_Buffer (1 .. Name_Len) := Str (1 .. Last);
247 File_Name_Id := Name_Find;
249 -- First, check if the file name matches at least one of
250 -- the excluded expressions;
252 for Index in Excluded_Expressions'Range loop
254 Match (Canon (1 .. Last), Excluded_Expressions (Index))
261 -- If it does not match any of the excluded expressions,
262 -- check if the file name matches at least one of the
263 -- regular expressions.
265 if Matched = True then
268 for Index in Regular_Expressions'Range loop
271 (Canon (1 .. Last), Regular_Expressions (Index))
280 or else (Matched = True and then Opt.Verbose_Mode)
282 Output.Write_Str (" Checking """);
283 Output.Write_Str (Str (1 .. Last));
284 Output.Write_Line (""": ");
287 -- If the file name matches one of the regular expressions,
288 -- parse it to get its unit name.
290 if Matched = True then
292 FD : File_Descriptor;
294 Saved_Output : File_Descriptor;
295 Saved_Error : File_Descriptor;
298 -- If we don't have the path of the compiler yet,
299 -- get it now. The compiler name may have a prefix,
300 -- so we get the potentially prefixed name.
302 if Gcc_Path = null then
304 Prefix_Gcc : String_Access :=
308 Locate_Exec_On_Path (Prefix_Gcc.all);
312 if Gcc_Path = null then
313 Prj.Com.Fail ("could not locate " & Gcc);
317 -- If we don't have yet the file name of the
318 -- temporary file, get it now.
320 if Temp_File_Name = null then
321 Create_Temp_File (FD, Temp_File_Name);
323 if FD = Invalid_FD then
325 ("could not create temporary file");
329 Delete_File (Temp_File_Name.all, Success);
332 Args (Args'Last) := new String'
334 Directory_Separator &
337 -- Create the temporary file
339 FD := Create_Output_Text_File
340 (Name => Temp_File_Name.all);
342 if FD = Invalid_FD then
344 ("could not create temporary file");
347 -- Save the standard output and error
349 Saved_Output := Dup (Standout);
350 Saved_Error := Dup (Standerr);
352 -- Set standard output and error to the temporary file
357 -- And spawn the compiler
359 Spawn (Gcc_Path.all, Args, Success);
361 -- Restore the standard output and error
363 Dup2 (Saved_Output, Standout);
364 Dup2 (Saved_Error, Standerr);
366 -- Close the temporary file
370 -- And close the saved standard output and error to
371 -- avoid too many file descriptors.
373 Close (Saved_Output);
376 -- Now that standard output is restored, check if
377 -- the compiler ran correctly.
379 -- Read the lines of the temporary file:
380 -- they should contain the kind and name of the unit.
384 Text_Line : String (1 .. 1_000);
388 Open (File, Temp_File_Name.all);
390 if not Is_Valid (File) then
392 ("could not read temporary file");
395 Save_Last_Pragma_Index := SFN_Pragmas.Last;
397 if End_Of_File (File) then
398 if Opt.Verbose_Mode then
400 Output.Write_Str (" (process died) ");
405 Line_Loop : while not End_Of_File (File) loop
406 Get_Line (File, Text_Line, Text_Last);
408 -- Find the first closing parenthesis
410 Char_Loop : for J in 1 .. Text_Last loop
411 if Text_Line (J) = ')' then
413 Text_Line (1 .. 4) = "Unit"
415 -- Add entry to SFN_Pragmas table
418 Name_Buffer (1 .. Name_Len) :=
419 Text_Line (6 .. J - 7);
422 File => File_Name_Id,
424 Spec => Text_Line (J - 5 .. J) =
427 SFN_Pragmas.Increment_Last;
429 (SFN_Pragmas.Last) := SFN_Prag;
437 if Save_Last_Pragma_Index = SFN_Pragmas.Last then
438 if Opt.Verbose_Mode then
439 Output.Write_Line (" not a unit");
443 if SFN_Pragmas.Last >
444 Save_Last_Pragma_Index + 1
446 for Index in Save_Last_Pragma_Index + 1 ..
449 SFN_Pragmas.Table (Index).Index :=
450 Int (Index - Save_Last_Pragma_Index);
454 for Index in Save_Last_Pragma_Index + 1 ..
457 SFN_Prag := SFN_Pragmas.Table (Index);
459 if Opt.Verbose_Mode then
460 if SFN_Prag.Spec then
461 Output.Write_Str (" spec of ");
464 Output.Write_Str (" body of ");
468 (Get_Name_String (SFN_Prag.Unit));
473 -- Add the corresponding attribute in the
474 -- Naming package of the naming project.
477 Decl_Item : constant Project_Node_Id :=
483 Attribute : constant Project_Node_Id :=
486 N_Attribute_Declaration,
489 Expression : constant Project_Node_Id :=
491 (Of_Kind => N_Expression,
492 And_Expr_Kind => Single,
495 Term : constant Project_Node_Id :=
498 And_Expr_Kind => Single,
501 Value : constant Project_Node_Id :=
503 (Of_Kind => N_Literal_String,
504 And_Expr_Kind => Single,
508 Set_Next_Declarative_Item
510 To => First_Declarative_Item_Of
511 (Naming_Package, Tree),
513 Set_First_Declarative_Item_Of
517 Set_Current_Item_Node
522 -- Is it a spec or a body?
524 if SFN_Prag.Spec then
534 -- Get the name of the unit
536 Get_Name_String (SFN_Prag.Unit);
537 To_Lower (Name_Buffer (1 .. Name_Len));
538 Set_Associative_Array_Index_Of
539 (Attribute, Tree, To => Name_Find);
542 (Attribute, Tree, To => Expression);
544 (Expression, Tree, To => Term);
546 (Term, Tree, To => Value);
548 -- And set the name of the file
551 (Value, Tree, To => File_Name_Id);
553 (Value, Tree, To => SFN_Prag.Index);
559 -- Add source file name to source list
563 Str (Last) := ASCII.LF;
565 if Write (Source_List_FD,
569 Prj.Com.Fail ("disk full");
576 Delete_File (Temp_File_Name.all, Success);
580 -- File name matches none of the regular expressions
583 -- If file is not excluded, see if this is foreign source
585 if Matched /= Excluded then
586 for Index in Foreign_Expressions'Range loop
587 if Match (Canon (1 .. Last),
588 Foreign_Expressions (Index))
599 Output.Write_Line ("no match");
602 Output.Write_Line ("excluded");
605 Output.Write_Line ("foreign source");
609 if Project_File and Matched = True then
611 -- Add source file name to source list file
614 Str (Last) := ASCII.LF;
616 if Write (Source_List_FD,
620 Prj.Com.Fail ("disk full");
630 -- If Recursively is True, call itself for each subdirectory.
631 -- We do that, even when this directory has already been processed,
632 -- because all of its subdirectories may not have been processed.
635 Open (Dir, Dir_Name);
638 Read (Dir, Str, Last);
641 -- Do not call itself for "." or ".."
644 (Dir_Name & Directory_Separator & Str (1 .. Last))
645 and then Str (1 .. Last) /= "."
646 and then Str (1 .. Last) /= ".."
649 (Dir_Name & Directory_Separator & Str (1 .. Last),
650 Recursively => True);
656 end Process_Directory;
658 -- Start of processing for Make
661 -- Do some needed initializations
666 Prj.Initialize (No_Project_Tree);
667 Prj.Tree.Initialize (Tree);
669 SFN_Pragmas.Set_Last (0);
671 Processed_Directories.Set_Last (0);
673 -- Initialize the compiler switches
675 Args (1) := new String'("-c");
676 Args (2) := new String'("-gnats");
677 Args (3) := new String'("-gnatu");
678 Args (4 .. 3 + Preproc_Switches'Length) := Preproc_Switches;
679 Args (4 + Preproc_Switches'Length) := new String'("-x");
680 Args (5 + Preproc_Switches'Length) := new String'("ada");
682 -- Get the path and file names
684 if File_Names_Case_Sensitive then
685 Path_Name (1 .. Path_Last) := File_Path;
687 Path_Name (1 .. Path_Last) := To_Lower (File_Path);
690 Path_Name (Path_Last + 1 .. Path_Name'Last) :=
691 Project_File_Extension;
693 -- Get the end of directory information, if any
695 for Index in reverse 1 .. Path_Last loop
696 if Path_Name (Index) = Directory_Separator then
697 Directory_Last := Index;
703 if Path_Last < Project_File_Extension'Length + 1
705 (Path_Last - Project_File_Extension'Length + 1 .. Path_Last)
706 /= Project_File_Extension
708 Path_Last := Path_Name'Last;
711 Output_Name (1 .. Path_Last) := To_Lower (Path_Name (1 .. Path_Last));
712 Output_Name_Last := Path_Last - Project_File_Extension'Length;
714 -- If there is already a project file with the specified name, parse
715 -- it to get the components that are not automatically generated.
717 if Is_Regular_File (Output_Name (1 .. Path_Last)) then
718 if Opt.Verbose_Mode then
719 Output.Write_Str ("Parsing already existing project file """);
720 Output.Write_Str (Output_Name (1 .. Output_Name_Last));
721 Output.Write_Line ("""");
726 Project => Project_Node,
727 Project_File_Name => Output_Name (1 .. Output_Name_Last),
728 Always_Errout_Finalize => False);
730 -- Fail if parsing was not successful
732 if Project_Node = Empty_Node then
733 Fail ("parsing of existing project file failed");
736 -- If parsing was successful, remove the components that are
737 -- automatically generated, if any, so that they will be
738 -- unconditionally added later.
740 -- Remove the with clause for the naming project file
743 With_Clause : Project_Node_Id :=
744 First_With_Clause_Of (Project_Node, Tree);
745 Previous : Project_Node_Id := Empty_Node;
748 while With_Clause /= Empty_Node loop
749 if Prj.Tree.Name_Of (With_Clause, Tree) =
752 if Previous = Empty_Node then
753 Set_First_With_Clause_Of
755 To => Next_With_Clause_Of (With_Clause, Tree));
757 Set_Next_With_Clause_Of
759 To => Next_With_Clause_Of (With_Clause, Tree));
765 Previous := With_Clause;
766 With_Clause := Next_With_Clause_Of (With_Clause, Tree);
770 -- Remove attribute declarations of Source_Files,
771 -- Source_List_File, Source_Dirs, and the declaration of
772 -- package Naming, if they exist.
775 Declaration : Project_Node_Id :=
776 First_Declarative_Item_Of
777 (Project_Declaration_Of
778 (Project_Node, Tree),
780 Previous : Project_Node_Id := Empty_Node;
781 Current_Node : Project_Node_Id := Empty_Node;
784 while Declaration /= Empty_Node loop
785 Current_Node := Current_Item_Node (Declaration, Tree);
787 if (Kind_Of (Current_Node, Tree) = N_Attribute_Declaration
789 (Prj.Tree.Name_Of (Current_Node, Tree) =
791 or else Prj.Tree.Name_Of (Current_Node, Tree) =
792 Name_Source_List_File
793 or else Prj.Tree.Name_Of (Current_Node, Tree) =
796 (Kind_Of (Current_Node, Tree) = N_Package_Declaration
797 and then Prj.Tree.Name_Of (Current_Node, Tree) =
800 if Previous = Empty_Node then
801 Set_First_Declarative_Item_Of
802 (Project_Declaration_Of (Project_Node, Tree),
804 To => Next_Declarative_Item (Declaration, Tree));
807 Set_Next_Declarative_Item
809 To => Next_Declarative_Item (Declaration, Tree));
813 Previous := Declaration;
816 Declaration := Next_Declarative_Item (Declaration, Tree);
822 if Directory_Last /= 0 then
823 Output_Name (1 .. Output_Name_Last - Directory_Last) :=
824 Output_Name (Directory_Last + 1 .. Output_Name_Last);
825 Output_Name_Last := Output_Name_Last - Directory_Last;
828 -- Get the project name id
830 Name_Len := Output_Name_Last;
831 Name_Buffer (1 .. Name_Len) := Output_Name (1 .. Name_Len);
832 Output_Name_Id := Name_Find;
834 -- Create the project naming file name
836 Project_Naming_Last := Output_Name_Last;
837 Project_Naming_File_Name (1 .. Project_Naming_Last) :=
838 Output_Name (1 .. Project_Naming_Last);
839 Project_Naming_File_Name
840 (Project_Naming_Last + 1 ..
841 Project_Naming_Last + Naming_File_Suffix'Length) :=
843 Project_Naming_Last :=
844 Project_Naming_Last + Naming_File_Suffix'Length;
846 -- Get the project naming id
848 Name_Len := Project_Naming_Last;
849 Name_Buffer (1 .. Name_Len) :=
850 Project_Naming_File_Name (1 .. Name_Len);
851 Project_Naming_Id := Name_Find;
853 Project_Naming_File_Name
854 (Project_Naming_Last + 1 ..
855 Project_Naming_Last + Project_File_Extension'Length) :=
856 Project_File_Extension;
857 Project_Naming_Last :=
858 Project_Naming_Last + Project_File_Extension'Length;
860 -- Create the source list file name
862 Source_List_Last := Output_Name_Last;
863 Source_List_Path (1 .. Source_List_Last) :=
864 Output_Name (1 .. Source_List_Last);
866 (Source_List_Last + 1 ..
867 Source_List_Last + Source_List_File_Suffix'Length) :=
868 Source_List_File_Suffix;
869 Source_List_Last := Source_List_Last + Source_List_File_Suffix'Length;
871 -- Add the project file extension to the project name
874 (Output_Name_Last + 1 ..
875 Output_Name_Last + Project_File_Extension'Length) :=
876 Project_File_Extension;
877 Output_Name_Last := Output_Name_Last + Project_File_Extension'Length;
880 -- Change the current directory to the directory of the project file,
881 -- if any directory information is specified.
883 if Directory_Last /= 0 then
885 Change_Dir (Path_Name (1 .. Directory_Last));
887 when Directory_Error =>
889 ("unknown directory """,
890 Path_Name (1 .. Directory_Last),
897 -- Delete the source list file, if it already exists
903 (Source_List_Path (1 .. Source_List_Last),
907 -- And create a new source list file.
908 -- Fail if file cannot be created.
910 Source_List_FD := Create_New_File
911 (Name => Source_List_Path (1 .. Source_List_Last),
914 if Source_List_FD = Invalid_FD then
916 ("cannot create file """,
917 Source_List_Path (1 .. Source_List_Last),
922 -- Compile the regular expressions. Fails immediately if any of
923 -- the specified strings is in error.
925 for Index in Excluded_Expressions'Range loop
927 Output.Write_Str ("Excluded pattern: """);
928 Output.Write_Str (Excluded_Patterns (Index).all);
929 Output.Write_Line ("""");
933 Excluded_Expressions (Index) :=
934 Compile (Pattern => Excluded_Patterns (Index).all, Glob => True);
936 when Error_In_Regexp =>
938 ("invalid regular expression """,
939 Excluded_Patterns (Index).all,
944 for Index in Foreign_Expressions'Range loop
946 Output.Write_Str ("Foreign pattern: """);
947 Output.Write_Str (Foreign_Patterns (Index).all);
948 Output.Write_Line ("""");
952 Foreign_Expressions (Index) :=
953 Compile (Pattern => Foreign_Patterns (Index).all, Glob => True);
955 when Error_In_Regexp =>
957 ("invalid regular expression """,
958 Foreign_Patterns (Index).all,
963 for Index in Regular_Expressions'Range loop
965 Output.Write_Str ("Pattern: """);
966 Output.Write_Str (Name_Patterns (Index).all);
967 Output.Write_Line ("""");
971 Regular_Expressions (Index) :=
972 Compile (Pattern => Name_Patterns (Index).all, Glob => True);
975 when Error_In_Regexp =>
977 ("invalid regular expression """,
978 Name_Patterns (Index).all,
984 if Opt.Verbose_Mode then
985 Output.Write_Str ("Naming project file name is """);
987 (Project_Naming_File_Name (1 .. Project_Naming_Last));
988 Output.Write_Line ("""");
991 -- If there were no already existing project file, or if the parsing
992 -- was unsuccessful, create an empty project node with the correct
993 -- name and its project declaration node.
995 if Project_Node = Empty_Node then
997 Default_Project_Node (Of_Kind => N_Project, In_Tree => Tree);
998 Set_Name_Of (Project_Node, Tree, To => Output_Name_Id);
999 Set_Project_Declaration_Of
1000 (Project_Node, Tree,
1001 To => Default_Project_Node
1002 (Of_Kind => N_Project_Declaration, In_Tree => Tree));
1006 -- Create the naming project node, and add an attribute declaration
1007 -- for Source_Files as an empty list, to indicate there are no
1008 -- sources in the naming project.
1010 Project_Naming_Node :=
1011 Default_Project_Node (Of_Kind => N_Project, In_Tree => Tree);
1012 Set_Name_Of (Project_Naming_Node, Tree, To => Project_Naming_Id);
1013 Project_Naming_Decl :=
1014 Default_Project_Node
1015 (Of_Kind => N_Project_Declaration, In_Tree => Tree);
1016 Set_Project_Declaration_Of
1017 (Project_Naming_Node, Tree, Project_Naming_Decl);
1019 Default_Project_Node
1020 (Of_Kind => N_Package_Declaration, In_Tree => Tree);
1021 Set_Name_Of (Naming_Package, Tree, To => Name_Naming);
1024 Decl_Item : constant Project_Node_Id :=
1025 Default_Project_Node
1026 (Of_Kind => N_Declarative_Item, In_Tree => Tree);
1028 Attribute : constant Project_Node_Id :=
1029 Default_Project_Node
1030 (Of_Kind => N_Attribute_Declaration,
1032 And_Expr_Kind => List);
1034 Expression : constant Project_Node_Id :=
1035 Default_Project_Node
1036 (Of_Kind => N_Expression,
1038 And_Expr_Kind => List);
1040 Term : constant Project_Node_Id :=
1041 Default_Project_Node
1044 And_Expr_Kind => List);
1046 Empty_List : constant Project_Node_Id :=
1047 Default_Project_Node
1048 (Of_Kind => N_Literal_String_List,
1052 Set_First_Declarative_Item_Of
1053 (Project_Naming_Decl, Tree, To => Decl_Item);
1054 Set_Next_Declarative_Item (Decl_Item, Tree, Naming_Package);
1055 Set_Current_Item_Node (Decl_Item, Tree, To => Attribute);
1056 Set_Name_Of (Attribute, Tree, To => Name_Source_Files);
1057 Set_Expression_Of (Attribute, Tree, To => Expression);
1058 Set_First_Term (Expression, Tree, To => Term);
1059 Set_Current_Term (Term, Tree, To => Empty_List);
1062 -- Add a with clause on the naming project in the main project
1065 With_Clause : constant Project_Node_Id :=
1066 Default_Project_Node
1067 (Of_Kind => N_With_Clause, In_Tree => Tree);
1070 Set_Next_With_Clause_Of
1072 To => First_With_Clause_Of (Project_Node, Tree));
1073 Set_First_With_Clause_Of (Project_Node, Tree, To => With_Clause);
1074 Set_Name_Of (With_Clause, Tree, To => Project_Naming_Id);
1076 -- We set the project node to something different than
1077 -- Empty_Node, so that Prj.PP does not generate a limited
1080 Set_Project_Node_Of (With_Clause, Tree, Non_Empty_Node);
1082 Name_Len := Project_Naming_Last;
1083 Name_Buffer (1 .. Name_Len) :=
1084 Project_Naming_File_Name (1 .. Project_Naming_Last);
1085 Set_String_Value_Of (With_Clause, Tree, To => Name_Find);
1088 Project_Declaration := Project_Declaration_Of (Project_Node, Tree);
1090 -- Add a renaming declaration for package Naming in the main project
1093 Decl_Item : constant Project_Node_Id :=
1094 Default_Project_Node
1095 (Of_Kind => N_Declarative_Item,
1098 Naming : constant Project_Node_Id :=
1099 Default_Project_Node
1100 (Of_Kind => N_Package_Declaration,
1104 Set_Next_Declarative_Item
1106 To => First_Declarative_Item_Of (Project_Declaration, Tree));
1107 Set_First_Declarative_Item_Of
1108 (Project_Declaration, Tree, To => Decl_Item);
1109 Set_Current_Item_Node (Decl_Item, Tree, To => Naming);
1110 Set_Name_Of (Naming, Tree, To => Name_Naming);
1111 Set_Project_Of_Renamed_Package_Of
1112 (Naming, Tree, To => Project_Naming_Node);
1115 -- Add an attribute declaration for Source_Dirs, initialized as an
1116 -- empty list. Directories will be added as they are read from the
1117 -- directory list file.
1120 Decl_Item : constant Project_Node_Id :=
1121 Default_Project_Node
1122 (Of_Kind => N_Declarative_Item,
1125 Attribute : constant Project_Node_Id :=
1126 Default_Project_Node
1127 (Of_Kind => N_Attribute_Declaration,
1129 And_Expr_Kind => List);
1131 Expression : constant Project_Node_Id :=
1132 Default_Project_Node
1133 (Of_Kind => N_Expression,
1135 And_Expr_Kind => List);
1137 Term : constant Project_Node_Id :=
1138 Default_Project_Node
1139 (Of_Kind => N_Term, In_Tree => Tree,
1140 And_Expr_Kind => List);
1143 Set_Next_Declarative_Item
1145 To => First_Declarative_Item_Of (Project_Declaration, Tree));
1146 Set_First_Declarative_Item_Of
1147 (Project_Declaration, Tree, To => Decl_Item);
1148 Set_Current_Item_Node (Decl_Item, Tree, To => Attribute);
1149 Set_Name_Of (Attribute, Tree, To => Name_Source_Dirs);
1150 Set_Expression_Of (Attribute, Tree, To => Expression);
1151 Set_First_Term (Expression, Tree, To => Term);
1153 Default_Project_Node
1154 (Of_Kind => N_Literal_String_List,
1156 And_Expr_Kind => List);
1157 Set_Current_Term (Term, Tree, To => Source_Dirs_List);
1160 -- Add an attribute declaration for Source_List_File with the
1161 -- source list file name that will be created.
1164 Decl_Item : constant Project_Node_Id :=
1165 Default_Project_Node
1166 (Of_Kind => N_Declarative_Item,
1169 Attribute : constant Project_Node_Id :=
1170 Default_Project_Node
1171 (Of_Kind => N_Attribute_Declaration,
1173 And_Expr_Kind => Single);
1175 Expression : constant Project_Node_Id :=
1176 Default_Project_Node
1177 (Of_Kind => N_Expression,
1179 And_Expr_Kind => Single);
1181 Term : constant Project_Node_Id :=
1182 Default_Project_Node
1185 And_Expr_Kind => Single);
1187 Value : constant Project_Node_Id :=
1188 Default_Project_Node
1189 (Of_Kind => N_Literal_String,
1191 And_Expr_Kind => Single);
1194 Set_Next_Declarative_Item
1196 To => First_Declarative_Item_Of (Project_Declaration, Tree));
1197 Set_First_Declarative_Item_Of
1198 (Project_Declaration, Tree, To => Decl_Item);
1199 Set_Current_Item_Node (Decl_Item, Tree, To => Attribute);
1200 Set_Name_Of (Attribute, Tree, To => Name_Source_List_File);
1201 Set_Expression_Of (Attribute, Tree, To => Expression);
1202 Set_First_Term (Expression, Tree, To => Term);
1203 Set_Current_Term (Term, Tree, To => Value);
1204 Name_Len := Source_List_Last;
1205 Name_Buffer (1 .. Name_Len) :=
1206 Source_List_Path (1 .. Source_List_Last);
1207 Set_String_Value_Of (Value, Tree, To => Name_Find);
1211 -- Process each directory
1213 for Index in Directories'Range loop
1216 Dir_Name : constant String := Directories (Index).all;
1217 Last : Natural := Dir_Name'Last;
1218 Recursively : Boolean := False;
1221 if Dir_Name'Length >= 4
1222 and then (Dir_Name (Last - 2 .. Last) = "/**")
1225 Recursively := True;
1228 if Project_File then
1230 -- Add the directory in the list for attribute Source_Dirs
1233 Expression : constant Project_Node_Id :=
1234 Default_Project_Node
1235 (Of_Kind => N_Expression,
1237 And_Expr_Kind => Single);
1239 Term : constant Project_Node_Id :=
1240 Default_Project_Node
1243 And_Expr_Kind => Single);
1245 Value : constant Project_Node_Id :=
1246 Default_Project_Node
1247 (Of_Kind => N_Literal_String,
1249 And_Expr_Kind => Single);
1252 if Current_Source_Dir = Empty_Node then
1253 Set_First_Expression_In_List
1254 (Source_Dirs_List, Tree, To => Expression);
1256 Set_Next_Expression_In_List
1257 (Current_Source_Dir, Tree, To => Expression);
1260 Current_Source_Dir := Expression;
1261 Set_First_Term (Expression, Tree, To => Term);
1262 Set_Current_Term (Term, Tree, To => Value);
1263 Name_Len := Dir_Name'Length;
1264 Name_Buffer (1 .. Name_Len) := Dir_Name;
1265 Set_String_Value_Of (Value, Tree, To => Name_Find);
1269 Process_Directory (Dir_Name (Dir_Name'First .. Last), Recursively);
1274 if Project_File then
1275 Close (Source_List_FD);
1282 -- Delete the file if it already exists
1285 (Path_Name (Directory_Last + 1 .. Path_Last),
1286 Success => Discard);
1290 if Opt.Verbose_Mode then
1291 Output.Write_Str ("Creating new file """);
1292 Output.Write_Str (Path_Name (Directory_Last + 1 .. Path_Last));
1293 Output.Write_Line ("""");
1296 Output_FD := Create_New_File
1297 (Path_Name (Directory_Last + 1 .. Path_Last),
1300 -- Fails if project file cannot be created
1302 if Output_FD = Invalid_FD then
1304 ("cannot create new """, Path_Name (1 .. Path_Last), """");
1307 if Project_File then
1309 -- Output the project file
1312 (Project_Node, Tree,
1313 W_Char => Write_A_Char'Access,
1314 W_Eol => Write_Eol'Access,
1315 W_Str => Write_A_String'Access,
1316 Backward_Compatibility => False);
1319 -- Delete the naming project file if it already exists
1322 (Project_Naming_File_Name (1 .. Project_Naming_Last),
1323 Success => Discard);
1327 if Opt.Verbose_Mode then
1328 Output.Write_Str ("Creating new naming project file """);
1329 Output.Write_Str (Project_Naming_File_Name
1330 (1 .. Project_Naming_Last));
1331 Output.Write_Line ("""");
1334 Output_FD := Create_New_File
1335 (Project_Naming_File_Name (1 .. Project_Naming_Last),
1338 -- Fails if naming project file cannot be created
1340 if Output_FD = Invalid_FD then
1342 ("cannot create new """,
1343 Project_Naming_File_Name (1 .. Project_Naming_Last),
1347 -- Output the naming project file
1350 (Project_Naming_Node, Tree,
1351 W_Char => Write_A_Char'Access,
1352 W_Eol => Write_Eol'Access,
1353 W_Str => Write_A_String'Access,
1354 Backward_Compatibility => False);
1358 -- Write to the output file each entry in the SFN_Pragmas table
1359 -- as an pragma Source_File_Name.
1361 for Index in 1 .. SFN_Pragmas.Last loop
1362 Write_A_String ("pragma Source_File_Name");
1364 Write_A_String (" (");
1366 (Get_Name_String (SFN_Pragmas.Table (Index).Unit));
1367 Write_A_String (",");
1370 if SFN_Pragmas.Table (Index).Spec then
1371 Write_A_String (" Spec_File_Name => """);
1374 Write_A_String (" Body_File_Name => """);
1378 (Get_Name_String (SFN_Pragmas.Table (Index).File));
1380 Write_A_String ("""");
1382 if SFN_Pragmas.Table (Index).Index /= 0 then
1383 Write_A_String (", Index =>");
1384 Write_A_String (SFN_Pragmas.Table (Index).Index'Img);
1387 Write_A_String (");");
1400 procedure Write_A_Char (C : Character) is
1402 Write_A_String ((1 => C));
1409 procedure Write_Eol is
1411 Write_A_String ((1 => ASCII.LF));
1414 --------------------
1415 -- Write_A_String --
1416 --------------------
1418 procedure Write_A_String (S : String) is
1419 Str : String (1 .. S'Length);
1422 if S'Length > 0 then
1425 if Write (Output_FD, Str (1)'Address, Str'Length) /= Str'Length then
1426 Prj.Com.Fail ("disk full");