1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2001-2009, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 ------------------------------------------------------------------------------
28 with Osint; use Osint;
29 with Output; use Output;
30 with Prj.Com; use Prj.Com;
33 package body Prj.Env is
35 -----------------------
36 -- Local Subprograms --
37 -----------------------
40 (Source_Dirs : String_List_Id;
41 In_Tree : Project_Tree_Ref);
42 -- Add to Ada_Path_Buffer all the source directories in string list
43 -- Source_Dirs, if any. Increment Ada_Path_Length.
45 procedure Add_To_Path (Dir : String; In_Tree : Project_Tree_Ref);
46 -- If Dir is not already in the global variable Ada_Path_Buffer, add it.
47 -- Increment Ada_Path_Length.
48 -- If Ada_Path_Length /= 0, prepend a Path_Separator character to
51 procedure Add_To_Source_Path
52 (Source_Dirs : String_List_Id; In_Tree : Project_Tree_Ref);
53 -- Add to Ada_Path_B all the source directories in string list
54 -- Source_Dirs, if any. Increment Ada_Path_Length.
56 procedure Add_To_Object_Path
57 (Object_Dir : Path_Name_Type;
58 In_Tree : Project_Tree_Ref);
59 -- Add Object_Dir to object path table. Make sure it is not duplicate
60 -- and it is the last one in the current table.
62 procedure Set_Path_File_Var (Name : String; Value : String);
63 -- Call Setenv, after calling To_Host_File_Spec
65 function Ultimate_Extension_Of
66 (Project : Project_Id) return Project_Id;
67 -- Return a project that is either Project or an extended ancestor of
68 -- Project that itself is not extended.
70 ----------------------
71 -- Ada_Include_Path --
72 ----------------------
74 function Ada_Include_Path
75 (Project : Project_Id;
76 In_Tree : Project_Tree_Ref) return String_Access
78 procedure Add (Project : Project_Id; Dummy : in out Boolean);
79 -- Add source dirs of Project to the path
85 procedure Add (Project : Project_Id; Dummy : in out Boolean) is
86 pragma Unreferenced (Dummy);
88 Add_To_Path (Project.Source_Dirs, In_Tree);
91 procedure For_All_Projects is
92 new For_Every_Project_Imported (Boolean, Add);
93 Dummy : Boolean := False;
95 -- Start of processing for Ada_Include_Path
98 -- If it is the first time we call this function for
99 -- this project, compute the source path
101 if Project.Ada_Include_Path = null then
102 In_Tree.Private_Part.Ada_Path_Length := 0;
103 For_All_Projects (Project, Dummy);
105 Project.Ada_Include_Path :=
107 (In_Tree.Private_Part.Ada_Path_Buffer
108 (1 .. In_Tree.Private_Part.Ada_Path_Length));
111 return Project.Ada_Include_Path;
112 end Ada_Include_Path;
114 ----------------------
115 -- Ada_Include_Path --
116 ----------------------
118 function Ada_Include_Path
119 (Project : Project_Id;
120 In_Tree : Project_Tree_Ref;
121 Recursive : Boolean) return String
125 return Ada_Include_Path (Project, In_Tree).all;
127 In_Tree.Private_Part.Ada_Path_Length := 0;
128 Add_To_Path (Project.Source_Dirs, In_Tree);
130 In_Tree.Private_Part.Ada_Path_Buffer
131 (1 .. In_Tree.Private_Part.Ada_Path_Length);
133 end Ada_Include_Path;
135 ----------------------
136 -- Ada_Objects_Path --
137 ----------------------
139 function Ada_Objects_Path
140 (Project : Project_Id;
141 In_Tree : Project_Tree_Ref;
142 Including_Libraries : Boolean := True) return String_Access
144 procedure Add (Project : Project_Id; Dummy : in out Boolean);
145 -- Add all the object directories of a project to the path
151 procedure Add (Project : Project_Id; Dummy : in out Boolean) is
152 pragma Unreferenced (Dummy);
153 Path : constant Path_Name_Type :=
156 Including_Libraries => Including_Libraries,
157 Only_If_Ada => False);
159 if Path /= No_Path then
160 Add_To_Path (Get_Name_String (Path), In_Tree);
164 procedure For_All_Projects is
165 new For_Every_Project_Imported (Boolean, Add);
166 Dummy : Boolean := False;
168 -- Start of processing for Ada_Objects_Path
171 -- If it is the first time we call this function for
172 -- this project, compute the objects path
174 if Project.Ada_Objects_Path = null then
175 In_Tree.Private_Part.Ada_Path_Length := 0;
176 For_All_Projects (Project, Dummy);
178 Project.Ada_Objects_Path :=
180 (In_Tree.Private_Part.Ada_Path_Buffer
181 (1 .. In_Tree.Private_Part.Ada_Path_Length));
184 return Project.Ada_Objects_Path;
185 end Ada_Objects_Path;
187 ------------------------
188 -- Add_To_Object_Path --
189 ------------------------
191 procedure Add_To_Object_Path
192 (Object_Dir : Path_Name_Type; In_Tree : Project_Tree_Ref)
195 -- Check if the directory is already in the table
197 for Index in Object_Path_Table.First ..
198 Object_Path_Table.Last (In_Tree.Private_Part.Object_Paths)
201 -- If it is, remove it, and add it as the last one
203 if In_Tree.Private_Part.Object_Paths.Table (Index) = Object_Dir then
204 for Index2 in Index + 1 ..
205 Object_Path_Table.Last
206 (In_Tree.Private_Part.Object_Paths)
208 In_Tree.Private_Part.Object_Paths.Table (Index2 - 1) :=
209 In_Tree.Private_Part.Object_Paths.Table (Index2);
212 In_Tree.Private_Part.Object_Paths.Table
213 (Object_Path_Table.Last (In_Tree.Private_Part.Object_Paths)) :=
219 -- The directory is not already in the table, add it
221 Object_Path_Table.Increment_Last (In_Tree.Private_Part.Object_Paths);
222 In_Tree.Private_Part.Object_Paths.Table
223 (Object_Path_Table.Last (In_Tree.Private_Part.Object_Paths)) :=
225 end Add_To_Object_Path;
231 procedure Add_To_Path
232 (Source_Dirs : String_List_Id;
233 In_Tree : Project_Tree_Ref)
235 Current : String_List_Id := Source_Dirs;
236 Source_Dir : String_Element;
238 while Current /= Nil_String loop
239 Source_Dir := In_Tree.String_Elements.Table (Current);
240 Add_To_Path (Get_Name_String (Source_Dir.Display_Value), In_Tree);
241 Current := Source_Dir.Next;
245 procedure Add_To_Path (Dir : String; In_Tree : Project_Tree_Ref) is
247 New_Buffer : String_Access;
250 function Is_Present (Path : String; Dir : String) return Boolean;
251 -- Return True if Dir is part of Path
257 function Is_Present (Path : String; Dir : String) return Boolean is
258 Last : constant Integer := Path'Last - Dir'Length + 1;
261 for J in Path'First .. Last loop
263 -- Note: the order of the conditions below is important, since
264 -- it ensures a minimal number of string comparisons.
267 or else Path (J - 1) = Path_Separator)
269 (J + Dir'Length > Path'Last
270 or else Path (J + Dir'Length) = Path_Separator)
271 and then Dir = Path (J .. J + Dir'Length - 1)
280 -- Start of processing for Add_To_Path
283 if Is_Present (In_Tree.Private_Part.Ada_Path_Buffer
284 (1 .. In_Tree.Private_Part.Ada_Path_Length),
288 -- Dir is already in the path, nothing to do
293 Min_Len := In_Tree.Private_Part.Ada_Path_Length + Dir'Length;
295 if In_Tree.Private_Part.Ada_Path_Length > 0 then
297 -- Add 1 for the Path_Separator character
299 Min_Len := Min_Len + 1;
302 -- If Ada_Path_Buffer is too small, increase it
304 Len := In_Tree.Private_Part.Ada_Path_Buffer'Last;
306 if Len < Min_Len then
309 exit when Len >= Min_Len;
312 New_Buffer := new String (1 .. Len);
313 New_Buffer (1 .. In_Tree.Private_Part.Ada_Path_Length) :=
314 In_Tree.Private_Part.Ada_Path_Buffer
315 (1 .. In_Tree.Private_Part.Ada_Path_Length);
316 Free (In_Tree.Private_Part.Ada_Path_Buffer);
317 In_Tree.Private_Part.Ada_Path_Buffer := New_Buffer;
320 if In_Tree.Private_Part.Ada_Path_Length > 0 then
321 In_Tree.Private_Part.Ada_Path_Length :=
322 In_Tree.Private_Part.Ada_Path_Length + 1;
323 In_Tree.Private_Part.Ada_Path_Buffer
324 (In_Tree.Private_Part.Ada_Path_Length) := Path_Separator;
327 In_Tree.Private_Part.Ada_Path_Buffer
328 (In_Tree.Private_Part.Ada_Path_Length + 1 ..
329 In_Tree.Private_Part.Ada_Path_Length + Dir'Length) := Dir;
330 In_Tree.Private_Part.Ada_Path_Length :=
331 In_Tree.Private_Part.Ada_Path_Length + Dir'Length;
334 ------------------------
335 -- Add_To_Source_Path --
336 ------------------------
338 procedure Add_To_Source_Path
339 (Source_Dirs : String_List_Id; In_Tree : Project_Tree_Ref)
341 Current : String_List_Id := Source_Dirs;
342 Source_Dir : String_Element;
346 -- Add each source directory
348 while Current /= Nil_String loop
349 Source_Dir := In_Tree.String_Elements.Table (Current);
352 -- Check if the source directory is already in the table
354 for Index in Source_Path_Table.First ..
355 Source_Path_Table.Last
356 (In_Tree.Private_Part.Source_Paths)
358 -- If it is already, no need to add it
360 if In_Tree.Private_Part.Source_Paths.Table (Index) =
369 Source_Path_Table.Increment_Last
370 (In_Tree.Private_Part.Source_Paths);
371 In_Tree.Private_Part.Source_Paths.Table
372 (Source_Path_Table.Last (In_Tree.Private_Part.Source_Paths)) :=
376 -- Next source directory
378 Current := Source_Dir.Next;
380 end Add_To_Source_Path;
382 --------------------------------
383 -- Create_Config_Pragmas_File --
384 --------------------------------
386 procedure Create_Config_Pragmas_File
387 (For_Project : Project_Id;
388 In_Tree : Project_Tree_Ref)
390 type Naming_Id is new Nat;
391 package Naming_Table is new GNAT.Dynamic_Tables
392 (Table_Component_Type => Lang_Naming_Data,
393 Table_Index_Type => Naming_Id,
394 Table_Low_Bound => 1,
396 Table_Increment => 100);
397 Default_Naming : constant Naming_Id := Naming_Table.First;
398 Namings : Naming_Table.Instance;
399 -- Table storing the naming data for gnatmake/gprmake
401 File_Name : Path_Name_Type := No_Path;
402 File : File_Descriptor := Invalid_FD;
404 Current_Unit : Unit_Index := Units_Htable.Get_First (In_Tree.Units_HT);
406 Current_Naming : Naming_Id;
411 procedure Check (Project : Project_Id; State : in out Integer);
412 -- Recursive procedure that put in the config pragmas file any non
413 -- standard naming schemes, if it is not already in the file, then call
414 -- itself for any imported project.
416 procedure Check_Temp_File;
417 -- Check that a temporary file has been opened.
418 -- If not, create one, and put its name in the project data,
419 -- with the indication that it is a temporary file.
422 (Unit_Name : Name_Id;
423 File_Name : File_Name_Type;
424 Unit_Kind : Spec_Or_Body;
426 -- Put an SFN pragma in the temporary file
428 procedure Put (File : File_Descriptor; S : String);
429 procedure Put_Line (File : File_Descriptor; S : String);
430 -- Output procedures, analogous to normal Text_IO procs of same name
436 procedure Check (Project : Project_Id; State : in out Integer) is
437 pragma Unreferenced (State);
438 Lang : constant Language_Ptr :=
439 Get_Language_From_Name (Project, "ada");
440 Naming : Lang_Naming_Data;
443 if Current_Verbosity = High then
444 Write_Str ("Checking project file """);
445 Write_Str (Namet.Get_Name_String (Project.Name));
451 if Current_Verbosity = High then
452 Write_Str ("Languages does not contain Ada, nothing to do");
458 Naming := Lang.Config.Naming_Data;
460 -- Is the naming scheme of this project one that we know?
462 Current_Naming := Default_Naming;
463 while Current_Naming <= Naming_Table.Last (Namings)
464 and then Namings.Table (Current_Naming).Dot_Replacement =
465 Naming.Dot_Replacement
466 and then Namings.Table (Current_Naming).Casing =
468 and then Namings.Table (Current_Naming).Separate_Suffix =
469 Naming.Separate_Suffix
471 Current_Naming := Current_Naming + 1;
474 -- If we don't know it, add it
476 if Current_Naming > Naming_Table.Last (Namings) then
477 Naming_Table.Increment_Last (Namings);
478 Namings.Table (Naming_Table.Last (Namings)) := Naming;
480 -- We need a temporary file to be created
484 -- Put the SFN pragmas for the naming scheme
489 (File, "pragma Source_File_Name_Project");
491 (File, " (Spec_File_Name => ""*" &
492 Get_Name_String (Naming.Spec_Suffix) & """,");
494 (File, " Casing => " &
495 Image (Naming.Casing) & ",");
497 (File, " Dot_Replacement => """ &
498 Get_Name_String (Naming.Dot_Replacement) & """);");
503 (File, "pragma Source_File_Name_Project");
505 (File, " (Body_File_Name => ""*" &
506 Get_Name_String (Naming.Body_Suffix) & """,");
508 (File, " Casing => " &
509 Image (Naming.Casing) & ",");
511 (File, " Dot_Replacement => """ &
512 Get_Name_String (Naming.Dot_Replacement) &
515 -- and maybe separate
517 if Naming.Body_Suffix /= Naming.Separate_Suffix then
518 Put_Line (File, "pragma Source_File_Name_Project");
520 (File, " (Subunit_File_Name => ""*" &
521 Get_Name_String (Naming.Separate_Suffix) & """,");
523 (File, " Casing => " &
524 Image (Naming.Casing) & ",");
526 (File, " Dot_Replacement => """ &
527 Get_Name_String (Naming.Dot_Replacement) &
533 ---------------------
534 -- Check_Temp_File --
535 ---------------------
537 procedure Check_Temp_File is
539 if File = Invalid_FD then
540 Tempdir.Create_Temp_File (File, Name => File_Name);
542 if File = Invalid_FD then
544 ("unable to create temporary configuration pragmas file");
547 Record_Temp_File (File_Name);
549 if Opt.Verbose_Mode then
550 Write_Str ("Creating temp file """);
551 Write_Str (Get_Name_String (File_Name));
563 (Unit_Name : Name_Id;
564 File_Name : File_Name_Type;
565 Unit_Kind : Spec_Or_Body;
569 -- A temporary file needs to be open
573 -- Put the pragma SFN for the unit kind (spec or body)
575 Put (File, "pragma Source_File_Name_Project (");
576 Put (File, Namet.Get_Name_String (Unit_Name));
578 if Unit_Kind = Spec then
579 Put (File, ", Spec_File_Name => """);
581 Put (File, ", Body_File_Name => """);
584 Put (File, Namet.Get_Name_String (File_Name));
588 Put (File, ", Index =>");
589 Put (File, Index'Img);
592 Put_Line (File, ");");
595 procedure Put (File : File_Descriptor; S : String) is
599 Last := Write (File, S (S'First)'Address, S'Length);
601 if Last /= S'Length then
603 ("Disk full when creating " & Get_Name_String (File_Name));
606 if Current_Verbosity = High then
615 procedure Put_Line (File : File_Descriptor; S : String) is
616 S0 : String (1 .. S'Length + 1);
620 -- Add an ASCII.LF to the string. As this config file is supposed to
621 -- be used only by the compiler, we don't care about the characters
622 -- for the end of line. In fact we could have put a space, but
623 -- it is more convenient to be able to read gnat.adc during
624 -- development, for which the ASCII.LF is fine.
626 S0 (1 .. S'Length) := S;
627 S0 (S0'Last) := ASCII.LF;
628 Last := Write (File, S0'Address, S0'Length);
630 if Last /= S'Length + 1 then
632 ("Disk full when creating " & Get_Name_String (File_Name));
635 if Current_Verbosity = High then
640 procedure Check_Imported_Projects is new For_Every_Project_Imported
642 Dummy : Integer := 0;
644 -- Start of processing for Create_Config_Pragmas_File
647 if not For_Project.Config_Checked then
649 Naming_Table.Init (Namings);
651 -- Check the naming schemes
653 Check_Imported_Projects (For_Project, Dummy, Imported_First => False);
655 -- Visit all the units and process those that need an SFN pragma
657 while Current_Unit /= No_Unit_Index loop
658 if Current_Unit.File_Names (Spec) /= null
659 and then Current_Unit.File_Names (Spec).Naming_Exception
660 and then not Current_Unit.File_Names (Spec).Locally_Removed
662 Put (Current_Unit.Name,
663 Current_Unit.File_Names (Spec).File,
665 Current_Unit.File_Names (Spec).Index);
668 if Current_Unit.File_Names (Impl) /= null
669 and then Current_Unit.File_Names (Impl).Naming_Exception
670 and then not Current_Unit.File_Names (Impl).Locally_Removed
672 Put (Current_Unit.Name,
673 Current_Unit.File_Names (Impl).File,
675 Current_Unit.File_Names (Impl).Index);
678 Current_Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
681 -- If there are no non standard naming scheme, issue the GNAT
682 -- standard naming scheme. This will tell the compiler that
683 -- a project file is used and will forbid any pragma SFN.
685 if File = Invalid_FD then
688 Put_Line (File, "pragma Source_File_Name_Project");
689 Put_Line (File, " (Spec_File_Name => ""*.ads"",");
690 Put_Line (File, " Dot_Replacement => ""-"",");
691 Put_Line (File, " Casing => lowercase);");
693 Put_Line (File, "pragma Source_File_Name_Project");
694 Put_Line (File, " (Body_File_Name => ""*.adb"",");
695 Put_Line (File, " Dot_Replacement => ""-"",");
696 Put_Line (File, " Casing => lowercase);");
699 -- Close the temporary file
701 GNAT.OS_Lib.Close (File, Status);
705 ("Disk full when creating " & Get_Name_String (File_Name));
708 if Opt.Verbose_Mode then
709 Write_Str ("Closing configuration file """);
710 Write_Str (Get_Name_String (File_Name));
714 For_Project.Config_File_Name := File_Name;
715 For_Project.Config_File_Temp := True;
716 For_Project.Config_Checked := True;
718 end Create_Config_Pragmas_File;
724 procedure Create_Mapping (In_Tree : Project_Tree_Ref) is
726 Iter : Source_Iterator;
731 Iter := For_Each_Source (In_Tree);
733 Data := Element (Iter);
734 exit when Data = No_Source;
736 if Data.Unit /= No_Unit_Index then
737 if Data.Locally_Removed then
738 Fmap.Add_Forbidden_File_Name (Data.File);
741 (Unit_Name => Unit_Name_Type (Data.Unit.Name),
742 File_Name => Data.File,
743 Path_Name => File_Name_Type (Data.Path.Name));
751 -------------------------
752 -- Create_Mapping_File --
753 -------------------------
755 procedure Create_Mapping_File
756 (Project : Project_Id;
758 In_Tree : Project_Tree_Ref;
759 Name : out Path_Name_Type)
761 File : File_Descriptor := Invalid_FD;
764 procedure Put_Name_Buffer;
765 -- Put the line contained in the Name_Buffer in the mapping file
767 procedure Process (Project : Project_Id; State : in out Integer);
768 -- Generate the mapping file for Project (not recursively)
774 procedure Put_Name_Buffer is
778 Name_Len := Name_Len + 1;
779 Name_Buffer (Name_Len) := ASCII.LF;
780 Last := Write (File, Name_Buffer (1)'Address, Name_Len);
782 if Current_Verbosity = High then
783 Write_Str ("Mapping file: " & Name_Buffer (1 .. Name_Len));
786 if Last /= Name_Len then
787 Prj.Com.Fail ("Disk full, cannot write mapping file");
795 procedure Process (Project : Project_Id; State : in out Integer) is
796 pragma Unreferenced (State);
798 Suffix : File_Name_Type;
799 Iter : Source_Iterator;
802 Iter := For_Each_Source (In_Tree, Project, Language => Language);
805 Source := Prj.Element (Iter);
806 exit when Source = No_Source;
808 if Source.Replaced_By = No_Source
809 and then Source.Path.Name /= No_Path
811 (Source.Language.Config.Kind = File_Based
812 or else Source.Unit /= No_Unit_Index)
814 if Source.Unit /= No_Unit_Index then
815 Get_Name_String (Source.Unit.Name);
817 if Get_Mode = Ada_Only then
819 -- ??? Mapping_Spec_Suffix could be set in the case of
822 Add_Char_To_Name_Buffer ('%');
824 if Source.Kind = Spec then
825 Add_Char_To_Name_Buffer ('s');
827 Add_Char_To_Name_Buffer ('b');
834 Source.Language.Config.Mapping_Spec_Suffix;
837 Source.Language.Config.Mapping_Body_Suffix;
840 if Suffix /= No_File then
841 Add_Str_To_Name_Buffer
842 (Get_Name_String (Suffix));
849 Get_Name_String (Source.File);
852 if Source.Locally_Removed then
854 Name_Buffer (1) := '/';
856 Get_Name_String (Source.Path.Name);
866 procedure For_Every_Imported_Project is new
867 For_Every_Project_Imported (State => Integer, Action => Process);
869 Dummy : Integer := 0;
871 -- Start of processing for Create_Mapping_File
875 -- Create the temporary file
877 Tempdir.Create_Temp_File (File, Name => Name);
879 if File = Invalid_FD then
880 Prj.Com.Fail ("unable to create temporary mapping file");
883 Record_Temp_File (Name);
885 if Opt.Verbose_Mode then
886 Write_Str ("Creating temp mapping file """);
887 Write_Str (Get_Name_String (Name));
892 For_Every_Imported_Project (Project, Dummy);
893 GNAT.OS_Lib.Close (File, Status);
897 -- We were able to create the temporary file, so there is no problem
898 -- of protection. However, we are not able to close it, so there must
899 -- be a capacity problem that we express using "disk full".
901 Prj.Com.Fail ("disk full, could not write mapping file");
903 end Create_Mapping_File;
905 --------------------------
906 -- Create_New_Path_File --
907 --------------------------
909 procedure Create_New_Path_File
910 (In_Tree : Project_Tree_Ref;
911 Path_FD : out File_Descriptor;
912 Path_Name : out Path_Name_Type)
915 Tempdir.Create_Temp_File (Path_FD, Path_Name);
917 if Path_Name /= No_Path then
918 Record_Temp_File (Path_Name);
920 -- Record the name, so that the temp path file will be deleted at the
921 -- end of the program.
923 Path_File_Table.Increment_Last (In_Tree.Private_Part.Path_Files);
924 In_Tree.Private_Part.Path_Files.Table
925 (Path_File_Table.Last (In_Tree.Private_Part.Path_Files)) :=
928 end Create_New_Path_File;
930 ---------------------------
931 -- Delete_All_Path_Files --
932 ---------------------------
934 procedure Delete_All_Path_Files (In_Tree : Project_Tree_Ref) is
935 Disregard : Boolean := True;
936 pragma Unreferenced (Disregard);
939 for Index in Path_File_Table.First ..
940 Path_File_Table.Last (In_Tree.Private_Part.Path_Files)
942 if In_Tree.Private_Part.Path_Files.Table (Index) /= No_Path then
945 (In_Tree.Private_Part.Path_Files.Table (Index)),
950 -- If any of the environment variables ADA_PRJ_INCLUDE_FILE or
951 -- ADA_PRJ_OBJECTS_FILE has been set, then reset their value to
952 -- the empty string. On VMS, this has the effect of deassigning
953 -- the logical names.
955 if In_Tree.Private_Part.Ada_Prj_Include_File_Set then
956 Setenv (Project_Include_Path_File, "");
957 In_Tree.Private_Part.Ada_Prj_Include_File_Set := False;
960 if In_Tree.Private_Part.Ada_Prj_Objects_File_Set then
961 Setenv (Project_Objects_Path_File, "");
962 In_Tree.Private_Part.Ada_Prj_Objects_File_Set := False;
964 end Delete_All_Path_Files;
966 ------------------------------------
967 -- File_Name_Of_Library_Unit_Body --
968 ------------------------------------
970 function File_Name_Of_Library_Unit_Body
972 Project : Project_Id;
973 In_Tree : Project_Tree_Ref;
974 Main_Project_Only : Boolean := True;
975 Full_Path : Boolean := False) return String
977 The_Project : Project_Id := Project;
978 Original_Name : String := Name;
980 Lang : constant Language_Ptr :=
981 Get_Language_From_Name (Project, "ada");
984 The_Original_Name : Name_Id;
985 The_Spec_Name : Name_Id;
986 The_Body_Name : Name_Id;
989 -- ??? Same block in Project_Of
990 Canonical_Case_File_Name (Original_Name);
991 Name_Len := Original_Name'Length;
992 Name_Buffer (1 .. Name_Len) := Original_Name;
993 The_Original_Name := Name_Find;
997 Naming : constant Lang_Naming_Data := Lang.Config.Naming_Data;
998 Extended_Spec_Name : String :=
999 Name & Namet.Get_Name_String
1000 (Naming.Spec_Suffix);
1001 Extended_Body_Name : String :=
1002 Name & Namet.Get_Name_String
1003 (Naming.Body_Suffix);
1006 Canonical_Case_File_Name (Extended_Spec_Name);
1007 Name_Len := Extended_Spec_Name'Length;
1008 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1009 The_Spec_Name := Name_Find;
1011 Canonical_Case_File_Name (Extended_Body_Name);
1012 Name_Len := Extended_Body_Name'Length;
1013 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1014 The_Body_Name := Name_Find;
1018 Name_Len := Name'Length;
1019 Name_Buffer (1 .. Name_Len) := Name;
1020 Canonical_Case_File_Name (Name_Buffer);
1021 The_Spec_Name := Name_Find;
1022 The_Body_Name := The_Spec_Name;
1025 if Current_Verbosity = High then
1026 Write_Str ("Looking for file name of """);
1030 Write_Str (" Extended Spec Name = """);
1031 Write_Str (Get_Name_String (The_Spec_Name));
1034 Write_Str (" Extended Body Name = """);
1035 Write_Str (Get_Name_String (The_Body_Name));
1040 -- For extending project, search in the extended project if the source
1041 -- is not found. For non extending projects, this loop will be run only
1045 -- Loop through units
1047 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1048 while Unit /= null loop
1051 if not Main_Project_Only
1053 (Unit.File_Names (Impl) /= null
1054 and then Unit.File_Names (Impl).Project = The_Project)
1057 Current_Name : File_Name_Type;
1059 -- Case of a body present
1061 if Unit.File_Names (Impl) /= null then
1062 Current_Name := Unit.File_Names (Impl).File;
1064 if Current_Verbosity = High then
1065 Write_Str (" Comparing with """);
1066 Write_Str (Get_Name_String (Current_Name));
1071 -- If it has the name of the original name, return the
1074 if Unit.Name = The_Original_Name
1076 Current_Name = File_Name_Type (The_Original_Name)
1078 if Current_Verbosity = High then
1083 return Get_Name_String
1084 (Unit.File_Names (Impl).Path.Name);
1087 return Get_Name_String (Current_Name);
1090 -- If it has the name of the extended body name,
1091 -- return the extended body name
1093 elsif Current_Name = File_Name_Type (The_Body_Name) then
1094 if Current_Verbosity = High then
1099 return Get_Name_String
1100 (Unit.File_Names (Impl).Path.Name);
1103 return Get_Name_String (The_Body_Name);
1107 if Current_Verbosity = High then
1108 Write_Line (" not good");
1117 if not Main_Project_Only
1119 (Unit.File_Names (Spec) /= null
1120 and then Unit.File_Names (Spec).Project =
1124 Current_Name : File_Name_Type;
1127 -- Case of spec present
1129 if Unit.File_Names (Spec) /= null then
1130 Current_Name := Unit.File_Names (Spec).File;
1131 if Current_Verbosity = High then
1132 Write_Str (" Comparing with """);
1133 Write_Str (Get_Name_String (Current_Name));
1138 -- If name same as original name, return original name
1140 if Unit.Name = The_Original_Name
1142 Current_Name = File_Name_Type (The_Original_Name)
1144 if Current_Verbosity = High then
1149 return Get_Name_String
1150 (Unit.File_Names (Spec).Path.Name);
1152 return Get_Name_String (Current_Name);
1155 -- If it has the same name as the extended spec name,
1156 -- return the extended spec name.
1158 elsif Current_Name = File_Name_Type (The_Spec_Name) then
1159 if Current_Verbosity = High then
1164 return Get_Name_String
1165 (Unit.File_Names (Spec).Path.Name);
1167 return Get_Name_String (The_Spec_Name);
1171 if Current_Verbosity = High then
1172 Write_Line (" not good");
1179 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1182 -- If we are not in an extending project, give up
1184 exit when not Main_Project_Only
1185 or else The_Project.Extends = No_Project;
1187 -- Otherwise, look in the project we are extending
1189 The_Project := The_Project.Extends;
1192 -- We don't know this file name, return an empty string
1195 end File_Name_Of_Library_Unit_Body;
1197 -------------------------
1198 -- For_All_Object_Dirs --
1199 -------------------------
1201 procedure For_All_Object_Dirs (Project : Project_Id) is
1202 procedure For_Project (Prj : Project_Id; Dummy : in out Integer);
1203 -- Get all object directories of Prj
1209 procedure For_Project (Prj : Project_Id; Dummy : in out Integer) is
1210 pragma Unreferenced (Dummy);
1212 -- ??? Set_Ada_Paths has a different behavior for library project
1213 -- files, should we have the same ?
1215 if Prj.Object_Directory /= No_Path_Information then
1216 Get_Name_String (Prj.Object_Directory.Display_Name);
1217 Action (Name_Buffer (1 .. Name_Len));
1221 procedure Get_Object_Dirs is
1222 new For_Every_Project_Imported (Integer, For_Project);
1223 Dummy : Integer := 1;
1225 -- Start of processing for For_All_Object_Dirs
1228 Get_Object_Dirs (Project, Dummy);
1229 end For_All_Object_Dirs;
1231 -------------------------
1232 -- For_All_Source_Dirs --
1233 -------------------------
1235 procedure For_All_Source_Dirs
1236 (Project : Project_Id;
1237 In_Tree : Project_Tree_Ref)
1239 procedure For_Project (Prj : Project_Id; Dummy : in out Integer);
1240 -- Get all object directories of Prj
1246 procedure For_Project (Prj : Project_Id; Dummy : in out Integer) is
1247 pragma Unreferenced (Dummy);
1248 Current : String_List_Id := Prj.Source_Dirs;
1249 The_String : String_Element;
1252 -- If there are Ada sources, call action with the name of every
1253 -- source directory.
1255 if Has_Ada_Sources (Project) then
1256 while Current /= Nil_String loop
1257 The_String := In_Tree.String_Elements.Table (Current);
1258 Action (Get_Name_String (The_String.Display_Value));
1259 Current := The_String.Next;
1264 procedure Get_Source_Dirs is
1265 new For_Every_Project_Imported (Integer, For_Project);
1266 Dummy : Integer := 1;
1268 -- Start of processing for For_All_Source_Dirs
1271 Get_Source_Dirs (Project, Dummy);
1272 end For_All_Source_Dirs;
1278 procedure Get_Reference
1279 (Source_File_Name : String;
1280 In_Tree : Project_Tree_Ref;
1281 Project : out Project_Id;
1282 Path : out Path_Name_Type)
1285 -- Body below could use some comments ???
1287 if Current_Verbosity > Default then
1288 Write_Str ("Getting Reference_Of (""");
1289 Write_Str (Source_File_Name);
1290 Write_Str (""") ... ");
1294 Original_Name : String := Source_File_Name;
1298 Canonical_Case_File_Name (Original_Name);
1299 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1301 while Unit /= null loop
1302 if Unit.File_Names (Spec) /= null
1303 and then Unit.File_Names (Spec).File /= No_File
1305 (Namet.Get_Name_String
1306 (Unit.File_Names (Spec).File) = Original_Name
1307 or else (Unit.File_Names (Spec).Path /=
1310 Namet.Get_Name_String
1311 (Unit.File_Names (Spec).Path.Name) =
1314 Project := Ultimate_Extension_Of
1315 (Project => Unit.File_Names (Spec).Project);
1316 Path := Unit.File_Names (Spec).Path.Display_Name;
1318 if Current_Verbosity > Default then
1319 Write_Str ("Done: Spec.");
1325 elsif Unit.File_Names (Impl) /= null
1326 and then Unit.File_Names (Impl).File /= No_File
1328 (Namet.Get_Name_String
1329 (Unit.File_Names (Impl).File) = Original_Name
1330 or else (Unit.File_Names (Impl).Path /=
1332 and then Namet.Get_Name_String
1333 (Unit.File_Names (Impl).Path.Name) =
1336 Project := Ultimate_Extension_Of
1337 (Project => Unit.File_Names (Impl).Project);
1338 Path := Unit.File_Names (Impl).Path.Display_Name;
1340 if Current_Verbosity > Default then
1341 Write_Str ("Done: Body.");
1348 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1352 Project := No_Project;
1355 if Current_Verbosity > Default then
1356 Write_Str ("Cannot be found.");
1365 procedure Initialize (In_Tree : Project_Tree_Ref) is
1367 In_Tree.Private_Part.Fill_Mapping_File := True;
1368 In_Tree.Private_Part.Current_Source_Path_File := No_Path;
1369 In_Tree.Private_Part.Current_Object_Path_File := No_Path;
1376 -- Could use some comments in this body ???
1378 procedure Print_Sources (In_Tree : Project_Tree_Ref) is
1382 Write_Line ("List of Sources:");
1384 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1386 while Unit /= No_Unit_Index loop
1388 Write_Line (Namet.Get_Name_String (Unit.Name));
1390 if Unit.File_Names (Spec).File /= No_File then
1391 if Unit.File_Names (Spec).Project = No_Project then
1392 Write_Line (" No project");
1395 Write_Str (" Project: ");
1397 (Unit.File_Names (Spec).Project.Path.Name);
1398 Write_Line (Name_Buffer (1 .. Name_Len));
1401 Write_Str (" spec: ");
1403 (Namet.Get_Name_String
1404 (Unit.File_Names (Spec).File));
1407 if Unit.File_Names (Impl).File /= No_File then
1408 if Unit.File_Names (Impl).Project = No_Project then
1409 Write_Line (" No project");
1412 Write_Str (" Project: ");
1414 (Unit.File_Names (Impl).Project.Path.Name);
1415 Write_Line (Name_Buffer (1 .. Name_Len));
1418 Write_Str (" body: ");
1420 (Namet.Get_Name_String (Unit.File_Names (Impl).File));
1423 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1426 Write_Line ("end of List of Sources.");
1435 Main_Project : Project_Id;
1436 In_Tree : Project_Tree_Ref) return Project_Id
1438 Result : Project_Id := No_Project;
1440 Original_Name : String := Name;
1442 Lang : constant Language_Ptr :=
1443 Get_Language_From_Name (Main_Project, "ada");
1447 Current_Name : File_Name_Type;
1448 The_Original_Name : File_Name_Type;
1449 The_Spec_Name : File_Name_Type;
1450 The_Body_Name : File_Name_Type;
1453 -- ??? Same block in File_Name_Of_Library_Unit_Body
1454 Canonical_Case_File_Name (Original_Name);
1455 Name_Len := Original_Name'Length;
1456 Name_Buffer (1 .. Name_Len) := Original_Name;
1457 The_Original_Name := Name_Find;
1459 if Lang /= null then
1461 Naming : Lang_Naming_Data renames Lang.Config.Naming_Data;
1462 Extended_Spec_Name : String :=
1463 Name & Namet.Get_Name_String
1464 (Naming.Spec_Suffix);
1465 Extended_Body_Name : String :=
1466 Name & Namet.Get_Name_String
1467 (Naming.Body_Suffix);
1470 Canonical_Case_File_Name (Extended_Spec_Name);
1471 Name_Len := Extended_Spec_Name'Length;
1472 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1473 The_Spec_Name := Name_Find;
1475 Canonical_Case_File_Name (Extended_Body_Name);
1476 Name_Len := Extended_Body_Name'Length;
1477 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1478 The_Body_Name := Name_Find;
1482 The_Spec_Name := The_Original_Name;
1483 The_Body_Name := The_Original_Name;
1486 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1487 while Unit /= null loop
1489 -- Case of a body present
1491 if Unit.File_Names (Impl) /= null then
1492 Current_Name := Unit.File_Names (Impl).File;
1494 -- If it has the name of the original name or the body name,
1495 -- we have found the project.
1497 if Unit.Name = Name_Id (The_Original_Name)
1498 or else Current_Name = The_Original_Name
1499 or else Current_Name = The_Body_Name
1501 Result := Unit.File_Names (Impl).Project;
1508 if Unit.File_Names (Spec) /= null then
1509 Current_Name := Unit.File_Names (Spec).File;
1511 -- If name same as the original name, or the spec name, we have
1512 -- found the project.
1514 if Unit.Name = Name_Id (The_Original_Name)
1515 or else Current_Name = The_Original_Name
1516 or else Current_Name = The_Spec_Name
1518 Result := Unit.File_Names (Spec).Project;
1523 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1526 -- Get the ultimate extending project
1528 if Result /= No_Project then
1529 while Result.Extended_By /= No_Project loop
1530 Result := Result.Extended_By;
1541 procedure Set_Ada_Paths
1542 (Project : Project_Id;
1543 In_Tree : Project_Tree_Ref;
1544 Including_Libraries : Boolean)
1547 Source_FD : File_Descriptor := Invalid_FD;
1548 Object_FD : File_Descriptor := Invalid_FD;
1550 Process_Source_Dirs : Boolean := False;
1551 Process_Object_Dirs : Boolean := False;
1554 -- For calls to Close
1558 procedure Recursive_Add (Project : Project_Id; Dummy : in out Boolean);
1559 -- Recursive procedure to add the source/object paths of extended/
1560 -- imported projects.
1566 procedure Recursive_Add (Project : Project_Id; Dummy : in out Boolean) is
1567 pragma Unreferenced (Dummy);
1569 Path : Path_Name_Type;
1572 -- ??? This is almost the equivalent of For_All_Source_Dirs
1574 if Process_Source_Dirs then
1576 -- Add to path all source directories of this project if there are
1579 if Has_Ada_Sources (Project) then
1580 Add_To_Source_Path (Project.Source_Dirs, In_Tree);
1584 if Process_Object_Dirs then
1585 Path := Get_Object_Directory
1587 Including_Libraries => Including_Libraries,
1588 Only_If_Ada => True);
1590 if Path /= No_Path then
1591 Add_To_Object_Path (Path, In_Tree);
1596 procedure For_All_Projects is
1597 new For_Every_Project_Imported (Boolean, Recursive_Add);
1598 Dummy : Boolean := False;
1600 -- Start of processing for Set_Ada_Paths
1603 -- If it is the first time we call this procedure for this project,
1604 -- compute the source path and/or the object path.
1606 if Project.Include_Path_File = No_Path then
1607 Process_Source_Dirs := True;
1608 Create_New_Path_File
1609 (In_Tree, Source_FD, Project.Include_Path_File);
1612 -- For the object path, we make a distinction depending on
1613 -- Including_Libraries.
1615 if Including_Libraries then
1616 if Project.Objects_Path_File_With_Libs = No_Path then
1617 Process_Object_Dirs := True;
1618 Create_New_Path_File
1619 (In_Tree, Object_FD, Project.Objects_Path_File_With_Libs);
1623 if Project.Objects_Path_File_Without_Libs = No_Path then
1624 Process_Object_Dirs := True;
1625 Create_New_Path_File
1626 (In_Tree, Object_FD, Project.Objects_Path_File_Without_Libs);
1630 -- If there is something to do, set Seen to False for all projects,
1631 -- then call the recursive procedure Add for Project.
1633 if Process_Source_Dirs or Process_Object_Dirs then
1634 Source_Path_Table.Set_Last (In_Tree.Private_Part.Source_Paths, 0);
1635 Object_Path_Table.Set_Last (In_Tree.Private_Part.Object_Paths, 0);
1636 For_All_Projects (Project, Dummy);
1639 -- Write and close any file that has been created
1641 if Source_FD /= Invalid_FD then
1642 for Index in Source_Path_Table.First ..
1643 Source_Path_Table.Last
1644 (In_Tree.Private_Part.Source_Paths)
1646 Get_Name_String (In_Tree.Private_Part.Source_Paths.Table (Index));
1647 Name_Len := Name_Len + 1;
1648 Name_Buffer (Name_Len) := ASCII.LF;
1649 Len := Write (Source_FD, Name_Buffer (1)'Address, Name_Len);
1651 if Len /= Name_Len then
1652 Prj.Com.Fail ("disk full");
1656 Close (Source_FD, Status);
1659 Prj.Com.Fail ("disk full");
1663 if Object_FD /= Invalid_FD then
1664 for Index in Object_Path_Table.First ..
1665 Object_Path_Table.Last
1666 (In_Tree.Private_Part.Object_Paths)
1668 Get_Name_String (In_Tree.Private_Part.Object_Paths.Table (Index));
1669 Name_Len := Name_Len + 1;
1670 Name_Buffer (Name_Len) := ASCII.LF;
1671 Len := Write (Object_FD, Name_Buffer (1)'Address, Name_Len);
1673 if Len /= Name_Len then
1674 Prj.Com.Fail ("disk full");
1678 Close (Object_FD, Status);
1681 Prj.Com.Fail ("disk full");
1685 -- Set the env vars, if they need to be changed, and set the
1686 -- corresponding flags.
1688 if In_Tree.Private_Part.Current_Source_Path_File /=
1689 Project.Include_Path_File
1691 In_Tree.Private_Part.Current_Source_Path_File :=
1692 Project.Include_Path_File;
1694 (Project_Include_Path_File,
1695 Get_Name_String (In_Tree.Private_Part.Current_Source_Path_File));
1696 In_Tree.Private_Part.Ada_Prj_Include_File_Set := True;
1699 if Including_Libraries then
1700 if In_Tree.Private_Part.Current_Object_Path_File /=
1701 Project.Objects_Path_File_With_Libs
1703 In_Tree.Private_Part.Current_Object_Path_File :=
1704 Project.Objects_Path_File_With_Libs;
1706 (Project_Objects_Path_File,
1708 (In_Tree.Private_Part.Current_Object_Path_File));
1709 In_Tree.Private_Part.Ada_Prj_Objects_File_Set := True;
1713 if In_Tree.Private_Part.Current_Object_Path_File /=
1714 Project.Objects_Path_File_Without_Libs
1716 In_Tree.Private_Part.Current_Object_Path_File :=
1717 Project.Objects_Path_File_Without_Libs;
1719 (Project_Objects_Path_File,
1721 (In_Tree.Private_Part.Current_Object_Path_File));
1722 In_Tree.Private_Part.Ada_Prj_Objects_File_Set := True;
1727 ---------------------------------------------
1728 -- Set_Mapping_File_Initial_State_To_Empty --
1729 ---------------------------------------------
1731 procedure Set_Mapping_File_Initial_State_To_Empty
1732 (In_Tree : Project_Tree_Ref)
1735 In_Tree.Private_Part.Fill_Mapping_File := False;
1736 end Set_Mapping_File_Initial_State_To_Empty;
1738 -----------------------
1739 -- Set_Path_File_Var --
1740 -----------------------
1742 procedure Set_Path_File_Var (Name : String; Value : String) is
1743 Host_Spec : String_Access := To_Host_File_Spec (Value);
1745 if Host_Spec = null then
1747 ("could not convert file name """ & Value & """ to host spec");
1749 Setenv (Name, Host_Spec.all);
1752 end Set_Path_File_Var;
1754 ---------------------------
1755 -- Ultimate_Extension_Of --
1756 ---------------------------
1758 function Ultimate_Extension_Of
1759 (Project : Project_Id) return Project_Id
1761 Result : Project_Id;
1765 while Result.Extended_By /= No_Project loop
1766 Result := Result.Extended_By;
1770 end Ultimate_Extension_Of;