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 Default_Naming : constant Naming_Id := Naming_Table.First;
37 -----------------------
38 -- Local Subprograms --
39 -----------------------
42 (Source_Dirs : String_List_Id;
43 In_Tree : Project_Tree_Ref);
44 -- Add to Ada_Path_Buffer all the source directories in string list
45 -- Source_Dirs, if any. Increment Ada_Path_Length.
47 procedure Add_To_Path (Dir : String; In_Tree : Project_Tree_Ref);
48 -- If Dir is not already in the global variable Ada_Path_Buffer, add it.
49 -- Increment Ada_Path_Length.
50 -- If Ada_Path_Length /= 0, prepend a Path_Separator character to
53 procedure Add_To_Source_Path
54 (Source_Dirs : String_List_Id; In_Tree : Project_Tree_Ref);
55 -- Add to Ada_Path_B all the source directories in string list
56 -- Source_Dirs, if any. Increment Ada_Path_Length.
58 procedure Add_To_Object_Path
59 (Object_Dir : Path_Name_Type;
60 In_Tree : Project_Tree_Ref);
61 -- Add Object_Dir to object path table. Make sure it is not duplicate
62 -- and it is the last one in the current table.
64 procedure Set_Path_File_Var (Name : String; Value : String);
65 -- Call Setenv, after calling To_Host_File_Spec
67 function Ultimate_Extension_Of
68 (Project : Project_Id;
69 In_Tree : Project_Tree_Ref) return Project_Id;
70 -- Return a project that is either Project or an extended ancestor of
71 -- Project that itself is not extended.
73 ----------------------
74 -- Ada_Include_Path --
75 ----------------------
77 function Ada_Include_Path
78 (Project : Project_Id;
79 In_Tree : Project_Tree_Ref) return String_Access
81 procedure Add (Project : Project_Id; Dummy : in out Boolean);
82 -- Add source dirs of Project to the path
88 procedure Add (Project : Project_Id; Dummy : in out Boolean) is
89 pragma Unreferenced (Dummy);
91 Add_To_Path (In_Tree.Projects.Table (Project).Source_Dirs, In_Tree);
94 procedure For_All_Projects is
95 new For_Every_Project_Imported (Boolean, Add);
96 Dummy : Boolean := False;
98 -- Start of processing for Ada_Include_Path
101 -- If it is the first time we call this function for
102 -- this project, compute the source path
104 if In_Tree.Projects.Table (Project).Ada_Include_Path = null then
105 In_Tree.Private_Part.Ada_Path_Length := 0;
106 For_All_Projects (Project, In_Tree, Dummy);
108 In_Tree.Projects.Table (Project).Ada_Include_Path :=
110 (In_Tree.Private_Part.Ada_Path_Buffer
111 (1 .. In_Tree.Private_Part.Ada_Path_Length));
114 return In_Tree.Projects.Table (Project).Ada_Include_Path;
115 end Ada_Include_Path;
117 ----------------------
118 -- Ada_Include_Path --
119 ----------------------
121 function Ada_Include_Path
122 (Project : Project_Id;
123 In_Tree : Project_Tree_Ref;
124 Recursive : Boolean) return String
128 return Ada_Include_Path (Project, In_Tree).all;
130 In_Tree.Private_Part.Ada_Path_Length := 0;
132 (In_Tree.Projects.Table (Project).Source_Dirs, In_Tree);
134 In_Tree.Private_Part.Ada_Path_Buffer
135 (1 .. In_Tree.Private_Part.Ada_Path_Length);
137 end Ada_Include_Path;
139 ----------------------
140 -- Ada_Objects_Path --
141 ----------------------
143 function Ada_Objects_Path
144 (Project : Project_Id;
145 In_Tree : Project_Tree_Ref;
146 Including_Libraries : Boolean := True) return String_Access
148 procedure Add (Project : Project_Id; Dummy : in out Boolean);
149 -- Add all the object directories of a project to the path
155 procedure Add (Project : Project_Id; Dummy : in out Boolean) is
156 pragma Unreferenced (Dummy);
157 Path : constant Path_Name_Type :=
160 Including_Libraries => Including_Libraries,
161 Only_If_Ada => False);
163 if Path /= No_Path then
164 Add_To_Path (Get_Name_String (Path), In_Tree);
168 procedure For_All_Projects is
169 new For_Every_Project_Imported (Boolean, Add);
170 Dummy : Boolean := False;
172 -- Start of processing for Ada_Objects_Path
175 -- If it is the first time we call this function for
176 -- this project, compute the objects path
178 if In_Tree.Projects.Table (Project).Ada_Objects_Path = null then
179 In_Tree.Private_Part.Ada_Path_Length := 0;
180 For_All_Projects (Project, In_Tree, Dummy);
182 In_Tree.Projects.Table (Project).Ada_Objects_Path :=
184 (In_Tree.Private_Part.Ada_Path_Buffer
185 (1 .. In_Tree.Private_Part.Ada_Path_Length));
188 return In_Tree.Projects.Table (Project).Ada_Objects_Path;
189 end Ada_Objects_Path;
191 ------------------------
192 -- Add_To_Object_Path --
193 ------------------------
195 procedure Add_To_Object_Path
196 (Object_Dir : Path_Name_Type; In_Tree : Project_Tree_Ref)
199 -- Check if the directory is already in the table
201 for Index in Object_Path_Table.First ..
202 Object_Path_Table.Last (In_Tree.Private_Part.Object_Paths)
205 -- If it is, remove it, and add it as the last one
207 if In_Tree.Private_Part.Object_Paths.Table (Index) = Object_Dir then
208 for Index2 in Index + 1 ..
209 Object_Path_Table.Last
210 (In_Tree.Private_Part.Object_Paths)
212 In_Tree.Private_Part.Object_Paths.Table (Index2 - 1) :=
213 In_Tree.Private_Part.Object_Paths.Table (Index2);
216 In_Tree.Private_Part.Object_Paths.Table
217 (Object_Path_Table.Last (In_Tree.Private_Part.Object_Paths)) :=
223 -- The directory is not already in the table, add it
225 Object_Path_Table.Increment_Last (In_Tree.Private_Part.Object_Paths);
226 In_Tree.Private_Part.Object_Paths.Table
227 (Object_Path_Table.Last (In_Tree.Private_Part.Object_Paths)) :=
229 end Add_To_Object_Path;
235 procedure Add_To_Path
236 (Source_Dirs : String_List_Id;
237 In_Tree : Project_Tree_Ref)
239 Current : String_List_Id := Source_Dirs;
240 Source_Dir : String_Element;
242 while Current /= Nil_String loop
243 Source_Dir := In_Tree.String_Elements.Table (Current);
244 Add_To_Path (Get_Name_String (Source_Dir.Display_Value), In_Tree);
245 Current := Source_Dir.Next;
249 procedure Add_To_Path (Dir : String; In_Tree : Project_Tree_Ref) is
251 New_Buffer : String_Access;
254 function Is_Present (Path : String; Dir : String) return Boolean;
255 -- Return True if Dir is part of Path
261 function Is_Present (Path : String; Dir : String) return Boolean is
262 Last : constant Integer := Path'Last - Dir'Length + 1;
265 for J in Path'First .. Last loop
267 -- Note: the order of the conditions below is important, since
268 -- it ensures a minimal number of string comparisons.
271 or else Path (J - 1) = Path_Separator)
273 (J + Dir'Length > Path'Last
274 or else Path (J + Dir'Length) = Path_Separator)
275 and then Dir = Path (J .. J + Dir'Length - 1)
284 -- Start of processing for Add_To_Path
287 if Is_Present (In_Tree.Private_Part.Ada_Path_Buffer
288 (1 .. In_Tree.Private_Part.Ada_Path_Length),
292 -- Dir is already in the path, nothing to do
297 Min_Len := In_Tree.Private_Part.Ada_Path_Length + Dir'Length;
299 if In_Tree.Private_Part.Ada_Path_Length > 0 then
301 -- Add 1 for the Path_Separator character
303 Min_Len := Min_Len + 1;
306 -- If Ada_Path_Buffer is too small, increase it
308 Len := In_Tree.Private_Part.Ada_Path_Buffer'Last;
310 if Len < Min_Len then
313 exit when Len >= Min_Len;
316 New_Buffer := new String (1 .. Len);
317 New_Buffer (1 .. In_Tree.Private_Part.Ada_Path_Length) :=
318 In_Tree.Private_Part.Ada_Path_Buffer
319 (1 .. In_Tree.Private_Part.Ada_Path_Length);
320 Free (In_Tree.Private_Part.Ada_Path_Buffer);
321 In_Tree.Private_Part.Ada_Path_Buffer := New_Buffer;
324 if In_Tree.Private_Part.Ada_Path_Length > 0 then
325 In_Tree.Private_Part.Ada_Path_Length :=
326 In_Tree.Private_Part.Ada_Path_Length + 1;
327 In_Tree.Private_Part.Ada_Path_Buffer
328 (In_Tree.Private_Part.Ada_Path_Length) := Path_Separator;
331 In_Tree.Private_Part.Ada_Path_Buffer
332 (In_Tree.Private_Part.Ada_Path_Length + 1 ..
333 In_Tree.Private_Part.Ada_Path_Length + Dir'Length) := Dir;
334 In_Tree.Private_Part.Ada_Path_Length :=
335 In_Tree.Private_Part.Ada_Path_Length + Dir'Length;
338 ------------------------
339 -- Add_To_Source_Path --
340 ------------------------
342 procedure Add_To_Source_Path
343 (Source_Dirs : String_List_Id; In_Tree : Project_Tree_Ref)
345 Current : String_List_Id := Source_Dirs;
346 Source_Dir : String_Element;
350 -- Add each source directory
352 while Current /= Nil_String loop
353 Source_Dir := In_Tree.String_Elements.Table (Current);
356 -- Check if the source directory is already in the table
358 for Index in Source_Path_Table.First ..
359 Source_Path_Table.Last
360 (In_Tree.Private_Part.Source_Paths)
362 -- If it is already, no need to add it
364 if In_Tree.Private_Part.Source_Paths.Table (Index) =
373 Source_Path_Table.Increment_Last
374 (In_Tree.Private_Part.Source_Paths);
375 In_Tree.Private_Part.Source_Paths.Table
376 (Source_Path_Table.Last (In_Tree.Private_Part.Source_Paths)) :=
380 -- Next source directory
382 Current := Source_Dir.Next;
384 end Add_To_Source_Path;
386 --------------------------------
387 -- Create_Config_Pragmas_File --
388 --------------------------------
390 procedure Create_Config_Pragmas_File
391 (For_Project : Project_Id;
392 Main_Project : Project_Id;
393 In_Tree : Project_Tree_Ref;
394 Include_Config_Files : Boolean := True)
396 pragma Unreferenced (Main_Project);
397 pragma Unreferenced (Include_Config_Files);
399 File_Name : Path_Name_Type := No_Path;
400 File : File_Descriptor := Invalid_FD;
402 Current_Unit : Unit_Index := Unit_Table.First;
404 First_Project : Project_List;
406 Current_Project : Project_List;
407 Current_Naming : Naming_Id;
412 procedure Check (Project : Project_Id);
413 -- Recursive procedure that put in the config pragmas file any non
414 -- standard naming schemes, if it is not already in the file, then call
415 -- itself for any imported project.
417 procedure Check_Temp_File;
418 -- Check that a temporary file has been opened.
419 -- If not, create one, and put its name in the project data,
420 -- with the indication that it is a temporary file.
423 (Unit_Name : Name_Id;
424 File_Name : File_Name_Type;
425 Unit_Kind : Spec_Or_Body;
427 -- Put an SFN pragma in the temporary file
429 procedure Put (File : File_Descriptor; S : String);
430 procedure Put_Line (File : File_Descriptor; S : String);
431 -- Output procedures, analogous to normal Text_IO procs of same name
437 procedure Check (Project : Project_Id) is
438 Data : constant Project_Data :=
439 In_Tree.Projects.Table (Project);
442 if Current_Verbosity = High then
443 Write_Str ("Checking project file """);
444 Write_Str (Namet.Get_Name_String (Data.Name));
449 -- Is this project in the list of the visited project?
451 Current_Project := First_Project;
452 while Current_Project /= null
453 and then Current_Project.Project /= Project
455 Current_Project := Current_Project.Next;
458 -- If it is not, put it in the list, and visit it
460 if Current_Project = null then
461 First_Project := new Project_List_Element'
463 Next => First_Project);
465 -- Is the naming scheme of this project one that we know?
467 Current_Naming := Default_Naming;
468 while Current_Naming <=
469 Naming_Table.Last (In_Tree.Private_Part.Namings)
470 and then not Same_Naming_Scheme
471 (Left => In_Tree.Private_Part.Namings.Table (Current_Naming),
472 Right => Data.Naming) loop
473 Current_Naming := Current_Naming + 1;
476 -- If we don't know it, add it
479 Naming_Table.Last (In_Tree.Private_Part.Namings)
481 Naming_Table.Increment_Last (In_Tree.Private_Part.Namings);
482 In_Tree.Private_Part.Namings.Table
483 (Naming_Table.Last (In_Tree.Private_Part.Namings)) :=
486 -- We need a temporary file to be created
490 -- Put the SFN pragmas for the naming scheme
495 (File, "pragma Source_File_Name_Project");
497 (File, " (Spec_File_Name => ""*" &
498 Spec_Suffix_Of (In_Tree, "ada", Data.Naming) &
501 (File, " Casing => " &
502 Image (Data.Naming.Casing) & ",");
504 (File, " Dot_Replacement => """ &
505 Namet.Get_Name_String (Data.Naming.Dot_Replacement) &
511 (File, "pragma Source_File_Name_Project");
513 (File, " (Body_File_Name => ""*" &
514 Body_Suffix_Of (In_Tree, "ada", Data.Naming) &
517 (File, " Casing => " &
518 Image (Data.Naming.Casing) & ",");
520 (File, " Dot_Replacement => """ &
521 Namet.Get_Name_String (Data.Naming.Dot_Replacement) &
524 -- and maybe separate
526 if Body_Suffix_Of (In_Tree, "ada", Data.Naming) /=
527 Get_Name_String (Data.Naming.Separate_Suffix)
530 (File, "pragma Source_File_Name_Project");
532 (File, " (Subunit_File_Name => ""*" &
533 Namet.Get_Name_String (Data.Naming.Separate_Suffix) &
536 (File, " Casing => " &
537 Image (Data.Naming.Casing) &
540 (File, " Dot_Replacement => """ &
541 Namet.Get_Name_String (Data.Naming.Dot_Replacement) &
546 if Data.Extends /= No_Project then
547 Check (Data.Extends);
551 Current : Project_List := Data.Imported_Projects;
553 while Current /= null loop
554 Check (Current.Project);
555 Current := Current.Next;
561 ---------------------
562 -- Check_Temp_File --
563 ---------------------
565 procedure Check_Temp_File is
567 if File = Invalid_FD then
568 Tempdir.Create_Temp_File (File, Name => File_Name);
570 if File = Invalid_FD then
572 ("unable to create temporary configuration pragmas file");
575 Record_Temp_File (File_Name);
577 if Opt.Verbose_Mode then
578 Write_Str ("Creating temp file """);
579 Write_Str (Get_Name_String (File_Name));
591 (Unit_Name : Name_Id;
592 File_Name : File_Name_Type;
593 Unit_Kind : Spec_Or_Body;
597 -- A temporary file needs to be open
601 -- Put the pragma SFN for the unit kind (spec or body)
603 Put (File, "pragma Source_File_Name_Project (");
604 Put (File, Namet.Get_Name_String (Unit_Name));
606 if Unit_Kind = Specification then
607 Put (File, ", Spec_File_Name => """);
609 Put (File, ", Body_File_Name => """);
612 Put (File, Namet.Get_Name_String (File_Name));
616 Put (File, ", Index =>");
617 Put (File, Index'Img);
620 Put_Line (File, ");");
623 procedure Put (File : File_Descriptor; S : String) is
627 Last := Write (File, S (S'First)'Address, S'Length);
629 if Last /= S'Length then
630 Prj.Com.Fail ("Disk full");
633 if Current_Verbosity = High then
642 procedure Put_Line (File : File_Descriptor; S : String) is
643 S0 : String (1 .. S'Length + 1);
647 -- Add an ASCII.LF to the string. As this config file is supposed to
648 -- be used only by the compiler, we don't care about the characters
649 -- for the end of line. In fact we could have put a space, but
650 -- it is more convenient to be able to read gnat.adc during
651 -- development, for which the ASCII.LF is fine.
653 S0 (1 .. S'Length) := S;
654 S0 (S0'Last) := ASCII.LF;
655 Last := Write (File, S0'Address, S0'Length);
657 if Last /= S'Length + 1 then
658 Prj.Com.Fail ("Disk full");
661 if Current_Verbosity = High then
666 -- Start of processing for Create_Config_Pragmas_File
670 In_Tree.Projects.Table (For_Project).Config_Checked
673 -- Remove any memory of processed naming schemes, if any
675 Naming_Table.Set_Last (In_Tree.Private_Part.Namings, Default_Naming);
677 -- Check the naming schemes
681 -- Visit all the units and process those that need an SFN pragma
684 Current_Unit <= Unit_Table.Last (In_Tree.Units)
687 Unit : constant Unit_Data :=
688 In_Tree.Units.Table (Current_Unit);
691 if Unit.File_Names (Specification).Needs_Pragma then
693 Unit.File_Names (Specification).Name,
695 Unit.File_Names (Specification).Index);
698 if Unit.File_Names (Body_Part).Needs_Pragma then
700 Unit.File_Names (Body_Part).Name,
702 Unit.File_Names (Body_Part).Index);
705 Current_Unit := Current_Unit + 1;
709 -- If there are no non standard naming scheme, issue the GNAT
710 -- standard naming scheme. This will tell the compiler that
711 -- a project file is used and will forbid any pragma SFN.
713 if File = Invalid_FD then
716 Put_Line (File, "pragma Source_File_Name_Project");
717 Put_Line (File, " (Spec_File_Name => ""*.ads"",");
718 Put_Line (File, " Dot_Replacement => ""-"",");
719 Put_Line (File, " Casing => lowercase);");
721 Put_Line (File, "pragma Source_File_Name_Project");
722 Put_Line (File, " (Body_File_Name => ""*.adb"",");
723 Put_Line (File, " Dot_Replacement => ""-"",");
724 Put_Line (File, " Casing => lowercase);");
727 -- Close the temporary file
729 GNAT.OS_Lib.Close (File, Status);
732 Prj.Com.Fail ("disk full");
735 if Opt.Verbose_Mode then
736 Write_Str ("Closing configuration file """);
737 Write_Str (Get_Name_String (File_Name));
741 In_Tree.Projects.Table (For_Project).Config_File_Name :=
743 In_Tree.Projects.Table (For_Project).Config_File_Temp :=
746 In_Tree.Projects.Table (For_Project).Config_Checked :=
749 end Create_Config_Pragmas_File;
755 procedure Create_Mapping (In_Tree : Project_Tree_Ref) is
756 The_Unit_Data : Unit_Data;
757 Data : File_Name_Data;
762 for Unit in 1 .. Unit_Table.Last (In_Tree.Units) loop
763 The_Unit_Data := In_Tree.Units.Table (Unit);
765 -- Process only if the unit has a valid name
767 if The_Unit_Data.Name /= No_Name then
768 Data := The_Unit_Data.File_Names (Specification);
770 -- If there is a spec, put it in the mapping
772 if Data.Name /= No_File then
773 if Data.Path.Name = Slash then
774 Fmap.Add_Forbidden_File_Name (Data.Name);
777 (Unit_Name => Unit_Name_Type (The_Unit_Data.Name),
778 File_Name => Data.Name,
779 Path_Name => File_Name_Type (Data.Path.Name));
783 Data := The_Unit_Data.File_Names (Body_Part);
785 -- If there is a body (or subunit) put it in the mapping
787 if Data.Name /= No_File then
788 if Data.Path.Name = Slash then
789 Fmap.Add_Forbidden_File_Name (Data.Name);
792 (Unit_Name => Unit_Name_Type (The_Unit_Data.Name),
793 File_Name => Data.Name,
794 Path_Name => File_Name_Type (Data.Path.Name));
801 -------------------------
802 -- Create_Mapping_File --
803 -------------------------
805 procedure Create_Mapping_File
806 (Project : Project_Id;
807 Language : Name_Id := No_Name;
808 In_Tree : Project_Tree_Ref;
809 Name : out Path_Name_Type)
811 File : File_Descriptor := Invalid_FD;
814 Present : array (No_Project .. Project_Table.Last (In_Tree.Projects))
815 of Boolean := (others => False);
816 -- For each project in the closure of Project, the corresponding flag
817 -- will be set to True.
820 Suffix : File_Name_Type;
821 The_Unit_Data : Unit_Data;
822 Data : File_Name_Data;
823 Iter : Source_Iterator;
825 procedure Put_Name_Buffer;
826 -- Put the line contained in the Name_Buffer in the mapping file
828 procedure Put_Data (Spec : Boolean);
829 -- Put the mapping of the spec or body contained in Data in the file
832 procedure Recursive_Flag (Prj : Project_Id);
833 -- Set the flags corresponding to Prj, the projects it imports
834 -- (directly or indirectly) or extends to True. Call itself recursively.
840 procedure Put_Name_Buffer is
844 Name_Len := Name_Len + 1;
845 Name_Buffer (Name_Len) := ASCII.LF;
846 Last := Write (File, Name_Buffer (1)'Address, Name_Len);
848 if Last /= Name_Len then
849 Prj.Com.Fail ("Disk full, cannot write mapping file");
857 procedure Put_Data (Spec : Boolean) is
859 -- Line with the unit name
861 Get_Name_String (The_Unit_Data.Name);
862 Name_Len := Name_Len + 1;
863 Name_Buffer (Name_Len) := '%';
864 Name_Len := Name_Len + 1;
867 Name_Buffer (Name_Len) := 's';
869 Name_Buffer (Name_Len) := 'b';
874 -- Line with the file name
876 Get_Name_String (Data.Name);
879 -- Line with the path name
881 Get_Name_String (Data.Path.Name);
889 procedure Recursive_Flag (Prj : Project_Id) is
890 Imported : Project_List;
893 -- Nothing to do for non existent project or project that has already
896 if Prj /= No_Project and then not Present (Prj) then
897 Present (Prj) := True;
899 Imported := In_Tree.Projects.Table (Prj).Imported_Projects;
900 while Imported /= null loop
901 Recursive_Flag (Imported.Project);
902 Imported := Imported.Next;
905 Recursive_Flag (In_Tree.Projects.Table (Prj).Extends);
909 -- Start of processing for Create_Mapping_File
912 -- Flag the necessary projects
914 Recursive_Flag (Project);
916 -- Create the temporary file
918 Tempdir.Create_Temp_File (File, Name => Name);
920 if File = Invalid_FD then
921 Prj.Com.Fail ("unable to create temporary mapping file");
924 Record_Temp_File (Name);
926 if Opt.Verbose_Mode then
927 Write_Str ("Creating temp mapping file """);
928 Write_Str (Get_Name_String (Name));
933 if Language = No_Name then
934 if In_Tree.Private_Part.Fill_Mapping_File then
935 for Unit in 1 .. Unit_Table.Last (In_Tree.Units) loop
936 The_Unit_Data := In_Tree.Units.Table (Unit);
938 -- Case of unit has a valid name
940 if The_Unit_Data.Name /= No_Name then
941 Data := The_Unit_Data.File_Names (Specification);
943 -- If there is a spec, put it mapping in the file if it is
944 -- from a project in the closure of Project.
946 if Data.Name /= No_File and then Present (Data.Project) then
947 Put_Data (Spec => True);
950 Data := The_Unit_Data.File_Names (Body_Part);
952 -- If there is a body (or subunit) put its mapping in the
953 -- file if it is from a project in the closure of Project.
955 if Data.Name /= No_File and then Present (Data.Project) then
956 Put_Data (Spec => False);
962 -- If language is defined
964 -- For all source of the Language of all projects in the closure
966 for Proj in Present'Range loop
967 if Present (Proj) then
969 Iter := For_Each_Source (In_Tree, Proj);
971 Source := Prj.Element (Iter);
972 exit when Source = No_Source;
974 if Source.Language.Name = Language
975 and then not Source.Locally_Removed
976 and then Source.Replaced_By = No_Source
977 and then Source.Path.Name /= No_Path
979 if Source.Unit /= No_Name then
980 Get_Name_String (Source.Unit);
982 if Source.Kind = Spec then
984 Source.Language.Config.Mapping_Spec_Suffix;
987 Source.Language.Config.Mapping_Body_Suffix;
990 if Suffix /= No_File then
991 Add_Str_To_Name_Buffer (Get_Name_String (Suffix));
997 Get_Name_String (Source.File);
1000 Get_Name_String (Source.Path.Name);
1010 GNAT.OS_Lib.Close (File, Status);
1014 -- We were able to create the temporary file, so there is no problem
1015 -- of protection. However, we are not able to close it, so there must
1016 -- be a capacity problem that we express using "disk full".
1018 Prj.Com.Fail ("disk full, could not write mapping file");
1020 end Create_Mapping_File;
1022 --------------------------
1023 -- Create_New_Path_File --
1024 --------------------------
1026 procedure Create_New_Path_File
1027 (In_Tree : Project_Tree_Ref;
1028 Path_FD : out File_Descriptor;
1029 Path_Name : out Path_Name_Type)
1032 Tempdir.Create_Temp_File (Path_FD, Path_Name);
1034 if Path_Name /= No_Path then
1035 Record_Temp_File (Path_Name);
1037 -- Record the name, so that the temp path file will be deleted at the
1038 -- end of the program.
1040 Path_File_Table.Increment_Last (In_Tree.Private_Part.Path_Files);
1041 In_Tree.Private_Part.Path_Files.Table
1042 (Path_File_Table.Last (In_Tree.Private_Part.Path_Files)) :=
1045 end Create_New_Path_File;
1047 ---------------------------
1048 -- Delete_All_Path_Files --
1049 ---------------------------
1051 procedure Delete_All_Path_Files (In_Tree : Project_Tree_Ref) is
1052 Disregard : Boolean := True;
1053 pragma Warnings (Off, Disregard);
1056 for Index in Path_File_Table.First ..
1057 Path_File_Table.Last (In_Tree.Private_Part.Path_Files)
1059 if In_Tree.Private_Part.Path_Files.Table (Index) /= No_Path then
1062 (In_Tree.Private_Part.Path_Files.Table (Index)),
1067 -- If any of the environment variables ADA_PRJ_INCLUDE_FILE or
1068 -- ADA_PRJ_OBJECTS_FILE has been set, then reset their value to
1069 -- the empty string. On VMS, this has the effect of deassigning
1070 -- the logical names.
1072 if In_Tree.Private_Part.Ada_Prj_Include_File_Set then
1073 Setenv (Project_Include_Path_File, "");
1074 In_Tree.Private_Part.Ada_Prj_Include_File_Set := False;
1077 if In_Tree.Private_Part.Ada_Prj_Objects_File_Set then
1078 Setenv (Project_Objects_Path_File, "");
1079 In_Tree.Private_Part.Ada_Prj_Objects_File_Set := False;
1081 end Delete_All_Path_Files;
1083 ------------------------------------
1084 -- File_Name_Of_Library_Unit_Body --
1085 ------------------------------------
1087 function File_Name_Of_Library_Unit_Body
1089 Project : Project_Id;
1090 In_Tree : Project_Tree_Ref;
1091 Main_Project_Only : Boolean := True;
1092 Full_Path : Boolean := False) return String
1094 The_Project : Project_Id := Project;
1095 Data : Project_Data :=
1096 In_Tree.Projects.Table (Project);
1097 Original_Name : String := Name;
1099 Extended_Spec_Name : String :=
1101 Spec_Suffix_Of (In_Tree, "ada", Data.Naming);
1102 Extended_Body_Name : String :=
1104 Body_Suffix_Of (In_Tree, "ada", Data.Naming);
1108 The_Original_Name : Name_Id;
1109 The_Spec_Name : Name_Id;
1110 The_Body_Name : Name_Id;
1113 Canonical_Case_File_Name (Original_Name);
1114 Name_Len := Original_Name'Length;
1115 Name_Buffer (1 .. Name_Len) := Original_Name;
1116 The_Original_Name := Name_Find;
1118 Canonical_Case_File_Name (Extended_Spec_Name);
1119 Name_Len := Extended_Spec_Name'Length;
1120 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1121 The_Spec_Name := Name_Find;
1123 Canonical_Case_File_Name (Extended_Body_Name);
1124 Name_Len := Extended_Body_Name'Length;
1125 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1126 The_Body_Name := Name_Find;
1128 if Current_Verbosity = High then
1129 Write_Str ("Looking for file name of """);
1133 Write_Str (" Extended Spec Name = """);
1134 Write_Str (Extended_Spec_Name);
1137 Write_Str (" Extended Body Name = """);
1138 Write_Str (Extended_Body_Name);
1143 -- For extending project, search in the extended project if the source
1144 -- is not found. For non extending projects, this loop will be run only
1148 -- Loop through units
1149 -- Should have comment explaining reverse ???
1151 for Current in reverse Unit_Table.First ..
1152 Unit_Table.Last (In_Tree.Units)
1154 Unit := In_Tree.Units.Table (Current);
1158 if not Main_Project_Only
1159 or else Unit.File_Names (Body_Part).Project = The_Project
1162 Current_Name : constant File_Name_Type :=
1163 Unit.File_Names (Body_Part).Name;
1166 -- Case of a body present
1168 if Current_Name /= No_File then
1169 if Current_Verbosity = High then
1170 Write_Str (" Comparing with """);
1171 Write_Str (Get_Name_String (Current_Name));
1176 -- If it has the name of the original name, return the
1179 if Unit.Name = The_Original_Name
1181 Current_Name = File_Name_Type (The_Original_Name)
1183 if Current_Verbosity = High then
1188 return Get_Name_String
1189 (Unit.File_Names (Body_Part).Path.Name);
1192 return Get_Name_String (Current_Name);
1195 -- If it has the name of the extended body name,
1196 -- return the extended body name
1198 elsif Current_Name = File_Name_Type (The_Body_Name) then
1199 if Current_Verbosity = High then
1204 return Get_Name_String
1205 (Unit.File_Names (Body_Part).Path.Name);
1208 return Extended_Body_Name;
1212 if Current_Verbosity = High then
1213 Write_Line (" not good");
1222 if not Main_Project_Only
1223 or else Unit.File_Names (Specification).Project = The_Project
1226 Current_Name : constant File_Name_Type :=
1227 Unit.File_Names (Specification).Name;
1230 -- Case of spec present
1232 if Current_Name /= No_File then
1233 if Current_Verbosity = High then
1234 Write_Str (" Comparing with """);
1235 Write_Str (Get_Name_String (Current_Name));
1240 -- If name same as original name, return original name
1242 if Unit.Name = The_Original_Name
1244 Current_Name = File_Name_Type (The_Original_Name)
1246 if Current_Verbosity = High then
1251 return Get_Name_String
1252 (Unit.File_Names (Specification).Path.Name);
1254 return Get_Name_String (Current_Name);
1257 -- If it has the same name as the extended spec name,
1258 -- return the extended spec name.
1260 elsif Current_Name = File_Name_Type (The_Spec_Name) then
1261 if Current_Verbosity = High then
1266 return Get_Name_String
1267 (Unit.File_Names (Specification).Path.Name);
1269 return Extended_Spec_Name;
1273 if Current_Verbosity = High then
1274 Write_Line (" not good");
1282 -- If we are not in an extending project, give up
1284 exit when (not Main_Project_Only) or else Data.Extends = No_Project;
1286 -- Otherwise, look in the project we are extending
1288 The_Project := Data.Extends;
1289 Data := In_Tree.Projects.Table (The_Project);
1292 -- We don't know this file name, return an empty string
1295 end File_Name_Of_Library_Unit_Body;
1297 -------------------------
1298 -- For_All_Object_Dirs --
1299 -------------------------
1301 procedure For_All_Object_Dirs
1302 (Project : Project_Id;
1303 In_Tree : Project_Tree_Ref)
1305 procedure For_Project (Prj : Project_Id; Dummy : in out Integer);
1306 -- Get all object directories of Prj
1312 procedure For_Project (Prj : Project_Id; Dummy : in out Integer) is
1313 pragma Unreferenced (Dummy);
1315 Data : Project_Data renames In_Tree.Projects.Table (Prj);
1318 -- ??? Set_Ada_Paths has a different behavior for library project
1319 -- files, should we have the same ?
1321 if Data.Object_Directory /= No_Path_Information then
1322 Get_Name_String (Data.Object_Directory.Display_Name);
1323 Action (Name_Buffer (1 .. Name_Len));
1327 procedure Get_Object_Dirs is
1328 new For_Every_Project_Imported (Integer, For_Project);
1329 Dummy : Integer := 1;
1331 -- Start of processing for For_All_Object_Dirs
1334 Get_Object_Dirs (Project, In_Tree, Dummy);
1335 end For_All_Object_Dirs;
1337 -------------------------
1338 -- For_All_Source_Dirs --
1339 -------------------------
1341 procedure For_All_Source_Dirs
1342 (Project : Project_Id;
1343 In_Tree : Project_Tree_Ref)
1345 procedure For_Project (Prj : Project_Id; Dummy : in out Integer);
1346 -- Get all object directories of Prj
1352 procedure For_Project (Prj : Project_Id; Dummy : in out Integer) is
1353 pragma Unreferenced (Dummy);
1355 Data : Project_Data renames In_Tree.Projects.Table (Prj);
1356 Current : String_List_Id := Data.Source_Dirs;
1357 The_String : String_Element;
1360 -- If there are Ada sources, call action with the name of every
1361 -- source directory.
1363 if Has_Ada_Sources (In_Tree.Projects.Table (Project)) then
1364 while Current /= Nil_String loop
1365 The_String := In_Tree.String_Elements.Table (Current);
1366 Action (Get_Name_String (The_String.Display_Value));
1367 Current := The_String.Next;
1372 procedure Get_Source_Dirs is
1373 new For_Every_Project_Imported (Integer, For_Project);
1374 Dummy : Integer := 1;
1376 -- Start of processing for For_All_Source_Dirs
1379 Get_Source_Dirs (Project, In_Tree, Dummy);
1380 end For_All_Source_Dirs;
1386 procedure Get_Reference
1387 (Source_File_Name : String;
1388 In_Tree : Project_Tree_Ref;
1389 Project : out Project_Id;
1390 Path : out Path_Name_Type)
1393 -- Body below could use some comments ???
1395 if Current_Verbosity > Default then
1396 Write_Str ("Getting Reference_Of (""");
1397 Write_Str (Source_File_Name);
1398 Write_Str (""") ... ");
1402 Original_Name : String := Source_File_Name;
1406 Canonical_Case_File_Name (Original_Name);
1408 for Id in Unit_Table.First ..
1409 Unit_Table.Last (In_Tree.Units)
1411 Unit := In_Tree.Units.Table (Id);
1413 if (Unit.File_Names (Specification).Name /= No_File
1415 Namet.Get_Name_String
1416 (Unit.File_Names (Specification).Name) = Original_Name)
1417 or else (Unit.File_Names (Specification).Path /=
1420 Namet.Get_Name_String
1421 (Unit.File_Names (Specification).Path.Name) =
1424 Project := Ultimate_Extension_Of
1425 (Project => Unit.File_Names (Specification).Project,
1426 In_Tree => In_Tree);
1427 Path := Unit.File_Names (Specification).Path.Display_Name;
1429 if Current_Verbosity > Default then
1430 Write_Str ("Done: Specification.");
1436 elsif (Unit.File_Names (Body_Part).Name /= No_File
1438 Namet.Get_Name_String
1439 (Unit.File_Names (Body_Part).Name) = Original_Name)
1440 or else (Unit.File_Names (Body_Part).Path /= No_Path_Information
1441 and then Namet.Get_Name_String
1442 (Unit.File_Names (Body_Part).Path.Name) =
1445 Project := Ultimate_Extension_Of
1446 (Project => Unit.File_Names (Body_Part).Project,
1447 In_Tree => In_Tree);
1448 Path := Unit.File_Names (Body_Part).Path.Display_Name;
1450 if Current_Verbosity > Default then
1451 Write_Str ("Done: Body.");
1460 Project := No_Project;
1463 if Current_Verbosity > Default then
1464 Write_Str ("Cannot be found.");
1473 procedure Initialize (In_Tree : Project_Tree_Ref) is
1475 In_Tree.Private_Part.Fill_Mapping_File := True;
1476 In_Tree.Private_Part.Current_Source_Path_File := No_Path;
1477 In_Tree.Private_Part.Current_Object_Path_File := No_Path;
1484 -- Could use some comments in this body ???
1486 procedure Print_Sources (In_Tree : Project_Tree_Ref) is
1490 Write_Line ("List of Sources:");
1492 for Id in Unit_Table.First ..
1493 Unit_Table.Last (In_Tree.Units)
1495 Unit := In_Tree.Units.Table (Id);
1497 Write_Line (Namet.Get_Name_String (Unit.Name));
1499 if Unit.File_Names (Specification).Name /= No_File then
1500 if Unit.File_Names (Specification).Project = No_Project then
1501 Write_Line (" No project");
1504 Write_Str (" Project: ");
1506 (In_Tree.Projects.Table
1507 (Unit.File_Names (Specification).Project).Path.Name);
1508 Write_Line (Name_Buffer (1 .. Name_Len));
1511 Write_Str (" spec: ");
1513 (Namet.Get_Name_String
1514 (Unit.File_Names (Specification).Name));
1517 if Unit.File_Names (Body_Part).Name /= No_File then
1518 if Unit.File_Names (Body_Part).Project = No_Project then
1519 Write_Line (" No project");
1522 Write_Str (" Project: ");
1524 (In_Tree.Projects.Table
1525 (Unit.File_Names (Body_Part).Project).Path.Name);
1526 Write_Line (Name_Buffer (1 .. Name_Len));
1529 Write_Str (" body: ");
1531 (Namet.Get_Name_String
1532 (Unit.File_Names (Body_Part).Name));
1536 Write_Line ("end of List of Sources.");
1545 Main_Project : Project_Id;
1546 In_Tree : Project_Tree_Ref) return Project_Id
1548 Result : Project_Id := No_Project;
1550 Original_Name : String := Name;
1552 Data : constant Project_Data :=
1553 In_Tree.Projects.Table (Main_Project);
1555 Extended_Spec_Name : String :=
1557 Spec_Suffix_Of (In_Tree, "ada", Data.Naming);
1558 Extended_Body_Name : String :=
1560 Body_Suffix_Of (In_Tree, "ada", Data.Naming);
1564 Current_Name : File_Name_Type;
1565 The_Original_Name : File_Name_Type;
1566 The_Spec_Name : File_Name_Type;
1567 The_Body_Name : File_Name_Type;
1570 Canonical_Case_File_Name (Original_Name);
1571 Name_Len := Original_Name'Length;
1572 Name_Buffer (1 .. Name_Len) := Original_Name;
1573 The_Original_Name := Name_Find;
1575 Canonical_Case_File_Name (Extended_Spec_Name);
1576 Name_Len := Extended_Spec_Name'Length;
1577 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1578 The_Spec_Name := Name_Find;
1580 Canonical_Case_File_Name (Extended_Body_Name);
1581 Name_Len := Extended_Body_Name'Length;
1582 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1583 The_Body_Name := Name_Find;
1585 for Current in reverse Unit_Table.First ..
1586 Unit_Table.Last (In_Tree.Units)
1588 Unit := In_Tree.Units.Table (Current);
1592 Current_Name := Unit.File_Names (Body_Part).Name;
1594 -- Case of a body present
1596 if Current_Name /= No_File then
1598 -- If it has the name of the original name or the body name,
1599 -- we have found the project.
1601 if Unit.Name = Name_Id (The_Original_Name)
1602 or else Current_Name = The_Original_Name
1603 or else Current_Name = The_Body_Name
1605 Result := Unit.File_Names (Body_Part).Project;
1612 Current_Name := Unit.File_Names (Specification).Name;
1614 if Current_Name /= No_File then
1616 -- If name same as the original name, or the spec name, we have
1617 -- found the project.
1619 if Unit.Name = Name_Id (The_Original_Name)
1620 or else Current_Name = The_Original_Name
1621 or else Current_Name = The_Spec_Name
1623 Result := Unit.File_Names (Specification).Project;
1629 -- Get the ultimate extending project
1631 if Result /= No_Project then
1632 while In_Tree.Projects.Table (Result).Extended_By /=
1635 Result := In_Tree.Projects.Table (Result).Extended_By;
1646 procedure Set_Ada_Paths
1647 (Project : Project_Id;
1648 In_Tree : Project_Tree_Ref;
1649 Including_Libraries : Boolean)
1652 Source_FD : File_Descriptor := Invalid_FD;
1653 Object_FD : File_Descriptor := Invalid_FD;
1655 Process_Source_Dirs : Boolean := False;
1656 Process_Object_Dirs : Boolean := False;
1659 -- For calls to Close
1663 procedure Recursive_Add (Project : Project_Id; Dummy : in out Boolean);
1664 -- Recursive procedure to add the source/object paths of extended/
1665 -- imported projects.
1671 procedure Recursive_Add (Project : Project_Id; Dummy : in out Boolean) is
1672 pragma Unreferenced (Dummy);
1674 Data : constant Project_Data := In_Tree.Projects.Table (Project);
1675 Path : Path_Name_Type;
1678 -- ??? This is almost the equivalent of For_All_Source_Dirs
1680 if Process_Source_Dirs then
1682 -- Add to path all source directories of this project if there are
1685 if Has_Ada_Sources (In_Tree.Projects.Table (Project)) then
1686 Add_To_Source_Path (Data.Source_Dirs, In_Tree);
1690 if Process_Object_Dirs then
1691 Path := Get_Object_Directory
1693 Including_Libraries => Including_Libraries,
1694 Only_If_Ada => True);
1696 if Path /= No_Path then
1697 Add_To_Object_Path (Path, In_Tree);
1702 procedure For_All_Projects is
1703 new For_Every_Project_Imported (Boolean, Recursive_Add);
1704 Dummy : Boolean := False;
1706 -- Start of processing for Set_Ada_Paths
1709 -- If it is the first time we call this procedure for this project,
1710 -- compute the source path and/or the object path.
1712 if In_Tree.Projects.Table (Project).Include_Path_File = No_Path then
1713 Process_Source_Dirs := True;
1714 Create_New_Path_File
1715 (In_Tree, Source_FD,
1716 In_Tree.Projects.Table (Project).Include_Path_File);
1719 -- For the object path, we make a distinction depending on
1720 -- Including_Libraries.
1722 if Including_Libraries then
1723 if In_Tree.Projects.Table
1724 (Project).Objects_Path_File_With_Libs = No_Path
1726 Process_Object_Dirs := True;
1727 Create_New_Path_File
1728 (In_Tree, Object_FD, In_Tree.Projects.Table (Project).
1729 Objects_Path_File_With_Libs);
1733 if In_Tree.Projects.Table
1734 (Project).Objects_Path_File_Without_Libs = No_Path
1736 Process_Object_Dirs := True;
1737 Create_New_Path_File
1738 (In_Tree, Object_FD, In_Tree.Projects.Table (Project).
1739 Objects_Path_File_Without_Libs);
1743 -- If there is something to do, set Seen to False for all projects,
1744 -- then call the recursive procedure Add for Project.
1746 if Process_Source_Dirs or Process_Object_Dirs then
1747 Source_Path_Table.Set_Last (In_Tree.Private_Part.Source_Paths, 0);
1748 Object_Path_Table.Set_Last (In_Tree.Private_Part.Object_Paths, 0);
1749 For_All_Projects (Project, In_Tree, Dummy);
1752 -- Write and close any file that has been created
1754 if Source_FD /= Invalid_FD then
1755 for Index in Source_Path_Table.First ..
1756 Source_Path_Table.Last
1757 (In_Tree.Private_Part.Source_Paths)
1759 Get_Name_String (In_Tree.Private_Part.Source_Paths.Table (Index));
1760 Name_Len := Name_Len + 1;
1761 Name_Buffer (Name_Len) := ASCII.LF;
1762 Len := Write (Source_FD, Name_Buffer (1)'Address, Name_Len);
1764 if Len /= Name_Len then
1765 Prj.Com.Fail ("disk full");
1769 Close (Source_FD, Status);
1772 Prj.Com.Fail ("disk full");
1776 if Object_FD /= Invalid_FD then
1777 for Index in Object_Path_Table.First ..
1778 Object_Path_Table.Last
1779 (In_Tree.Private_Part.Object_Paths)
1781 Get_Name_String (In_Tree.Private_Part.Object_Paths.Table (Index));
1782 Name_Len := Name_Len + 1;
1783 Name_Buffer (Name_Len) := ASCII.LF;
1784 Len := Write (Object_FD, Name_Buffer (1)'Address, Name_Len);
1786 if Len /= Name_Len then
1787 Prj.Com.Fail ("disk full");
1791 Close (Object_FD, Status);
1794 Prj.Com.Fail ("disk full");
1798 -- Set the env vars, if they need to be changed, and set the
1799 -- corresponding flags.
1801 if In_Tree.Private_Part.Current_Source_Path_File /=
1802 In_Tree.Projects.Table (Project).Include_Path_File
1804 In_Tree.Private_Part.Current_Source_Path_File :=
1805 In_Tree.Projects.Table (Project).Include_Path_File;
1807 (Project_Include_Path_File,
1808 Get_Name_String (In_Tree.Private_Part.Current_Source_Path_File));
1809 In_Tree.Private_Part.Ada_Prj_Include_File_Set := True;
1812 if Including_Libraries then
1813 if In_Tree.Private_Part.Current_Object_Path_File /=
1814 In_Tree.Projects.Table (Project).Objects_Path_File_With_Libs
1816 In_Tree.Private_Part.Current_Object_Path_File :=
1817 In_Tree.Projects.Table
1818 (Project).Objects_Path_File_With_Libs;
1820 (Project_Objects_Path_File,
1822 (In_Tree.Private_Part.Current_Object_Path_File));
1823 In_Tree.Private_Part.Ada_Prj_Objects_File_Set := True;
1827 if In_Tree.Private_Part.Current_Object_Path_File /=
1828 In_Tree.Projects.Table (Project).Objects_Path_File_Without_Libs
1830 In_Tree.Private_Part.Current_Object_Path_File :=
1831 In_Tree.Projects.Table
1832 (Project).Objects_Path_File_Without_Libs;
1834 (Project_Objects_Path_File,
1836 (In_Tree.Private_Part.Current_Object_Path_File));
1837 In_Tree.Private_Part.Ada_Prj_Objects_File_Set := True;
1842 ---------------------------------------------
1843 -- Set_Mapping_File_Initial_State_To_Empty --
1844 ---------------------------------------------
1846 procedure Set_Mapping_File_Initial_State_To_Empty
1847 (In_Tree : Project_Tree_Ref)
1850 In_Tree.Private_Part.Fill_Mapping_File := False;
1851 end Set_Mapping_File_Initial_State_To_Empty;
1853 -----------------------
1854 -- Set_Path_File_Var --
1855 -----------------------
1857 procedure Set_Path_File_Var (Name : String; Value : String) is
1858 Host_Spec : String_Access := To_Host_File_Spec (Value);
1860 if Host_Spec = null then
1862 ("could not convert file name """ & Value & """ to host spec");
1864 Setenv (Name, Host_Spec.all);
1867 end Set_Path_File_Var;
1869 ---------------------------
1870 -- Ultimate_Extension_Of --
1871 ---------------------------
1873 function Ultimate_Extension_Of
1874 (Project : Project_Id;
1875 In_Tree : Project_Tree_Ref) return Project_Id
1877 Result : Project_Id := Project;
1880 while In_Tree.Projects.Table (Result).Extended_By /= No_Project loop
1881 Result := In_Tree.Projects.Table (Result).Extended_By;
1885 end Ultimate_Extension_Of;