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_Naming : Naming_Id;
405 Iter : Source_Iterator;
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.
421 procedure Put (Source : Source_Id);
422 -- Put an SFN pragma in the temporary file
424 procedure Put (File : File_Descriptor; S : String);
425 procedure Put_Line (File : File_Descriptor; S : String);
426 -- Output procedures, analogous to normal Text_IO procs of same name
432 procedure Check (Project : Project_Id; State : in out Integer) is
433 pragma Unreferenced (State);
434 Lang : constant Language_Ptr :=
435 Get_Language_From_Name (Project, "ada");
436 Naming : Lang_Naming_Data;
439 if Current_Verbosity = High then
440 Write_Str ("Checking project file """);
441 Write_Str (Namet.Get_Name_String (Project.Name));
447 if Current_Verbosity = High then
448 Write_Line (" Languages does not contain Ada, nothing to do");
454 Naming := Lang.Config.Naming_Data;
456 -- Is the naming scheme of this project one that we know?
458 Current_Naming := Default_Naming;
459 while Current_Naming <= Naming_Table.Last (Namings)
460 and then Namings.Table (Current_Naming).Dot_Replacement =
461 Naming.Dot_Replacement
462 and then Namings.Table (Current_Naming).Casing =
464 and then Namings.Table (Current_Naming).Separate_Suffix =
465 Naming.Separate_Suffix
467 Current_Naming := Current_Naming + 1;
470 -- If we don't know it, add it
472 if Current_Naming > Naming_Table.Last (Namings) then
473 Naming_Table.Increment_Last (Namings);
474 Namings.Table (Naming_Table.Last (Namings)) := Naming;
476 -- We need a temporary file to be created
480 -- Put the SFN pragmas for the naming scheme
485 (File, "pragma Source_File_Name_Project");
487 (File, " (Spec_File_Name => ""*" &
488 Get_Name_String (Naming.Spec_Suffix) & """,");
490 (File, " Casing => " &
491 Image (Naming.Casing) & ",");
493 (File, " Dot_Replacement => """ &
494 Get_Name_String (Naming.Dot_Replacement) & """);");
499 (File, "pragma Source_File_Name_Project");
501 (File, " (Body_File_Name => ""*" &
502 Get_Name_String (Naming.Body_Suffix) & """,");
504 (File, " Casing => " &
505 Image (Naming.Casing) & ",");
507 (File, " Dot_Replacement => """ &
508 Get_Name_String (Naming.Dot_Replacement) &
511 -- and maybe separate
513 if Naming.Body_Suffix /= Naming.Separate_Suffix then
514 Put_Line (File, "pragma Source_File_Name_Project");
516 (File, " (Subunit_File_Name => ""*" &
517 Get_Name_String (Naming.Separate_Suffix) & """,");
519 (File, " Casing => " &
520 Image (Naming.Casing) & ",");
522 (File, " Dot_Replacement => """ &
523 Get_Name_String (Naming.Dot_Replacement) &
529 ---------------------
530 -- Check_Temp_File --
531 ---------------------
533 procedure Check_Temp_File is
535 if File = Invalid_FD then
536 Tempdir.Create_Temp_File (File, Name => File_Name);
538 if File = Invalid_FD then
540 ("unable to create temporary configuration pragmas file");
543 Record_Temp_File (File_Name);
545 if Opt.Verbose_Mode then
546 Write_Str ("Creating temp file """);
547 Write_Str (Get_Name_String (File_Name));
558 procedure Put (Source : Source_Id) is
560 -- A temporary file needs to be open
564 -- Put the pragma SFN for the unit kind (spec or body)
566 Put (File, "pragma Source_File_Name_Project (");
567 Put (File, Namet.Get_Name_String (Source.Unit.Name));
569 if Source.Kind = Spec then
570 Put (File, ", Spec_File_Name => """);
572 Put (File, ", Body_File_Name => """);
575 Put (File, Namet.Get_Name_String (Source.File));
578 if Source.Index /= 0 then
579 Put (File, ", Index =>");
580 Put (File, Source.Index'Img);
583 Put_Line (File, ");");
586 procedure Put (File : File_Descriptor; S : String) is
590 Last := Write (File, S (S'First)'Address, S'Length);
592 if Last /= S'Length then
594 ("Disk full when creating " & Get_Name_String (File_Name));
597 if Current_Verbosity = High then
606 procedure Put_Line (File : File_Descriptor; S : String) is
607 S0 : String (1 .. S'Length + 1);
611 -- Add an ASCII.LF to the string. As this config file is supposed to
612 -- be used only by the compiler, we don't care about the characters
613 -- for the end of line. In fact we could have put a space, but
614 -- it is more convenient to be able to read gnat.adc during
615 -- development, for which the ASCII.LF is fine.
617 S0 (1 .. S'Length) := S;
618 S0 (S0'Last) := ASCII.LF;
619 Last := Write (File, S0'Address, S0'Length);
621 if Last /= S'Length + 1 then
623 ("Disk full when creating " & Get_Name_String (File_Name));
626 if Current_Verbosity = High then
631 procedure Check_Imported_Projects is new For_Every_Project_Imported
633 Dummy : Integer := 0;
635 -- Start of processing for Create_Config_Pragmas_File
638 if not For_Project.Config_Checked then
640 Naming_Table.Init (Namings);
642 -- Check the naming schemes
644 Check_Imported_Projects (For_Project, Dummy, Imported_First => False);
646 -- Visit all the files and process those that need an SFN pragma
648 Iter := For_Each_Source (In_Tree, For_Project);
649 while Element (Iter) /= No_Source loop
650 Source := Element (Iter);
653 and then not Source.Locally_Removed
654 and then Source.Unit /= null
662 -- If there are no non standard naming scheme, issue the GNAT
663 -- standard naming scheme. This will tell the compiler that
664 -- a project file is used and will forbid any pragma SFN.
666 if File = Invalid_FD then
669 Put_Line (File, "pragma Source_File_Name_Project");
670 Put_Line (File, " (Spec_File_Name => ""*.ads"",");
671 Put_Line (File, " Dot_Replacement => ""-"",");
672 Put_Line (File, " Casing => lowercase);");
674 Put_Line (File, "pragma Source_File_Name_Project");
675 Put_Line (File, " (Body_File_Name => ""*.adb"",");
676 Put_Line (File, " Dot_Replacement => ""-"",");
677 Put_Line (File, " Casing => lowercase);");
680 -- Close the temporary file
682 GNAT.OS_Lib.Close (File, Status);
686 ("Disk full when creating " & Get_Name_String (File_Name));
689 if Opt.Verbose_Mode then
690 Write_Str ("Closing configuration file """);
691 Write_Str (Get_Name_String (File_Name));
695 For_Project.Config_File_Name := File_Name;
696 For_Project.Config_File_Temp := True;
697 For_Project.Config_Checked := True;
699 end Create_Config_Pragmas_File;
705 procedure Create_Mapping (In_Tree : Project_Tree_Ref) is
707 Iter : Source_Iterator;
712 Iter := For_Each_Source (In_Tree);
714 Data := Element (Iter);
715 exit when Data = No_Source;
717 if Data.Unit /= No_Unit_Index then
718 if Data.Locally_Removed then
719 Fmap.Add_Forbidden_File_Name (Data.File);
722 (Unit_Name => Unit_Name_Type (Data.Unit.Name),
723 File_Name => Data.File,
724 Path_Name => File_Name_Type (Data.Path.Name));
732 -------------------------
733 -- Create_Mapping_File --
734 -------------------------
736 procedure Create_Mapping_File
737 (Project : Project_Id;
739 In_Tree : Project_Tree_Ref;
740 Name : out Path_Name_Type)
742 File : File_Descriptor := Invalid_FD;
745 procedure Put_Name_Buffer;
746 -- Put the line contained in the Name_Buffer in the mapping file
748 procedure Process (Project : Project_Id; State : in out Integer);
749 -- Generate the mapping file for Project (not recursively)
755 procedure Put_Name_Buffer is
759 Name_Len := Name_Len + 1;
760 Name_Buffer (Name_Len) := ASCII.LF;
761 Last := Write (File, Name_Buffer (1)'Address, Name_Len);
763 if Current_Verbosity = High then
764 Write_Str ("Mapping file: " & Name_Buffer (1 .. Name_Len));
767 if Last /= Name_Len then
768 Prj.Com.Fail ("Disk full, cannot write mapping file");
776 procedure Process (Project : Project_Id; State : in out Integer) is
777 pragma Unreferenced (State);
779 Suffix : File_Name_Type;
780 Iter : Source_Iterator;
783 Iter := For_Each_Source (In_Tree, Project, Language => Language);
786 Source := Prj.Element (Iter);
787 exit when Source = No_Source;
789 if Source.Replaced_By = No_Source
790 and then Source.Path.Name /= No_Path
792 (Source.Language.Config.Kind = File_Based
793 or else Source.Unit /= No_Unit_Index)
795 if Source.Unit /= No_Unit_Index then
796 Get_Name_String (Source.Unit.Name);
798 if Get_Mode = Ada_Only then
800 -- ??? Mapping_Spec_Suffix could be set in the case of
803 Add_Char_To_Name_Buffer ('%');
805 if Source.Kind = Spec then
806 Add_Char_To_Name_Buffer ('s');
808 Add_Char_To_Name_Buffer ('b');
815 Source.Language.Config.Mapping_Spec_Suffix;
818 Source.Language.Config.Mapping_Body_Suffix;
821 if Suffix /= No_File then
822 Add_Str_To_Name_Buffer
823 (Get_Name_String (Suffix));
830 Get_Name_String (Source.File);
833 if Source.Locally_Removed then
835 Name_Buffer (1) := '/';
837 Get_Name_String (Source.Path.Name);
847 procedure For_Every_Imported_Project is new
848 For_Every_Project_Imported (State => Integer, Action => Process);
850 Dummy : Integer := 0;
852 -- Start of processing for Create_Mapping_File
856 -- Create the temporary file
858 Tempdir.Create_Temp_File (File, Name => Name);
860 if File = Invalid_FD then
861 Prj.Com.Fail ("unable to create temporary mapping file");
864 Record_Temp_File (Name);
866 if Opt.Verbose_Mode then
867 Write_Str ("Creating temp mapping file """);
868 Write_Str (Get_Name_String (Name));
873 For_Every_Imported_Project (Project, Dummy);
874 GNAT.OS_Lib.Close (File, Status);
878 -- We were able to create the temporary file, so there is no problem
879 -- of protection. However, we are not able to close it, so there must
880 -- be a capacity problem that we express using "disk full".
882 Prj.Com.Fail ("disk full, could not write mapping file");
884 end Create_Mapping_File;
886 --------------------------
887 -- Create_New_Path_File --
888 --------------------------
890 procedure Create_New_Path_File
891 (In_Tree : Project_Tree_Ref;
892 Path_FD : out File_Descriptor;
893 Path_Name : out Path_Name_Type)
896 Tempdir.Create_Temp_File (Path_FD, Path_Name);
898 if Path_Name /= No_Path then
899 Record_Temp_File (Path_Name);
901 -- Record the name, so that the temp path file will be deleted at the
902 -- end of the program.
904 Path_File_Table.Increment_Last (In_Tree.Private_Part.Path_Files);
905 In_Tree.Private_Part.Path_Files.Table
906 (Path_File_Table.Last (In_Tree.Private_Part.Path_Files)) :=
909 end Create_New_Path_File;
911 ---------------------------
912 -- Delete_All_Path_Files --
913 ---------------------------
915 procedure Delete_All_Path_Files (In_Tree : Project_Tree_Ref) is
916 Disregard : Boolean := True;
917 pragma Unreferenced (Disregard);
920 for Index in Path_File_Table.First ..
921 Path_File_Table.Last (In_Tree.Private_Part.Path_Files)
923 if In_Tree.Private_Part.Path_Files.Table (Index) /= No_Path then
926 (In_Tree.Private_Part.Path_Files.Table (Index)),
931 -- If any of the environment variables ADA_PRJ_INCLUDE_FILE or
932 -- ADA_PRJ_OBJECTS_FILE has been set, then reset their value to
933 -- the empty string. On VMS, this has the effect of deassigning
934 -- the logical names.
936 if In_Tree.Private_Part.Ada_Prj_Include_File_Set then
937 Setenv (Project_Include_Path_File, "");
938 In_Tree.Private_Part.Ada_Prj_Include_File_Set := False;
941 if In_Tree.Private_Part.Ada_Prj_Objects_File_Set then
942 Setenv (Project_Objects_Path_File, "");
943 In_Tree.Private_Part.Ada_Prj_Objects_File_Set := False;
945 end Delete_All_Path_Files;
947 ------------------------------------
948 -- File_Name_Of_Library_Unit_Body --
949 ------------------------------------
951 function File_Name_Of_Library_Unit_Body
953 Project : Project_Id;
954 In_Tree : Project_Tree_Ref;
955 Main_Project_Only : Boolean := True;
956 Full_Path : Boolean := False) return String
958 The_Project : Project_Id := Project;
959 Original_Name : String := Name;
961 Lang : constant Language_Ptr :=
962 Get_Language_From_Name (Project, "ada");
965 The_Original_Name : Name_Id;
966 The_Spec_Name : Name_Id;
967 The_Body_Name : Name_Id;
970 -- ??? Same block in Project_Of
971 Canonical_Case_File_Name (Original_Name);
972 Name_Len := Original_Name'Length;
973 Name_Buffer (1 .. Name_Len) := Original_Name;
974 The_Original_Name := Name_Find;
978 Naming : constant Lang_Naming_Data := Lang.Config.Naming_Data;
979 Extended_Spec_Name : String :=
980 Name & Namet.Get_Name_String
981 (Naming.Spec_Suffix);
982 Extended_Body_Name : String :=
983 Name & Namet.Get_Name_String
984 (Naming.Body_Suffix);
987 Canonical_Case_File_Name (Extended_Spec_Name);
988 Name_Len := Extended_Spec_Name'Length;
989 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
990 The_Spec_Name := Name_Find;
992 Canonical_Case_File_Name (Extended_Body_Name);
993 Name_Len := Extended_Body_Name'Length;
994 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
995 The_Body_Name := Name_Find;
999 Name_Len := Name'Length;
1000 Name_Buffer (1 .. Name_Len) := Name;
1001 Canonical_Case_File_Name (Name_Buffer);
1002 The_Spec_Name := Name_Find;
1003 The_Body_Name := The_Spec_Name;
1006 if Current_Verbosity = High then
1007 Write_Str ("Looking for file name of """);
1011 Write_Str (" Extended Spec Name = """);
1012 Write_Str (Get_Name_String (The_Spec_Name));
1015 Write_Str (" Extended Body Name = """);
1016 Write_Str (Get_Name_String (The_Body_Name));
1021 -- For extending project, search in the extended project if the source
1022 -- is not found. For non extending projects, this loop will be run only
1026 -- Loop through units
1028 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1029 while Unit /= null loop
1032 if not Main_Project_Only
1034 (Unit.File_Names (Impl) /= null
1035 and then Unit.File_Names (Impl).Project = The_Project)
1038 Current_Name : File_Name_Type;
1040 -- Case of a body present
1042 if Unit.File_Names (Impl) /= null then
1043 Current_Name := Unit.File_Names (Impl).File;
1045 if Current_Verbosity = High then
1046 Write_Str (" Comparing with """);
1047 Write_Str (Get_Name_String (Current_Name));
1052 -- If it has the name of the original name, return the
1055 if Unit.Name = The_Original_Name
1057 Current_Name = File_Name_Type (The_Original_Name)
1059 if Current_Verbosity = High then
1064 return Get_Name_String
1065 (Unit.File_Names (Impl).Path.Name);
1068 return Get_Name_String (Current_Name);
1071 -- If it has the name of the extended body name,
1072 -- return the extended body name
1074 elsif Current_Name = File_Name_Type (The_Body_Name) then
1075 if Current_Verbosity = High then
1080 return Get_Name_String
1081 (Unit.File_Names (Impl).Path.Name);
1084 return Get_Name_String (The_Body_Name);
1088 if Current_Verbosity = High then
1089 Write_Line (" not good");
1098 if not Main_Project_Only
1100 (Unit.File_Names (Spec) /= null
1101 and then Unit.File_Names (Spec).Project =
1105 Current_Name : File_Name_Type;
1108 -- Case of spec present
1110 if Unit.File_Names (Spec) /= null then
1111 Current_Name := Unit.File_Names (Spec).File;
1112 if Current_Verbosity = High then
1113 Write_Str (" Comparing with """);
1114 Write_Str (Get_Name_String (Current_Name));
1119 -- If name same as original name, return original name
1121 if Unit.Name = The_Original_Name
1123 Current_Name = File_Name_Type (The_Original_Name)
1125 if Current_Verbosity = High then
1130 return Get_Name_String
1131 (Unit.File_Names (Spec).Path.Name);
1133 return Get_Name_String (Current_Name);
1136 -- If it has the same name as the extended spec name,
1137 -- return the extended spec name.
1139 elsif Current_Name = File_Name_Type (The_Spec_Name) then
1140 if Current_Verbosity = High then
1145 return Get_Name_String
1146 (Unit.File_Names (Spec).Path.Name);
1148 return Get_Name_String (The_Spec_Name);
1152 if Current_Verbosity = High then
1153 Write_Line (" not good");
1160 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1163 -- If we are not in an extending project, give up
1165 exit when not Main_Project_Only
1166 or else The_Project.Extends = No_Project;
1168 -- Otherwise, look in the project we are extending
1170 The_Project := The_Project.Extends;
1173 -- We don't know this file name, return an empty string
1176 end File_Name_Of_Library_Unit_Body;
1178 -------------------------
1179 -- For_All_Object_Dirs --
1180 -------------------------
1182 procedure For_All_Object_Dirs (Project : Project_Id) is
1183 procedure For_Project (Prj : Project_Id; Dummy : in out Integer);
1184 -- Get all object directories of Prj
1190 procedure For_Project (Prj : Project_Id; Dummy : in out Integer) is
1191 pragma Unreferenced (Dummy);
1193 -- ??? Set_Ada_Paths has a different behavior for library project
1194 -- files, should we have the same ?
1196 if Prj.Object_Directory /= No_Path_Information then
1197 Get_Name_String (Prj.Object_Directory.Display_Name);
1198 Action (Name_Buffer (1 .. Name_Len));
1202 procedure Get_Object_Dirs is
1203 new For_Every_Project_Imported (Integer, For_Project);
1204 Dummy : Integer := 1;
1206 -- Start of processing for For_All_Object_Dirs
1209 Get_Object_Dirs (Project, Dummy);
1210 end For_All_Object_Dirs;
1212 -------------------------
1213 -- For_All_Source_Dirs --
1214 -------------------------
1216 procedure For_All_Source_Dirs
1217 (Project : Project_Id;
1218 In_Tree : Project_Tree_Ref)
1220 procedure For_Project (Prj : Project_Id; Dummy : in out Integer);
1221 -- Get all object directories of Prj
1227 procedure For_Project (Prj : Project_Id; Dummy : in out Integer) is
1228 pragma Unreferenced (Dummy);
1229 Current : String_List_Id := Prj.Source_Dirs;
1230 The_String : String_Element;
1233 -- If there are Ada sources, call action with the name of every
1234 -- source directory.
1236 if Has_Ada_Sources (Project) then
1237 while Current /= Nil_String loop
1238 The_String := In_Tree.String_Elements.Table (Current);
1239 Action (Get_Name_String (The_String.Display_Value));
1240 Current := The_String.Next;
1245 procedure Get_Source_Dirs is
1246 new For_Every_Project_Imported (Integer, For_Project);
1247 Dummy : Integer := 1;
1249 -- Start of processing for For_All_Source_Dirs
1252 Get_Source_Dirs (Project, Dummy);
1253 end For_All_Source_Dirs;
1259 procedure Get_Reference
1260 (Source_File_Name : String;
1261 In_Tree : Project_Tree_Ref;
1262 Project : out Project_Id;
1263 Path : out Path_Name_Type)
1266 -- Body below could use some comments ???
1268 if Current_Verbosity > Default then
1269 Write_Str ("Getting Reference_Of (""");
1270 Write_Str (Source_File_Name);
1271 Write_Str (""") ... ");
1275 Original_Name : String := Source_File_Name;
1279 Canonical_Case_File_Name (Original_Name);
1280 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1282 while Unit /= null loop
1283 if Unit.File_Names (Spec) /= null
1284 and then Unit.File_Names (Spec).File /= No_File
1286 (Namet.Get_Name_String
1287 (Unit.File_Names (Spec).File) = Original_Name
1288 or else (Unit.File_Names (Spec).Path /=
1291 Namet.Get_Name_String
1292 (Unit.File_Names (Spec).Path.Name) =
1295 Project := Ultimate_Extension_Of
1296 (Project => Unit.File_Names (Spec).Project);
1297 Path := Unit.File_Names (Spec).Path.Display_Name;
1299 if Current_Verbosity > Default then
1300 Write_Str ("Done: Spec.");
1306 elsif Unit.File_Names (Impl) /= null
1307 and then Unit.File_Names (Impl).File /= No_File
1309 (Namet.Get_Name_String
1310 (Unit.File_Names (Impl).File) = Original_Name
1311 or else (Unit.File_Names (Impl).Path /=
1313 and then Namet.Get_Name_String
1314 (Unit.File_Names (Impl).Path.Name) =
1317 Project := Ultimate_Extension_Of
1318 (Project => Unit.File_Names (Impl).Project);
1319 Path := Unit.File_Names (Impl).Path.Display_Name;
1321 if Current_Verbosity > Default then
1322 Write_Str ("Done: Body.");
1329 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1333 Project := No_Project;
1336 if Current_Verbosity > Default then
1337 Write_Str ("Cannot be found.");
1346 procedure Initialize (In_Tree : Project_Tree_Ref) is
1348 In_Tree.Private_Part.Fill_Mapping_File := True;
1349 In_Tree.Private_Part.Current_Source_Path_File := No_Path;
1350 In_Tree.Private_Part.Current_Object_Path_File := No_Path;
1357 -- Could use some comments in this body ???
1359 procedure Print_Sources (In_Tree : Project_Tree_Ref) is
1363 Write_Line ("List of Sources:");
1365 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1367 while Unit /= No_Unit_Index loop
1369 Write_Line (Namet.Get_Name_String (Unit.Name));
1371 if Unit.File_Names (Spec).File /= No_File then
1372 if Unit.File_Names (Spec).Project = No_Project then
1373 Write_Line (" No project");
1376 Write_Str (" Project: ");
1378 (Unit.File_Names (Spec).Project.Path.Name);
1379 Write_Line (Name_Buffer (1 .. Name_Len));
1382 Write_Str (" spec: ");
1384 (Namet.Get_Name_String
1385 (Unit.File_Names (Spec).File));
1388 if Unit.File_Names (Impl).File /= No_File then
1389 if Unit.File_Names (Impl).Project = No_Project then
1390 Write_Line (" No project");
1393 Write_Str (" Project: ");
1395 (Unit.File_Names (Impl).Project.Path.Name);
1396 Write_Line (Name_Buffer (1 .. Name_Len));
1399 Write_Str (" body: ");
1401 (Namet.Get_Name_String (Unit.File_Names (Impl).File));
1404 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1407 Write_Line ("end of List of Sources.");
1416 Main_Project : Project_Id;
1417 In_Tree : Project_Tree_Ref) return Project_Id
1419 Result : Project_Id := No_Project;
1421 Original_Name : String := Name;
1423 Lang : constant Language_Ptr :=
1424 Get_Language_From_Name (Main_Project, "ada");
1428 Current_Name : File_Name_Type;
1429 The_Original_Name : File_Name_Type;
1430 The_Spec_Name : File_Name_Type;
1431 The_Body_Name : File_Name_Type;
1434 -- ??? Same block in File_Name_Of_Library_Unit_Body
1435 Canonical_Case_File_Name (Original_Name);
1436 Name_Len := Original_Name'Length;
1437 Name_Buffer (1 .. Name_Len) := Original_Name;
1438 The_Original_Name := Name_Find;
1440 if Lang /= null then
1442 Naming : Lang_Naming_Data renames Lang.Config.Naming_Data;
1443 Extended_Spec_Name : String :=
1444 Name & Namet.Get_Name_String
1445 (Naming.Spec_Suffix);
1446 Extended_Body_Name : String :=
1447 Name & Namet.Get_Name_String
1448 (Naming.Body_Suffix);
1451 Canonical_Case_File_Name (Extended_Spec_Name);
1452 Name_Len := Extended_Spec_Name'Length;
1453 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1454 The_Spec_Name := Name_Find;
1456 Canonical_Case_File_Name (Extended_Body_Name);
1457 Name_Len := Extended_Body_Name'Length;
1458 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1459 The_Body_Name := Name_Find;
1463 The_Spec_Name := The_Original_Name;
1464 The_Body_Name := The_Original_Name;
1467 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1468 while Unit /= null loop
1470 -- Case of a body present
1472 if Unit.File_Names (Impl) /= null then
1473 Current_Name := Unit.File_Names (Impl).File;
1475 -- If it has the name of the original name or the body name,
1476 -- we have found the project.
1478 if Unit.Name = Name_Id (The_Original_Name)
1479 or else Current_Name = The_Original_Name
1480 or else Current_Name = The_Body_Name
1482 Result := Unit.File_Names (Impl).Project;
1489 if Unit.File_Names (Spec) /= null then
1490 Current_Name := Unit.File_Names (Spec).File;
1492 -- If name same as the original name, or the spec name, we have
1493 -- found the project.
1495 if Unit.Name = Name_Id (The_Original_Name)
1496 or else Current_Name = The_Original_Name
1497 or else Current_Name = The_Spec_Name
1499 Result := Unit.File_Names (Spec).Project;
1504 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1507 -- Get the ultimate extending project
1509 if Result /= No_Project then
1510 while Result.Extended_By /= No_Project loop
1511 Result := Result.Extended_By;
1522 procedure Set_Ada_Paths
1523 (Project : Project_Id;
1524 In_Tree : Project_Tree_Ref;
1525 Including_Libraries : Boolean)
1528 Source_FD : File_Descriptor := Invalid_FD;
1529 Object_FD : File_Descriptor := Invalid_FD;
1531 Process_Source_Dirs : Boolean := False;
1532 Process_Object_Dirs : Boolean := False;
1535 -- For calls to Close
1539 procedure Recursive_Add (Project : Project_Id; Dummy : in out Boolean);
1540 -- Recursive procedure to add the source/object paths of extended/
1541 -- imported projects.
1547 procedure Recursive_Add (Project : Project_Id; Dummy : in out Boolean) is
1548 pragma Unreferenced (Dummy);
1550 Path : Path_Name_Type;
1553 -- ??? This is almost the equivalent of For_All_Source_Dirs
1555 if Process_Source_Dirs then
1557 -- Add to path all source directories of this project if there are
1560 if Has_Ada_Sources (Project) then
1561 Add_To_Source_Path (Project.Source_Dirs, In_Tree);
1565 if Process_Object_Dirs then
1566 Path := Get_Object_Directory
1568 Including_Libraries => Including_Libraries,
1569 Only_If_Ada => True);
1571 if Path /= No_Path then
1572 Add_To_Object_Path (Path, In_Tree);
1577 procedure For_All_Projects is
1578 new For_Every_Project_Imported (Boolean, Recursive_Add);
1579 Dummy : Boolean := False;
1581 -- Start of processing for Set_Ada_Paths
1584 -- If it is the first time we call this procedure for this project,
1585 -- compute the source path and/or the object path.
1587 if Project.Include_Path_File = No_Path then
1588 Process_Source_Dirs := True;
1589 Create_New_Path_File
1590 (In_Tree, Source_FD, Project.Include_Path_File);
1593 -- For the object path, we make a distinction depending on
1594 -- Including_Libraries.
1596 if Including_Libraries then
1597 if Project.Objects_Path_File_With_Libs = No_Path then
1598 Process_Object_Dirs := True;
1599 Create_New_Path_File
1600 (In_Tree, Object_FD, Project.Objects_Path_File_With_Libs);
1604 if Project.Objects_Path_File_Without_Libs = No_Path then
1605 Process_Object_Dirs := True;
1606 Create_New_Path_File
1607 (In_Tree, Object_FD, Project.Objects_Path_File_Without_Libs);
1611 -- If there is something to do, set Seen to False for all projects,
1612 -- then call the recursive procedure Add for Project.
1614 if Process_Source_Dirs or Process_Object_Dirs then
1615 Source_Path_Table.Set_Last (In_Tree.Private_Part.Source_Paths, 0);
1616 Object_Path_Table.Set_Last (In_Tree.Private_Part.Object_Paths, 0);
1617 For_All_Projects (Project, Dummy);
1620 -- Write and close any file that has been created
1622 if Source_FD /= Invalid_FD then
1623 for Index in Source_Path_Table.First ..
1624 Source_Path_Table.Last
1625 (In_Tree.Private_Part.Source_Paths)
1627 Get_Name_String (In_Tree.Private_Part.Source_Paths.Table (Index));
1628 Name_Len := Name_Len + 1;
1629 Name_Buffer (Name_Len) := ASCII.LF;
1630 Len := Write (Source_FD, Name_Buffer (1)'Address, Name_Len);
1632 if Len /= Name_Len then
1633 Prj.Com.Fail ("disk full");
1637 Close (Source_FD, Status);
1640 Prj.Com.Fail ("disk full");
1644 if Object_FD /= Invalid_FD then
1645 for Index in Object_Path_Table.First ..
1646 Object_Path_Table.Last
1647 (In_Tree.Private_Part.Object_Paths)
1649 Get_Name_String (In_Tree.Private_Part.Object_Paths.Table (Index));
1650 Name_Len := Name_Len + 1;
1651 Name_Buffer (Name_Len) := ASCII.LF;
1652 Len := Write (Object_FD, Name_Buffer (1)'Address, Name_Len);
1654 if Len /= Name_Len then
1655 Prj.Com.Fail ("disk full");
1659 Close (Object_FD, Status);
1662 Prj.Com.Fail ("disk full");
1666 -- Set the env vars, if they need to be changed, and set the
1667 -- corresponding flags.
1669 if In_Tree.Private_Part.Current_Source_Path_File /=
1670 Project.Include_Path_File
1672 In_Tree.Private_Part.Current_Source_Path_File :=
1673 Project.Include_Path_File;
1675 (Project_Include_Path_File,
1676 Get_Name_String (In_Tree.Private_Part.Current_Source_Path_File));
1677 In_Tree.Private_Part.Ada_Prj_Include_File_Set := True;
1680 if Including_Libraries then
1681 if In_Tree.Private_Part.Current_Object_Path_File /=
1682 Project.Objects_Path_File_With_Libs
1684 In_Tree.Private_Part.Current_Object_Path_File :=
1685 Project.Objects_Path_File_With_Libs;
1687 (Project_Objects_Path_File,
1689 (In_Tree.Private_Part.Current_Object_Path_File));
1690 In_Tree.Private_Part.Ada_Prj_Objects_File_Set := True;
1694 if In_Tree.Private_Part.Current_Object_Path_File /=
1695 Project.Objects_Path_File_Without_Libs
1697 In_Tree.Private_Part.Current_Object_Path_File :=
1698 Project.Objects_Path_File_Without_Libs;
1700 (Project_Objects_Path_File,
1702 (In_Tree.Private_Part.Current_Object_Path_File));
1703 In_Tree.Private_Part.Ada_Prj_Objects_File_Set := True;
1708 ---------------------------------------------
1709 -- Set_Mapping_File_Initial_State_To_Empty --
1710 ---------------------------------------------
1712 procedure Set_Mapping_File_Initial_State_To_Empty
1713 (In_Tree : Project_Tree_Ref)
1716 In_Tree.Private_Part.Fill_Mapping_File := False;
1717 end Set_Mapping_File_Initial_State_To_Empty;
1719 -----------------------
1720 -- Set_Path_File_Var --
1721 -----------------------
1723 procedure Set_Path_File_Var (Name : String; Value : String) is
1724 Host_Spec : String_Access := To_Host_File_Spec (Value);
1726 if Host_Spec = null then
1728 ("could not convert file name """ & Value & """ to host spec");
1730 Setenv (Name, Host_Spec.all);
1733 end Set_Path_File_Var;
1735 ---------------------------
1736 -- Ultimate_Extension_Of --
1737 ---------------------------
1739 function Ultimate_Extension_Of
1740 (Project : Project_Id) return Project_Id
1742 Result : Project_Id;
1746 while Result.Extended_By /= No_Project loop
1747 Result := Result.Extended_By;
1751 end Ultimate_Extension_Of;