more autogen definiton
[official-gcc.git] / gcc / ada / prj-env.adb
blob23d2cbf526f8c8833a4defdf7481d7cba3304d75
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- P R J . E N V --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2001-2012, Free Software Foundation, Inc. --
10 -- --
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. --
20 -- --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
23 -- --
24 ------------------------------------------------------------------------------
26 with Fmap;
27 with Hostparm;
28 with Makeutl; use Makeutl;
29 with Opt;
30 with Osint; use Osint;
31 with Output; use Output;
32 with Prj.Com; use Prj.Com;
33 with Sdefault;
34 with Tempdir;
36 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
38 package body Prj.Env is
40 Buffer_Initial : constant := 1_000;
41 -- Initial size of Buffer
43 Uninitialized_Prefix : constant String := '#' & Path_Separator;
44 -- Prefix to indicate that the project path has not been initialized yet.
45 -- Must be two characters long
47 No_Project_Default_Dir : constant String := "-";
48 -- Indicator in the project path to indicate that the default search
49 -- directories should not be added to the path
51 -----------------------
52 -- Local Subprograms --
53 -----------------------
55 package Source_Path_Table is new GNAT.Dynamic_Tables
56 (Table_Component_Type => Name_Id,
57 Table_Index_Type => Natural,
58 Table_Low_Bound => 1,
59 Table_Initial => 50,
60 Table_Increment => 100);
61 -- A table to store the source dirs before creating the source path file
63 package Object_Path_Table is new GNAT.Dynamic_Tables
64 (Table_Component_Type => Path_Name_Type,
65 Table_Index_Type => Natural,
66 Table_Low_Bound => 1,
67 Table_Initial => 50,
68 Table_Increment => 100);
69 -- A table to store the object dirs, before creating the object path file
71 procedure Add_To_Buffer
72 (S : String;
73 Buffer : in out String_Access;
74 Buffer_Last : in out Natural);
75 -- Add a string to Buffer, extending Buffer if needed
77 procedure Add_To_Path
78 (Source_Dirs : String_List_Id;
79 Shared : Shared_Project_Tree_Data_Access;
80 Buffer : in out String_Access;
81 Buffer_Last : in out Natural);
82 -- Add to Ada_Path_Buffer all the source directories in string list
83 -- Source_Dirs, if any.
85 procedure Add_To_Path
86 (Dir : String;
87 Buffer : in out String_Access;
88 Buffer_Last : in out Natural);
89 -- If Dir is not already in the global variable Ada_Path_Buffer, add it.
90 -- If Buffer_Last /= 0, prepend a Path_Separator character to Path.
92 procedure Add_To_Source_Path
93 (Source_Dirs : String_List_Id;
94 Shared : Shared_Project_Tree_Data_Access;
95 Source_Paths : in out Source_Path_Table.Instance);
96 -- Add to Ada_Path_B all the source directories in string list
97 -- Source_Dirs, if any. Increment Ada_Path_Length.
99 procedure Add_To_Object_Path
100 (Object_Dir : Path_Name_Type;
101 Object_Paths : in out Object_Path_Table.Instance);
102 -- Add Object_Dir to object path table. Make sure it is not duplicate
103 -- and it is the last one in the current table.
105 ----------------------
106 -- Ada_Include_Path --
107 ----------------------
109 function Ada_Include_Path
110 (Project : Project_Id;
111 In_Tree : Project_Tree_Ref;
112 Recursive : Boolean := False) return String
114 Buffer : String_Access;
115 Buffer_Last : Natural := 0;
117 procedure Add
118 (Project : Project_Id;
119 In_Tree : Project_Tree_Ref;
120 Dummy : in out Boolean);
121 -- Add source dirs of Project to the path
123 ---------
124 -- Add --
125 ---------
127 procedure Add
128 (Project : Project_Id;
129 In_Tree : Project_Tree_Ref;
130 Dummy : in out Boolean)
132 pragma Unreferenced (Dummy);
133 begin
134 Add_To_Path
135 (Project.Source_Dirs, In_Tree.Shared, Buffer, Buffer_Last);
136 end Add;
138 procedure For_All_Projects is
139 new For_Every_Project_Imported (Boolean, Add);
141 Dummy : Boolean := False;
143 -- Start of processing for Ada_Include_Path
145 begin
146 if Recursive then
148 -- If it is the first time we call this function for
149 -- this project, compute the source path
151 if Project.Ada_Include_Path = null then
152 Buffer := new String (1 .. 4096);
153 For_All_Projects
154 (Project, In_Tree, Dummy, Include_Aggregated => True);
155 Project.Ada_Include_Path := new String'(Buffer (1 .. Buffer_Last));
156 Free (Buffer);
157 end if;
159 return Project.Ada_Include_Path.all;
161 else
162 Buffer := new String (1 .. 4096);
163 Add_To_Path
164 (Project.Source_Dirs, In_Tree.Shared, Buffer, Buffer_Last);
166 declare
167 Result : constant String := Buffer (1 .. Buffer_Last);
168 begin
169 Free (Buffer);
170 return Result;
171 end;
172 end if;
173 end Ada_Include_Path;
175 ----------------------
176 -- Ada_Objects_Path --
177 ----------------------
179 function Ada_Objects_Path
180 (Project : Project_Id;
181 In_Tree : Project_Tree_Ref;
182 Including_Libraries : Boolean := True) return String_Access
184 Buffer : String_Access;
185 Buffer_Last : Natural := 0;
187 procedure Add
188 (Project : Project_Id;
189 In_Tree : Project_Tree_Ref;
190 Dummy : in out Boolean);
191 -- Add all the object directories of a project to the path
193 ---------
194 -- Add --
195 ---------
197 procedure Add
198 (Project : Project_Id;
199 In_Tree : Project_Tree_Ref;
200 Dummy : in out Boolean)
202 pragma Unreferenced (Dummy, In_Tree);
204 Path : constant Path_Name_Type :=
205 Get_Object_Directory
206 (Project,
207 Including_Libraries => Including_Libraries,
208 Only_If_Ada => False);
209 begin
210 if Path /= No_Path then
211 Add_To_Path (Get_Name_String (Path), Buffer, Buffer_Last);
212 end if;
213 end Add;
215 procedure For_All_Projects is
216 new For_Every_Project_Imported (Boolean, Add);
218 Dummy : Boolean := False;
220 -- Start of processing for Ada_Objects_Path
222 begin
223 -- If it is the first time we call this function for
224 -- this project, compute the objects path
226 if Project.Ada_Objects_Path = null then
227 Buffer := new String (1 .. 4096);
228 For_All_Projects (Project, In_Tree, Dummy);
230 Project.Ada_Objects_Path := new String'(Buffer (1 .. Buffer_Last));
231 Free (Buffer);
232 end if;
234 return Project.Ada_Objects_Path;
235 end Ada_Objects_Path;
237 -------------------
238 -- Add_To_Buffer --
239 -------------------
241 procedure Add_To_Buffer
242 (S : String;
243 Buffer : in out String_Access;
244 Buffer_Last : in out Natural)
246 Last : constant Natural := Buffer_Last + S'Length;
248 begin
249 while Last > Buffer'Last loop
250 declare
251 New_Buffer : constant String_Access :=
252 new String (1 .. 2 * Buffer'Last);
253 begin
254 New_Buffer (1 .. Buffer_Last) := Buffer (1 .. Buffer_Last);
255 Free (Buffer);
256 Buffer := New_Buffer;
257 end;
258 end loop;
260 Buffer (Buffer_Last + 1 .. Last) := S;
261 Buffer_Last := Last;
262 end Add_To_Buffer;
264 ------------------------
265 -- Add_To_Object_Path --
266 ------------------------
268 procedure Add_To_Object_Path
269 (Object_Dir : Path_Name_Type;
270 Object_Paths : in out Object_Path_Table.Instance)
272 begin
273 -- Check if the directory is already in the table
275 for Index in
276 Object_Path_Table.First .. Object_Path_Table.Last (Object_Paths)
277 loop
279 -- If it is, remove it, and add it as the last one
281 if Object_Paths.Table (Index) = Object_Dir then
282 for Index2 in
283 Index + 1 .. Object_Path_Table.Last (Object_Paths)
284 loop
285 Object_Paths.Table (Index2 - 1) := Object_Paths.Table (Index2);
286 end loop;
288 Object_Paths.Table
289 (Object_Path_Table.Last (Object_Paths)) := Object_Dir;
290 return;
291 end if;
292 end loop;
294 -- The directory is not already in the table, add it
296 Object_Path_Table.Append (Object_Paths, Object_Dir);
297 end Add_To_Object_Path;
299 -----------------
300 -- Add_To_Path --
301 -----------------
303 procedure Add_To_Path
304 (Source_Dirs : String_List_Id;
305 Shared : Shared_Project_Tree_Data_Access;
306 Buffer : in out String_Access;
307 Buffer_Last : in out Natural)
309 Current : String_List_Id := Source_Dirs;
310 Source_Dir : String_Element;
311 begin
312 while Current /= Nil_String loop
313 Source_Dir := Shared.String_Elements.Table (Current);
314 Add_To_Path (Get_Name_String (Source_Dir.Display_Value),
315 Buffer, Buffer_Last);
316 Current := Source_Dir.Next;
317 end loop;
318 end Add_To_Path;
320 procedure Add_To_Path
321 (Dir : String;
322 Buffer : in out String_Access;
323 Buffer_Last : in out Natural)
325 Len : Natural;
326 New_Buffer : String_Access;
327 Min_Len : Natural;
329 function Is_Present (Path : String; Dir : String) return Boolean;
330 -- Return True if Dir is part of Path
332 ----------------
333 -- Is_Present --
334 ----------------
336 function Is_Present (Path : String; Dir : String) return Boolean is
337 Last : constant Integer := Path'Last - Dir'Length + 1;
339 begin
340 for J in Path'First .. Last loop
342 -- Note: the order of the conditions below is important, since
343 -- it ensures a minimal number of string comparisons.
345 if (J = Path'First
346 or else Path (J - 1) = Path_Separator)
347 and then
348 (J + Dir'Length > Path'Last
349 or else Path (J + Dir'Length) = Path_Separator)
350 and then Dir = Path (J .. J + Dir'Length - 1)
351 then
352 return True;
353 end if;
354 end loop;
356 return False;
357 end Is_Present;
359 -- Start of processing for Add_To_Path
361 begin
362 if Is_Present (Buffer (1 .. Buffer_Last), Dir) then
364 -- Dir is already in the path, nothing to do
366 return;
367 end if;
369 Min_Len := Buffer_Last + Dir'Length;
371 if Buffer_Last > 0 then
373 -- Add 1 for the Path_Separator character
375 Min_Len := Min_Len + 1;
376 end if;
378 -- If Ada_Path_Buffer is too small, increase it
380 Len := Buffer'Last;
382 if Len < Min_Len then
383 loop
384 Len := Len * 2;
385 exit when Len >= Min_Len;
386 end loop;
388 New_Buffer := new String (1 .. Len);
389 New_Buffer (1 .. Buffer_Last) := Buffer (1 .. Buffer_Last);
390 Free (Buffer);
391 Buffer := New_Buffer;
392 end if;
394 if Buffer_Last > 0 then
395 Buffer_Last := Buffer_Last + 1;
396 Buffer (Buffer_Last) := Path_Separator;
397 end if;
399 Buffer (Buffer_Last + 1 .. Buffer_Last + Dir'Length) := Dir;
400 Buffer_Last := Buffer_Last + Dir'Length;
401 end Add_To_Path;
403 ------------------------
404 -- Add_To_Source_Path --
405 ------------------------
407 procedure Add_To_Source_Path
408 (Source_Dirs : String_List_Id;
409 Shared : Shared_Project_Tree_Data_Access;
410 Source_Paths : in out Source_Path_Table.Instance)
412 Current : String_List_Id := Source_Dirs;
413 Source_Dir : String_Element;
414 Add_It : Boolean;
416 begin
417 -- Add each source directory
419 while Current /= Nil_String loop
420 Source_Dir := Shared.String_Elements.Table (Current);
421 Add_It := True;
423 -- Check if the source directory is already in the table
425 for Index in
426 Source_Path_Table.First .. Source_Path_Table.Last (Source_Paths)
427 loop
428 -- If it is already, no need to add it
430 if Source_Paths.Table (Index) = Source_Dir.Value then
431 Add_It := False;
432 exit;
433 end if;
434 end loop;
436 if Add_It then
437 Source_Path_Table.Append (Source_Paths, Source_Dir.Display_Value);
438 end if;
440 -- Next source directory
442 Current := Source_Dir.Next;
443 end loop;
444 end Add_To_Source_Path;
446 --------------------------------
447 -- Create_Config_Pragmas_File --
448 --------------------------------
450 procedure Create_Config_Pragmas_File
451 (For_Project : Project_Id;
452 In_Tree : Project_Tree_Ref)
454 type Naming_Id is new Nat;
455 package Naming_Table is new GNAT.Dynamic_Tables
456 (Table_Component_Type => Lang_Naming_Data,
457 Table_Index_Type => Naming_Id,
458 Table_Low_Bound => 1,
459 Table_Initial => 5,
460 Table_Increment => 100);
462 Default_Naming : constant Naming_Id := Naming_Table.First;
463 Namings : Naming_Table.Instance;
464 -- Table storing the naming data for gnatmake/gprmake
466 Buffer : String_Access := new String (1 .. Buffer_Initial);
467 Buffer_Last : Natural := 0;
469 File_Name : Path_Name_Type := No_Path;
470 File : File_Descriptor := Invalid_FD;
472 Current_Naming : Naming_Id;
474 procedure Check
475 (Project : Project_Id;
476 In_Tree : Project_Tree_Ref;
477 State : in out Integer);
478 -- Recursive procedure that put in the config pragmas file any non
479 -- standard naming schemes, if it is not already in the file, then call
480 -- itself for any imported project.
482 procedure Put (Source : Source_Id);
483 -- Put an SFN pragma in the temporary file
485 procedure Put (S : String);
486 procedure Put_Line (S : String);
487 -- Output procedures, analogous to normal Text_IO procs of same name.
488 -- The text is put in Buffer, then it will be written into a temporary
489 -- file with procedure Write_Temp_File below.
491 procedure Write_Temp_File;
492 -- Create a temporary file and put the content of the buffer in it
494 -----------
495 -- Check --
496 -----------
498 procedure Check
499 (Project : Project_Id;
500 In_Tree : Project_Tree_Ref;
501 State : in out Integer)
503 pragma Unreferenced (State);
505 Lang : constant Language_Ptr :=
506 Get_Language_From_Name (Project, "ada");
507 Naming : Lang_Naming_Data;
508 Iter : Source_Iterator;
509 Source : Source_Id;
511 begin
512 if Current_Verbosity = High then
513 Debug_Output ("Checking project file:", Project.Name);
514 end if;
516 if Lang = null then
517 if Current_Verbosity = High then
518 Debug_Output ("Languages does not contain Ada, nothing to do");
519 end if;
521 return;
522 end if;
524 -- Visit all the files and process those that need an SFN pragma
526 Iter := For_Each_Source (In_Tree, Project);
527 while Element (Iter) /= No_Source loop
528 Source := Element (Iter);
530 if not Source.Locally_Removed
531 and then Source.Unit /= null
532 and then
533 (Source.Index >= 1 or else Source.Naming_Exception /= No)
534 then
535 Put (Source);
536 end if;
538 Next (Iter);
539 end loop;
541 Naming := Lang.Config.Naming_Data;
543 -- Is the naming scheme of this project one that we know?
545 Current_Naming := Default_Naming;
546 while Current_Naming <= Naming_Table.Last (Namings)
547 and then Namings.Table (Current_Naming).Dot_Replacement =
548 Naming.Dot_Replacement
549 and then Namings.Table (Current_Naming).Casing =
550 Naming.Casing
551 and then Namings.Table (Current_Naming).Separate_Suffix =
552 Naming.Separate_Suffix
553 loop
554 Current_Naming := Current_Naming + 1;
555 end loop;
557 -- If we don't know it, add it
559 if Current_Naming > Naming_Table.Last (Namings) then
560 Naming_Table.Increment_Last (Namings);
561 Namings.Table (Naming_Table.Last (Namings)) := Naming;
563 -- Put the SFN pragmas for the naming scheme
565 -- Spec
567 Put_Line
568 ("pragma Source_File_Name_Project");
569 Put_Line
570 (" (Spec_File_Name => ""*" &
571 Get_Name_String (Naming.Spec_Suffix) & """,");
572 Put_Line
573 (" Casing => " &
574 Image (Naming.Casing) & ",");
575 Put_Line
576 (" Dot_Replacement => """ &
577 Get_Name_String (Naming.Dot_Replacement) & """);");
579 -- and body
581 Put_Line
582 ("pragma Source_File_Name_Project");
583 Put_Line
584 (" (Body_File_Name => ""*" &
585 Get_Name_String (Naming.Body_Suffix) & """,");
586 Put_Line
587 (" Casing => " &
588 Image (Naming.Casing) & ",");
589 Put_Line
590 (" Dot_Replacement => """ &
591 Get_Name_String (Naming.Dot_Replacement) &
592 """);");
594 -- and maybe separate
596 if Naming.Body_Suffix /= Naming.Separate_Suffix then
597 Put_Line ("pragma Source_File_Name_Project");
598 Put_Line
599 (" (Subunit_File_Name => ""*" &
600 Get_Name_String (Naming.Separate_Suffix) & """,");
601 Put_Line
602 (" Casing => " &
603 Image (Naming.Casing) & ",");
604 Put_Line
605 (" Dot_Replacement => """ &
606 Get_Name_String (Naming.Dot_Replacement) &
607 """);");
608 end if;
609 end if;
610 end Check;
612 ---------
613 -- Put --
614 ---------
616 procedure Put (Source : Source_Id) is
617 begin
618 -- Put the pragma SFN for the unit kind (spec or body)
620 Put ("pragma Source_File_Name_Project (");
621 Put (Namet.Get_Name_String (Source.Unit.Name));
623 if Source.Kind = Spec then
624 Put (", Spec_File_Name => """);
625 else
626 Put (", Body_File_Name => """);
627 end if;
629 Put (Namet.Get_Name_String (Source.File));
630 Put ("""");
632 if Source.Index /= 0 then
633 Put (", Index =>");
634 Put (Source.Index'Img);
635 end if;
637 Put_Line (");");
638 end Put;
640 procedure Put (S : String) is
641 begin
642 Add_To_Buffer (S, Buffer, Buffer_Last);
644 if Current_Verbosity = High then
645 Write_Str (S);
646 end if;
647 end Put;
649 --------------
650 -- Put_Line --
651 --------------
653 procedure Put_Line (S : String) is
654 begin
655 -- Add an ASCII.LF to the string. As this config file is supposed to
656 -- be used only by the compiler, we don't care about the characters
657 -- for the end of line. In fact we could have put a space, but
658 -- it is more convenient to be able to read gnat.adc during
659 -- development, for which the ASCII.LF is fine.
661 Put (S);
662 Put (S => (1 => ASCII.LF));
663 end Put_Line;
665 ---------------------
666 -- Write_Temp_File --
667 ---------------------
669 procedure Write_Temp_File is
670 Status : Boolean := False;
671 Last : Natural;
673 begin
674 Tempdir.Create_Temp_File (File, File_Name);
676 if File /= Invalid_FD then
677 Last := Write (File, Buffer (1)'Address, Buffer_Last);
679 if Last = Buffer_Last then
680 Close (File, Status);
681 end if;
682 end if;
684 if not Status then
685 Prj.Com.Fail ("unable to create temporary file");
686 end if;
687 end Write_Temp_File;
689 procedure Check_Imported_Projects is
690 new For_Every_Project_Imported (Integer, Check);
692 Dummy : Integer := 0;
694 -- Start of processing for Create_Config_Pragmas_File
696 begin
697 if not For_Project.Config_Checked then
698 Naming_Table.Init (Namings);
700 -- Check the naming schemes
702 Check_Imported_Projects
703 (For_Project, In_Tree, Dummy, Imported_First => False);
705 -- If there are no non standard naming scheme, issue the GNAT
706 -- standard naming scheme. This will tell the compiler that
707 -- a project file is used and will forbid any pragma SFN.
709 if Buffer_Last = 0 then
711 Put_Line ("pragma Source_File_Name_Project");
712 Put_Line (" (Spec_File_Name => ""*.ads"",");
713 Put_Line (" Dot_Replacement => ""-"",");
714 Put_Line (" Casing => lowercase);");
716 Put_Line ("pragma Source_File_Name_Project");
717 Put_Line (" (Body_File_Name => ""*.adb"",");
718 Put_Line (" Dot_Replacement => ""-"",");
719 Put_Line (" Casing => lowercase);");
720 end if;
722 -- Close the temporary file
724 Write_Temp_File;
726 if Opt.Verbose_Mode then
727 Write_Str ("Created configuration file """);
728 Write_Str (Get_Name_String (File_Name));
729 Write_Line ("""");
730 end if;
732 For_Project.Config_File_Name := File_Name;
733 For_Project.Config_File_Temp := True;
734 For_Project.Config_Checked := True;
735 end if;
737 Free (Buffer);
738 end Create_Config_Pragmas_File;
740 --------------------
741 -- Create_Mapping --
742 --------------------
744 procedure Create_Mapping (In_Tree : Project_Tree_Ref) is
745 Data : Source_Id;
746 Iter : Source_Iterator;
748 begin
749 Fmap.Reset_Tables;
751 Iter := For_Each_Source (In_Tree);
752 loop
753 Data := Element (Iter);
754 exit when Data = No_Source;
756 if Data.Unit /= No_Unit_Index then
757 if Data.Locally_Removed then
758 Fmap.Add_Forbidden_File_Name (Data.File);
759 else
760 Fmap.Add_To_File_Map
761 (Unit_Name => Unit_Name_Type (Data.Unit.Name),
762 File_Name => Data.File,
763 Path_Name => File_Name_Type (Data.Path.Display_Name));
764 end if;
765 end if;
767 Next (Iter);
768 end loop;
769 end Create_Mapping;
771 -------------------------
772 -- Create_Mapping_File --
773 -------------------------
775 procedure Create_Mapping_File
776 (Project : Project_Id;
777 Language : Name_Id;
778 In_Tree : Project_Tree_Ref;
779 Name : out Path_Name_Type)
781 File : File_Descriptor := Invalid_FD;
782 Buffer : String_Access := new String (1 .. Buffer_Initial);
783 Buffer_Last : Natural := 0;
785 procedure Put_Name_Buffer;
786 -- Put the line contained in the Name_Buffer in the global buffer
788 procedure Process
789 (Project : Project_Id;
790 In_Tree : Project_Tree_Ref;
791 State : in out Integer);
792 -- Generate the mapping file for Project (not recursively)
794 ---------------------
795 -- Put_Name_Buffer --
796 ---------------------
798 procedure Put_Name_Buffer is
799 begin
800 if Current_Verbosity = High then
801 Debug_Output (Name_Buffer (1 .. Name_Len));
802 end if;
804 Name_Len := Name_Len + 1;
805 Name_Buffer (Name_Len) := ASCII.LF;
806 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
807 end Put_Name_Buffer;
809 -------------
810 -- Process --
811 -------------
813 procedure Process
814 (Project : Project_Id;
815 In_Tree : Project_Tree_Ref;
816 State : in out Integer)
818 pragma Unreferenced (State);
820 Source : Source_Id;
821 Suffix : File_Name_Type;
822 Iter : Source_Iterator;
824 begin
825 Debug_Output ("Add mapping for project", Project.Name);
826 Iter := For_Each_Source (In_Tree, Project, Language => Language);
828 loop
829 Source := Prj.Element (Iter);
830 exit when Source = No_Source;
832 if Source.Replaced_By = No_Source
833 and then Source.Path.Name /= No_Path
834 and then (Source.Language.Config.Kind = File_Based
835 or else Source.Unit /= No_Unit_Index)
836 then
837 if Source.Unit /= No_Unit_Index then
839 -- Put the encoded unit name in the name buffer
841 declare
842 Uname : constant String :=
843 Get_Name_String (Source.Unit.Name);
845 begin
846 Name_Len := 0;
847 for J in Uname'Range loop
848 if Uname (J) in Upper_Half_Character then
849 Store_Encoded_Character (Get_Char_Code (Uname (J)));
850 else
851 Add_Char_To_Name_Buffer (Uname (J));
852 end if;
853 end loop;
854 end;
856 if Source.Language.Config.Kind = Unit_Based then
858 -- ??? Mapping_Spec_Suffix could be set in the case of
859 -- gnatmake as well
861 Add_Char_To_Name_Buffer ('%');
863 if Source.Kind = Spec then
864 Add_Char_To_Name_Buffer ('s');
865 else
866 Add_Char_To_Name_Buffer ('b');
867 end if;
869 else
870 case Source.Kind is
871 when Spec =>
872 Suffix :=
873 Source.Language.Config.Mapping_Spec_Suffix;
874 when Impl | Sep =>
875 Suffix :=
876 Source.Language.Config.Mapping_Body_Suffix;
877 end case;
879 if Suffix /= No_File then
880 Add_Str_To_Name_Buffer (Get_Name_String (Suffix));
881 end if;
882 end if;
884 Put_Name_Buffer;
885 end if;
887 Get_Name_String (Source.Display_File);
888 Put_Name_Buffer;
890 if Source.Locally_Removed then
891 Name_Len := 1;
892 Name_Buffer (1) := '/';
893 else
894 Get_Name_String (Source.Path.Display_Name);
895 end if;
897 Put_Name_Buffer;
898 end if;
900 Next (Iter);
901 end loop;
902 end Process;
904 procedure For_Every_Imported_Project is new
905 For_Every_Project_Imported (State => Integer, Action => Process);
907 -- Local variables
909 Dummy : Integer := 0;
911 -- Start of processing for Create_Mapping_File
913 begin
914 if Current_Verbosity = High then
915 Debug_Output ("Create mapping file for", Debug_Name (In_Tree));
916 end if;
918 Create_Temp_File (In_Tree.Shared, File, Name, "mapping");
920 if Current_Verbosity = High then
921 Debug_Increase_Indent ("Create mapping file ", Name_Id (Name));
922 end if;
924 For_Every_Imported_Project
925 (Project, In_Tree, Dummy, Include_Aggregated => False);
927 declare
928 Last : Natural;
929 Status : Boolean := False;
931 begin
932 if File /= Invalid_FD then
933 Last := Write (File, Buffer (1)'Address, Buffer_Last);
935 if Last = Buffer_Last then
936 GNAT.OS_Lib.Close (File, Status);
937 end if;
938 end if;
940 if not Status then
941 Prj.Com.Fail ("could not write mapping file");
942 end if;
943 end;
945 Free (Buffer);
947 Debug_Decrease_Indent ("Done create mapping file");
948 end Create_Mapping_File;
950 ----------------------
951 -- Create_Temp_File --
952 ----------------------
954 procedure Create_Temp_File
955 (Shared : Shared_Project_Tree_Data_Access;
956 Path_FD : out File_Descriptor;
957 Path_Name : out Path_Name_Type;
958 File_Use : String)
960 begin
961 Tempdir.Create_Temp_File (Path_FD, Path_Name);
963 if Path_Name /= No_Path then
964 if Current_Verbosity = High then
965 Write_Line ("Create temp file (" & File_Use & ") "
966 & Get_Name_String (Path_Name));
967 end if;
969 Record_Temp_File (Shared, Path_Name);
971 else
972 Prj.Com.Fail
973 ("unable to create temporary " & File_Use & " file");
974 end if;
975 end Create_Temp_File;
977 --------------------------
978 -- Create_New_Path_File --
979 --------------------------
981 procedure Create_New_Path_File
982 (Shared : Shared_Project_Tree_Data_Access;
983 Path_FD : out File_Descriptor;
984 Path_Name : out Path_Name_Type)
986 begin
987 Create_Temp_File (Shared, Path_FD, Path_Name, "path file");
988 end Create_New_Path_File;
990 ------------------------------------
991 -- File_Name_Of_Library_Unit_Body --
992 ------------------------------------
994 function File_Name_Of_Library_Unit_Body
995 (Name : String;
996 Project : Project_Id;
997 In_Tree : Project_Tree_Ref;
998 Main_Project_Only : Boolean := True;
999 Full_Path : Boolean := False) return String
1002 Lang : constant Language_Ptr :=
1003 Get_Language_From_Name (Project, "ada");
1004 The_Project : Project_Id := Project;
1005 Original_Name : String := Name;
1007 Unit : Unit_Index;
1008 The_Original_Name : Name_Id;
1009 The_Spec_Name : Name_Id;
1010 The_Body_Name : Name_Id;
1012 begin
1013 -- ??? Same block in Project_Of
1014 Canonical_Case_File_Name (Original_Name);
1015 Name_Len := Original_Name'Length;
1016 Name_Buffer (1 .. Name_Len) := Original_Name;
1017 The_Original_Name := Name_Find;
1019 if Lang /= null then
1020 declare
1021 Naming : constant Lang_Naming_Data := Lang.Config.Naming_Data;
1022 Extended_Spec_Name : String :=
1023 Name & Namet.Get_Name_String
1024 (Naming.Spec_Suffix);
1025 Extended_Body_Name : String :=
1026 Name & Namet.Get_Name_String
1027 (Naming.Body_Suffix);
1029 begin
1030 Canonical_Case_File_Name (Extended_Spec_Name);
1031 Name_Len := Extended_Spec_Name'Length;
1032 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1033 The_Spec_Name := Name_Find;
1035 Canonical_Case_File_Name (Extended_Body_Name);
1036 Name_Len := Extended_Body_Name'Length;
1037 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1038 The_Body_Name := Name_Find;
1039 end;
1041 else
1042 Name_Len := Name'Length;
1043 Name_Buffer (1 .. Name_Len) := Name;
1044 Canonical_Case_File_Name (Name_Buffer);
1045 The_Spec_Name := Name_Find;
1046 The_Body_Name := The_Spec_Name;
1047 end if;
1049 if Current_Verbosity = High then
1050 Write_Str ("Looking for file name of """);
1051 Write_Str (Name);
1052 Write_Char ('"');
1053 Write_Eol;
1054 Write_Str (" Extended Spec Name = """);
1055 Write_Str (Get_Name_String (The_Spec_Name));
1056 Write_Char ('"');
1057 Write_Eol;
1058 Write_Str (" Extended Body Name = """);
1059 Write_Str (Get_Name_String (The_Body_Name));
1060 Write_Char ('"');
1061 Write_Eol;
1062 end if;
1064 -- For extending project, search in the extended project if the source
1065 -- is not found. For non extending projects, this loop will be run only
1066 -- once.
1068 loop
1069 -- Loop through units
1071 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1072 while Unit /= null loop
1073 -- Check for body
1075 if not Main_Project_Only
1076 or else
1077 (Unit.File_Names (Impl) /= null
1078 and then Unit.File_Names (Impl).Project = The_Project)
1079 then
1080 declare
1081 Current_Name : File_Name_Type;
1082 begin
1083 -- Case of a body present
1085 if Unit.File_Names (Impl) /= null then
1086 Current_Name := Unit.File_Names (Impl).File;
1088 if Current_Verbosity = High then
1089 Write_Str (" Comparing with """);
1090 Write_Str (Get_Name_String (Current_Name));
1091 Write_Char ('"');
1092 Write_Eol;
1093 end if;
1095 -- If it has the name of the original name, return the
1096 -- original name.
1098 if Unit.Name = The_Original_Name
1099 or else
1100 Current_Name = File_Name_Type (The_Original_Name)
1101 then
1102 if Current_Verbosity = High then
1103 Write_Line (" OK");
1104 end if;
1106 if Full_Path then
1107 return Get_Name_String
1108 (Unit.File_Names (Impl).Path.Name);
1110 else
1111 return Get_Name_String (Current_Name);
1112 end if;
1114 -- If it has the name of the extended body name,
1115 -- return the extended body name
1117 elsif Current_Name = File_Name_Type (The_Body_Name) then
1118 if Current_Verbosity = High then
1119 Write_Line (" OK");
1120 end if;
1122 if Full_Path then
1123 return Get_Name_String
1124 (Unit.File_Names (Impl).Path.Name);
1126 else
1127 return Get_Name_String (The_Body_Name);
1128 end if;
1130 else
1131 if Current_Verbosity = High then
1132 Write_Line (" not good");
1133 end if;
1134 end if;
1135 end if;
1136 end;
1137 end if;
1139 -- Check for spec
1141 if not Main_Project_Only
1142 or else (Unit.File_Names (Spec) /= null
1143 and then Unit.File_Names (Spec).Project = The_Project)
1144 then
1145 declare
1146 Current_Name : File_Name_Type;
1148 begin
1149 -- Case of spec present
1151 if Unit.File_Names (Spec) /= null then
1152 Current_Name := Unit.File_Names (Spec).File;
1153 if Current_Verbosity = High then
1154 Write_Str (" Comparing with """);
1155 Write_Str (Get_Name_String (Current_Name));
1156 Write_Char ('"');
1157 Write_Eol;
1158 end if;
1160 -- If name same as original name, return original name
1162 if Unit.Name = The_Original_Name
1163 or else
1164 Current_Name = File_Name_Type (The_Original_Name)
1165 then
1166 if Current_Verbosity = High then
1167 Write_Line (" OK");
1168 end if;
1170 if Full_Path then
1171 return Get_Name_String
1172 (Unit.File_Names (Spec).Path.Name);
1173 else
1174 return Get_Name_String (Current_Name);
1175 end if;
1177 -- If it has the same name as the extended spec name,
1178 -- return the extended spec name.
1180 elsif Current_Name = File_Name_Type (The_Spec_Name) then
1181 if Current_Verbosity = High then
1182 Write_Line (" OK");
1183 end if;
1185 if Full_Path then
1186 return Get_Name_String
1187 (Unit.File_Names (Spec).Path.Name);
1188 else
1189 return Get_Name_String (The_Spec_Name);
1190 end if;
1192 else
1193 if Current_Verbosity = High then
1194 Write_Line (" not good");
1195 end if;
1196 end if;
1197 end if;
1198 end;
1199 end if;
1201 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1202 end loop;
1204 -- If we are not in an extending project, give up
1206 exit when not Main_Project_Only
1207 or else The_Project.Extends = No_Project;
1209 -- Otherwise, look in the project we are extending
1211 The_Project := The_Project.Extends;
1212 end loop;
1214 -- We don't know this file name, return an empty string
1216 return "";
1217 end File_Name_Of_Library_Unit_Body;
1219 -------------------------
1220 -- For_All_Object_Dirs --
1221 -------------------------
1223 procedure For_All_Object_Dirs
1224 (Project : Project_Id;
1225 Tree : Project_Tree_Ref)
1227 procedure For_Project
1228 (Prj : Project_Id;
1229 Tree : Project_Tree_Ref;
1230 Dummy : in out Integer);
1231 -- Get all object directories of Prj
1233 -----------------
1234 -- For_Project --
1235 -----------------
1237 procedure For_Project
1238 (Prj : Project_Id;
1239 Tree : Project_Tree_Ref;
1240 Dummy : in out Integer)
1242 pragma Unreferenced (Dummy, Tree);
1244 begin
1245 -- ??? Set_Ada_Paths has a different behavior for library project
1246 -- files, should we have the same ?
1248 if Prj.Object_Directory /= No_Path_Information then
1249 Get_Name_String (Prj.Object_Directory.Display_Name);
1250 Action (Name_Buffer (1 .. Name_Len));
1251 end if;
1252 end For_Project;
1254 procedure Get_Object_Dirs is
1255 new For_Every_Project_Imported (Integer, For_Project);
1256 Dummy : Integer := 1;
1258 -- Start of processing for For_All_Object_Dirs
1260 begin
1261 Get_Object_Dirs (Project, Tree, Dummy);
1262 end For_All_Object_Dirs;
1264 -------------------------
1265 -- For_All_Source_Dirs --
1266 -------------------------
1268 procedure For_All_Source_Dirs
1269 (Project : Project_Id;
1270 In_Tree : Project_Tree_Ref)
1272 procedure For_Project
1273 (Prj : Project_Id;
1274 In_Tree : Project_Tree_Ref;
1275 Dummy : in out Integer);
1276 -- Get all object directories of Prj
1278 -----------------
1279 -- For_Project --
1280 -----------------
1282 procedure For_Project
1283 (Prj : Project_Id;
1284 In_Tree : Project_Tree_Ref;
1285 Dummy : in out Integer)
1287 pragma Unreferenced (Dummy);
1289 Current : String_List_Id := Prj.Source_Dirs;
1290 The_String : String_Element;
1292 begin
1293 -- If there are Ada sources, call action with the name of every
1294 -- source directory.
1296 if Has_Ada_Sources (Prj) then
1297 while Current /= Nil_String loop
1298 The_String := In_Tree.Shared.String_Elements.Table (Current);
1299 Action (Get_Name_String (The_String.Display_Value));
1300 Current := The_String.Next;
1301 end loop;
1302 end if;
1303 end For_Project;
1305 procedure Get_Source_Dirs is
1306 new For_Every_Project_Imported (Integer, For_Project);
1307 Dummy : Integer := 1;
1309 -- Start of processing for For_All_Source_Dirs
1311 begin
1312 Get_Source_Dirs (Project, In_Tree, Dummy);
1313 end For_All_Source_Dirs;
1315 -------------------
1316 -- Get_Reference --
1317 -------------------
1319 procedure Get_Reference
1320 (Source_File_Name : String;
1321 In_Tree : Project_Tree_Ref;
1322 Project : out Project_Id;
1323 Path : out Path_Name_Type)
1325 begin
1326 -- Body below could use some comments ???
1328 if Current_Verbosity > Default then
1329 Write_Str ("Getting Reference_Of (""");
1330 Write_Str (Source_File_Name);
1331 Write_Str (""") ... ");
1332 end if;
1334 declare
1335 Original_Name : String := Source_File_Name;
1336 Unit : Unit_Index;
1338 begin
1339 Canonical_Case_File_Name (Original_Name);
1340 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1342 while Unit /= null loop
1343 if Unit.File_Names (Spec) /= null
1344 and then not Unit.File_Names (Spec).Locally_Removed
1345 and then Unit.File_Names (Spec).File /= No_File
1346 and then
1347 (Namet.Get_Name_String
1348 (Unit.File_Names (Spec).File) = Original_Name
1349 or else (Unit.File_Names (Spec).Path /= No_Path_Information
1350 and then
1351 Namet.Get_Name_String
1352 (Unit.File_Names (Spec).Path.Name) =
1353 Original_Name))
1354 then
1355 Project :=
1356 Ultimate_Extending_Project_Of
1357 (Unit.File_Names (Spec).Project);
1358 Path := Unit.File_Names (Spec).Path.Display_Name;
1360 if Current_Verbosity > Default then
1361 Write_Str ("Done: Spec.");
1362 Write_Eol;
1363 end if;
1365 return;
1367 elsif Unit.File_Names (Impl) /= null
1368 and then Unit.File_Names (Impl).File /= No_File
1369 and then not Unit.File_Names (Impl).Locally_Removed
1370 and then
1371 (Namet.Get_Name_String
1372 (Unit.File_Names (Impl).File) = Original_Name
1373 or else (Unit.File_Names (Impl).Path /= No_Path_Information
1374 and then Namet.Get_Name_String
1375 (Unit.File_Names (Impl).Path.Name) =
1376 Original_Name))
1377 then
1378 Project :=
1379 Ultimate_Extending_Project_Of
1380 (Unit.File_Names (Impl).Project);
1381 Path := Unit.File_Names (Impl).Path.Display_Name;
1383 if Current_Verbosity > Default then
1384 Write_Str ("Done: Body.");
1385 Write_Eol;
1386 end if;
1388 return;
1389 end if;
1391 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1392 end loop;
1393 end;
1395 Project := No_Project;
1396 Path := No_Path;
1398 if Current_Verbosity > Default then
1399 Write_Str ("Cannot be found.");
1400 Write_Eol;
1401 end if;
1402 end Get_Reference;
1404 ----------------------
1405 -- Get_Runtime_Path --
1406 ----------------------
1408 function Get_Runtime_Path
1409 (Self : Project_Search_Path;
1410 Name : String) return String_Access
1412 function Is_Base_Name (Path : String) return Boolean;
1413 -- Returns True if Path has no directory separator
1415 ------------------
1416 -- Is_Base_Name --
1417 ------------------
1419 function Is_Base_Name (Path : String) return Boolean is
1420 begin
1421 for J in Path'Range loop
1422 if Path (J) = Directory_Separator or else Path (J) = '/' then
1423 return False;
1424 end if;
1425 end loop;
1427 return True;
1428 end Is_Base_Name;
1430 function Find_Rts_In_Path is new Prj.Env.Find_Name_In_Path
1431 (Check_Filename => Is_Directory);
1433 -- Start of processing for Get_Runtime_Path
1435 begin
1436 if not Is_Base_Name (Name) then
1437 return Find_Rts_In_Path (Self, Name);
1438 else
1439 return null;
1440 end if;
1441 end Get_Runtime_Path;
1443 ----------------
1444 -- Initialize --
1445 ----------------
1447 procedure Initialize (In_Tree : Project_Tree_Ref) is
1448 begin
1449 In_Tree.Shared.Private_Part.Current_Source_Path_File := No_Path;
1450 In_Tree.Shared.Private_Part.Current_Object_Path_File := No_Path;
1451 end Initialize;
1453 -------------------
1454 -- Print_Sources --
1455 -------------------
1457 -- Could use some comments in this body ???
1459 procedure Print_Sources (In_Tree : Project_Tree_Ref) is
1460 Unit : Unit_Index;
1462 begin
1463 Write_Line ("List of Sources:");
1465 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1467 while Unit /= No_Unit_Index loop
1468 Write_Str (" ");
1469 Write_Line (Namet.Get_Name_String (Unit.Name));
1471 if Unit.File_Names (Spec).File /= No_File then
1472 if Unit.File_Names (Spec).Project = No_Project then
1473 Write_Line (" No project");
1475 else
1476 Write_Str (" Project: ");
1477 Get_Name_String
1478 (Unit.File_Names (Spec).Project.Path.Name);
1479 Write_Line (Name_Buffer (1 .. Name_Len));
1480 end if;
1482 Write_Str (" spec: ");
1483 Write_Line
1484 (Namet.Get_Name_String
1485 (Unit.File_Names (Spec).File));
1486 end if;
1488 if Unit.File_Names (Impl).File /= No_File then
1489 if Unit.File_Names (Impl).Project = No_Project then
1490 Write_Line (" No project");
1492 else
1493 Write_Str (" Project: ");
1494 Get_Name_String
1495 (Unit.File_Names (Impl).Project.Path.Name);
1496 Write_Line (Name_Buffer (1 .. Name_Len));
1497 end if;
1499 Write_Str (" body: ");
1500 Write_Line
1501 (Namet.Get_Name_String (Unit.File_Names (Impl).File));
1502 end if;
1504 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1505 end loop;
1507 Write_Line ("end of List of Sources.");
1508 end Print_Sources;
1510 ----------------
1511 -- Project_Of --
1512 ----------------
1514 function Project_Of
1515 (Name : String;
1516 Main_Project : Project_Id;
1517 In_Tree : Project_Tree_Ref) return Project_Id
1519 Result : Project_Id := No_Project;
1521 Original_Name : String := Name;
1523 Lang : constant Language_Ptr :=
1524 Get_Language_From_Name (Main_Project, "ada");
1526 Unit : Unit_Index;
1528 Current_Name : File_Name_Type;
1529 The_Original_Name : File_Name_Type;
1530 The_Spec_Name : File_Name_Type;
1531 The_Body_Name : File_Name_Type;
1533 begin
1534 -- ??? Same block in File_Name_Of_Library_Unit_Body
1535 Canonical_Case_File_Name (Original_Name);
1536 Name_Len := Original_Name'Length;
1537 Name_Buffer (1 .. Name_Len) := Original_Name;
1538 The_Original_Name := Name_Find;
1540 if Lang /= null then
1541 declare
1542 Naming : Lang_Naming_Data renames Lang.Config.Naming_Data;
1543 Extended_Spec_Name : String :=
1544 Name & Namet.Get_Name_String
1545 (Naming.Spec_Suffix);
1546 Extended_Body_Name : String :=
1547 Name & Namet.Get_Name_String
1548 (Naming.Body_Suffix);
1550 begin
1551 Canonical_Case_File_Name (Extended_Spec_Name);
1552 Name_Len := Extended_Spec_Name'Length;
1553 Name_Buffer (1 .. Name_Len) := Extended_Spec_Name;
1554 The_Spec_Name := Name_Find;
1556 Canonical_Case_File_Name (Extended_Body_Name);
1557 Name_Len := Extended_Body_Name'Length;
1558 Name_Buffer (1 .. Name_Len) := Extended_Body_Name;
1559 The_Body_Name := Name_Find;
1560 end;
1562 else
1563 The_Spec_Name := The_Original_Name;
1564 The_Body_Name := The_Original_Name;
1565 end if;
1567 Unit := Units_Htable.Get_First (In_Tree.Units_HT);
1568 while Unit /= null loop
1570 -- Case of a body present
1572 if Unit.File_Names (Impl) /= null then
1573 Current_Name := Unit.File_Names (Impl).File;
1575 -- If it has the name of the original name or the body name,
1576 -- we have found the project.
1578 if Unit.Name = Name_Id (The_Original_Name)
1579 or else Current_Name = The_Original_Name
1580 or else Current_Name = The_Body_Name
1581 then
1582 Result := Unit.File_Names (Impl).Project;
1583 exit;
1584 end if;
1585 end if;
1587 -- Check for spec
1589 if Unit.File_Names (Spec) /= null then
1590 Current_Name := Unit.File_Names (Spec).File;
1592 -- If name same as the original name, or the spec name, we have
1593 -- found the project.
1595 if Unit.Name = Name_Id (The_Original_Name)
1596 or else Current_Name = The_Original_Name
1597 or else Current_Name = The_Spec_Name
1598 then
1599 Result := Unit.File_Names (Spec).Project;
1600 exit;
1601 end if;
1602 end if;
1604 Unit := Units_Htable.Get_Next (In_Tree.Units_HT);
1605 end loop;
1607 return Ultimate_Extending_Project_Of (Result);
1608 end Project_Of;
1610 -------------------
1611 -- Set_Ada_Paths --
1612 -------------------
1614 procedure Set_Ada_Paths
1615 (Project : Project_Id;
1616 In_Tree : Project_Tree_Ref;
1617 Including_Libraries : Boolean;
1618 Include_Path : Boolean := True;
1619 Objects_Path : Boolean := True)
1622 Shared : constant Shared_Project_Tree_Data_Access := In_Tree.Shared;
1624 Source_Paths : Source_Path_Table.Instance;
1625 Object_Paths : Object_Path_Table.Instance;
1626 -- List of source or object dirs. Only computed the first time this
1627 -- procedure is called (since Source_FD is then reused)
1629 Source_FD : File_Descriptor := Invalid_FD;
1630 Object_FD : File_Descriptor := Invalid_FD;
1631 -- The temporary files to store the paths. These are only created the
1632 -- first time this procedure is called, and reused from then on.
1634 Process_Source_Dirs : Boolean := False;
1635 Process_Object_Dirs : Boolean := False;
1637 Status : Boolean;
1638 -- For calls to Close
1640 Last : Natural;
1641 Buffer : String_Access := new String (1 .. Buffer_Initial);
1642 Buffer_Last : Natural := 0;
1644 procedure Recursive_Add
1645 (Project : Project_Id;
1646 In_Tree : Project_Tree_Ref;
1647 Dummy : in out Boolean);
1648 -- Recursive procedure to add the source/object paths of extended/
1649 -- imported projects.
1651 -------------------
1652 -- Recursive_Add --
1653 -------------------
1655 procedure Recursive_Add
1656 (Project : Project_Id;
1657 In_Tree : Project_Tree_Ref;
1658 Dummy : in out Boolean)
1660 pragma Unreferenced (Dummy, In_Tree);
1662 Path : Path_Name_Type;
1664 begin
1665 -- ??? This is almost the equivalent of For_All_Source_Dirs
1667 if Process_Source_Dirs then
1669 -- Add to path all source directories of this project if there are
1670 -- Ada sources.
1672 if Has_Ada_Sources (Project) then
1673 Add_To_Source_Path (Project.Source_Dirs, Shared, Source_Paths);
1674 end if;
1675 end if;
1677 if Process_Object_Dirs then
1678 Path := Get_Object_Directory
1679 (Project,
1680 Including_Libraries => Including_Libraries,
1681 Only_If_Ada => True);
1683 if Path /= No_Path then
1684 Add_To_Object_Path (Path, Object_Paths);
1685 end if;
1686 end if;
1687 end Recursive_Add;
1689 procedure For_All_Projects is
1690 new For_Every_Project_Imported (Boolean, Recursive_Add);
1692 Dummy : Boolean := False;
1694 -- Start of processing for Set_Ada_Paths
1696 begin
1697 -- If it is the first time we call this procedure for this project,
1698 -- compute the source path and/or the object path.
1700 if Include_Path and then Project.Include_Path_File = No_Path then
1701 Source_Path_Table.Init (Source_Paths);
1702 Process_Source_Dirs := True;
1703 Create_New_Path_File (Shared, Source_FD, Project.Include_Path_File);
1704 end if;
1706 -- For the object path, we make a distinction depending on
1707 -- Including_Libraries.
1709 if Objects_Path and Including_Libraries then
1710 if Project.Objects_Path_File_With_Libs = No_Path then
1711 Object_Path_Table.Init (Object_Paths);
1712 Process_Object_Dirs := True;
1713 Create_New_Path_File
1714 (Shared, Object_FD, Project.Objects_Path_File_With_Libs);
1715 end if;
1717 elsif Objects_Path then
1718 if Project.Objects_Path_File_Without_Libs = No_Path then
1719 Object_Path_Table.Init (Object_Paths);
1720 Process_Object_Dirs := True;
1721 Create_New_Path_File
1722 (Shared, Object_FD, Project.Objects_Path_File_Without_Libs);
1723 end if;
1724 end if;
1726 -- If there is something to do, set Seen to False for all projects,
1727 -- then call the recursive procedure Add for Project.
1729 if Process_Source_Dirs or Process_Object_Dirs then
1730 For_All_Projects (Project, In_Tree, Dummy);
1731 end if;
1733 -- Write and close any file that has been created. Source_FD is not set
1734 -- when this subprogram is called a second time or more, since we reuse
1735 -- the previous version of the file.
1737 if Source_FD /= Invalid_FD then
1738 Buffer_Last := 0;
1740 for Index in
1741 Source_Path_Table.First .. Source_Path_Table.Last (Source_Paths)
1742 loop
1743 Get_Name_String (Source_Paths.Table (Index));
1744 Name_Len := Name_Len + 1;
1745 Name_Buffer (Name_Len) := ASCII.LF;
1746 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
1747 end loop;
1749 Last := Write (Source_FD, Buffer (1)'Address, Buffer_Last);
1751 if Last = Buffer_Last then
1752 Close (Source_FD, Status);
1754 else
1755 Status := False;
1756 end if;
1758 if not Status then
1759 Prj.Com.Fail ("could not write temporary file");
1760 end if;
1761 end if;
1763 if Object_FD /= Invalid_FD then
1764 Buffer_Last := 0;
1766 for Index in
1767 Object_Path_Table.First .. Object_Path_Table.Last (Object_Paths)
1768 loop
1769 Get_Name_String (Object_Paths.Table (Index));
1770 Name_Len := Name_Len + 1;
1771 Name_Buffer (Name_Len) := ASCII.LF;
1772 Add_To_Buffer (Name_Buffer (1 .. Name_Len), Buffer, Buffer_Last);
1773 end loop;
1775 Last := Write (Object_FD, Buffer (1)'Address, Buffer_Last);
1777 if Last = Buffer_Last then
1778 Close (Object_FD, Status);
1779 else
1780 Status := False;
1781 end if;
1783 if not Status then
1784 Prj.Com.Fail ("could not write temporary file");
1785 end if;
1786 end if;
1788 -- Set the env vars, if they need to be changed, and set the
1789 -- corresponding flags.
1791 if Include_Path
1792 and then
1793 Shared.Private_Part.Current_Source_Path_File /=
1794 Project.Include_Path_File
1795 then
1796 Shared.Private_Part.Current_Source_Path_File :=
1797 Project.Include_Path_File;
1798 Set_Path_File_Var
1799 (Project_Include_Path_File,
1800 Get_Name_String (Shared.Private_Part.Current_Source_Path_File));
1801 end if;
1803 if Objects_Path then
1804 if Including_Libraries then
1805 if Shared.Private_Part.Current_Object_Path_File /=
1806 Project.Objects_Path_File_With_Libs
1807 then
1808 Shared.Private_Part.Current_Object_Path_File :=
1809 Project.Objects_Path_File_With_Libs;
1810 Set_Path_File_Var
1811 (Project_Objects_Path_File,
1812 Get_Name_String
1813 (Shared.Private_Part.Current_Object_Path_File));
1814 end if;
1816 else
1817 if Shared.Private_Part.Current_Object_Path_File /=
1818 Project.Objects_Path_File_Without_Libs
1819 then
1820 Shared.Private_Part.Current_Object_Path_File :=
1821 Project.Objects_Path_File_Without_Libs;
1822 Set_Path_File_Var
1823 (Project_Objects_Path_File,
1824 Get_Name_String
1825 (Shared.Private_Part.Current_Object_Path_File));
1826 end if;
1827 end if;
1828 end if;
1830 Free (Buffer);
1831 end Set_Ada_Paths;
1833 ---------------------
1834 -- Add_Directories --
1835 ---------------------
1837 procedure Add_Directories
1838 (Self : in out Project_Search_Path;
1839 Path : String)
1841 Tmp : String_Access;
1842 begin
1843 if Self.Path = null then
1844 Self.Path := new String'(Uninitialized_Prefix & Path);
1845 else
1846 Tmp := Self.Path;
1847 Self.Path := new String'(Tmp.all & Path_Separator & Path);
1848 Free (Tmp);
1849 end if;
1851 if Current_Verbosity = High then
1852 Debug_Output ("Adding directories to Project_Path: """
1853 & Path & '"');
1854 end if;
1855 end Add_Directories;
1857 --------------------
1858 -- Is_Initialized --
1859 --------------------
1861 function Is_Initialized (Self : Project_Search_Path) return Boolean is
1862 begin
1863 return Self.Path /= null
1864 and then (Self.Path'Length = 0
1865 or else Self.Path (Self.Path'First) /= '#');
1866 end Is_Initialized;
1868 ----------------------
1869 -- Initialize_Empty --
1870 ----------------------
1872 procedure Initialize_Empty (Self : in out Project_Search_Path) is
1873 begin
1874 Free (Self.Path);
1875 Self.Path := new String'("");
1876 end Initialize_Empty;
1878 -------------------------------------
1879 -- Initialize_Default_Project_Path --
1880 -------------------------------------
1882 procedure Initialize_Default_Project_Path
1883 (Self : in out Project_Search_Path;
1884 Target_Name : String)
1886 Add_Default_Dir : Boolean := True;
1887 First : Positive;
1888 Last : Positive;
1889 New_Len : Positive;
1890 New_Last : Positive;
1892 Ada_Project_Path : constant String := "ADA_PROJECT_PATH";
1893 Gpr_Project_Path : constant String := "GPR_PROJECT_PATH";
1894 -- Name of alternate env. variable that contain path name(s) of
1895 -- directories where project files may reside. GPR_PROJECT_PATH has
1896 -- precedence over ADA_PROJECT_PATH.
1898 Gpr_Prj_Path : String_Access;
1899 Ada_Prj_Path : String_Access;
1900 -- The path name(s) of directories where project files may reside.
1901 -- May be empty.
1903 begin
1904 if Is_Initialized (Self) then
1905 return;
1906 end if;
1908 -- The current directory is always first in the search path. Since the
1909 -- Project_Path currently starts with '#:' as a sign that it isn't
1910 -- initialized, we simply replace '#' with '.'
1912 if Self.Path = null then
1913 Self.Path := new String'('.' & Path_Separator);
1914 else
1915 Self.Path (Self.Path'First) := '.';
1916 end if;
1918 -- Then the reset of the project path (if any) currently contains the
1919 -- directories added through Add_Search_Project_Directory
1921 -- If environment variables are defined and not empty, add their content
1923 Gpr_Prj_Path := Getenv (Gpr_Project_Path);
1924 Ada_Prj_Path := Getenv (Ada_Project_Path);
1926 if Gpr_Prj_Path.all /= "" then
1927 Add_Directories (Self, Gpr_Prj_Path.all);
1928 end if;
1930 Free (Gpr_Prj_Path);
1932 if Ada_Prj_Path.all /= "" then
1933 Add_Directories (Self, Ada_Prj_Path.all);
1934 end if;
1936 Free (Ada_Prj_Path);
1938 -- Copy to Name_Buffer, since we will need to manipulate the path
1940 Name_Len := Self.Path'Length;
1941 Name_Buffer (1 .. Name_Len) := Self.Path.all;
1943 -- Scan the directory path to see if "-" is one of the directories.
1944 -- Remove each occurrence of "-" and set Add_Default_Dir to False.
1945 -- Also resolve relative paths and symbolic links.
1947 First := 3;
1948 loop
1949 while First <= Name_Len
1950 and then (Name_Buffer (First) = Path_Separator)
1951 loop
1952 First := First + 1;
1953 end loop;
1955 exit when First > Name_Len;
1957 Last := First;
1959 while Last < Name_Len
1960 and then Name_Buffer (Last + 1) /= Path_Separator
1961 loop
1962 Last := Last + 1;
1963 end loop;
1965 -- If the directory is "-", set Add_Default_Dir to False and
1966 -- remove from path.
1968 if Name_Buffer (First .. Last) = No_Project_Default_Dir then
1969 Add_Default_Dir := False;
1971 for J in Last + 1 .. Name_Len loop
1972 Name_Buffer (J - No_Project_Default_Dir'Length - 1) :=
1973 Name_Buffer (J);
1974 end loop;
1976 Name_Len := Name_Len - No_Project_Default_Dir'Length - 1;
1978 -- After removing the '-', go back one character to get the next
1979 -- directory correctly.
1981 Last := Last - 1;
1983 elsif not Hostparm.OpenVMS
1984 or else not Is_Absolute_Path (Name_Buffer (First .. Last))
1985 then
1986 -- On VMS, only expand relative path names, as absolute paths
1987 -- may correspond to multi-valued VMS logical names.
1989 declare
1990 New_Dir : constant String :=
1991 Normalize_Pathname
1992 (Name_Buffer (First .. Last),
1993 Resolve_Links => Opt.Follow_Links_For_Dirs);
1995 begin
1996 -- If the absolute path was resolved and is different from
1997 -- the original, replace original with the resolved path.
1999 if New_Dir /= Name_Buffer (First .. Last)
2000 and then New_Dir'Length /= 0
2001 then
2002 New_Len := Name_Len + New_Dir'Length - (Last - First + 1);
2003 New_Last := First + New_Dir'Length - 1;
2004 Name_Buffer (New_Last + 1 .. New_Len) :=
2005 Name_Buffer (Last + 1 .. Name_Len);
2006 Name_Buffer (First .. New_Last) := New_Dir;
2007 Name_Len := New_Len;
2008 Last := New_Last;
2009 end if;
2010 end;
2011 end if;
2013 First := Last + 1;
2014 end loop;
2016 Free (Self.Path);
2018 -- Set the initial value of Current_Project_Path
2020 if Add_Default_Dir then
2021 declare
2022 Prefix : String_Ptr;
2024 begin
2025 if Sdefault.Search_Dir_Prefix = null then
2027 -- gprbuild case
2029 Prefix := new String'(Executable_Prefix_Path);
2031 else
2032 Prefix := new String'(Sdefault.Search_Dir_Prefix.all
2033 & ".." & Dir_Separator
2034 & ".." & Dir_Separator
2035 & ".." & Dir_Separator
2036 & ".." & Dir_Separator);
2037 end if;
2039 if Prefix.all /= "" then
2040 if Target_Name /= "" then
2042 -- $prefix/$target/lib/gnat
2044 Add_Str_To_Name_Buffer
2045 (Path_Separator & Prefix.all &
2046 Target_Name);
2048 -- Note: Target_Name has a trailing / when it comes from
2049 -- Sdefault.
2051 if Name_Buffer (Name_Len) /= '/' then
2052 Add_Char_To_Name_Buffer (Directory_Separator);
2053 end if;
2055 Add_Str_To_Name_Buffer
2056 ("lib" & Directory_Separator & "gnat");
2057 end if;
2059 -- $prefix/share/gpr
2061 Add_Str_To_Name_Buffer
2062 (Path_Separator & Prefix.all &
2063 "share" & Directory_Separator & "gpr");
2065 -- $prefix/lib/gnat
2067 Add_Str_To_Name_Buffer
2068 (Path_Separator & Prefix.all &
2069 "lib" & Directory_Separator & "gnat");
2070 end if;
2072 Free (Prefix);
2073 end;
2074 end if;
2076 Self.Path := new String'(Name_Buffer (1 .. Name_Len));
2077 end Initialize_Default_Project_Path;
2079 --------------
2080 -- Get_Path --
2081 --------------
2083 procedure Get_Path (Self : Project_Search_Path; Path : out String_Access) is
2084 begin
2085 pragma Assert (Is_Initialized (Self));
2086 Path := Self.Path;
2087 end Get_Path;
2089 --------------
2090 -- Set_Path --
2091 --------------
2093 procedure Set_Path (Self : in out Project_Search_Path; Path : String) is
2094 begin
2095 Free (Self.Path);
2096 Self.Path := new String'(Path);
2097 Projects_Paths.Reset (Self.Cache);
2098 end Set_Path;
2100 -----------------------
2101 -- Find_Name_In_Path --
2102 -----------------------
2104 function Find_Name_In_Path
2105 (Self : Project_Search_Path;
2106 Path : String) return String_Access
2108 First : Natural;
2109 Last : Natural;
2111 begin
2112 if Current_Verbosity = High then
2113 Debug_Output ("Trying " & Path);
2114 end if;
2116 if Is_Absolute_Path (Path) then
2117 if Check_Filename (Path) then
2118 return new String'(Path);
2119 else
2120 return null;
2121 end if;
2123 else
2124 -- Because we don't want to resolve symbolic links, we cannot use
2125 -- Locate_Regular_File. So, we try each possible path successively.
2127 First := Self.Path'First;
2128 while First <= Self.Path'Last loop
2129 while First <= Self.Path'Last
2130 and then Self.Path (First) = Path_Separator
2131 loop
2132 First := First + 1;
2133 end loop;
2135 exit when First > Self.Path'Last;
2137 Last := First;
2138 while Last < Self.Path'Last
2139 and then Self.Path (Last + 1) /= Path_Separator
2140 loop
2141 Last := Last + 1;
2142 end loop;
2144 Name_Len := 0;
2146 if not Is_Absolute_Path (Self.Path (First .. Last)) then
2147 Add_Str_To_Name_Buffer (Get_Current_Dir); -- ??? System call
2148 Add_Char_To_Name_Buffer (Directory_Separator);
2149 end if;
2151 Add_Str_To_Name_Buffer (Self.Path (First .. Last));
2152 Add_Char_To_Name_Buffer (Directory_Separator);
2153 Add_Str_To_Name_Buffer (Path);
2155 if Current_Verbosity = High then
2156 Debug_Output ("Testing file " & Name_Buffer (1 .. Name_Len));
2157 end if;
2159 if Check_Filename (Name_Buffer (1 .. Name_Len)) then
2160 return new String'(Name_Buffer (1 .. Name_Len));
2161 end if;
2163 First := Last + 1;
2164 end loop;
2165 end if;
2167 return null;
2168 end Find_Name_In_Path;
2170 ------------------
2171 -- Find_Project --
2172 ------------------
2174 procedure Find_Project
2175 (Self : in out Project_Search_Path;
2176 Project_File_Name : String;
2177 Directory : String;
2178 Path : out Namet.Path_Name_Type)
2180 File : constant String := Project_File_Name;
2181 -- Have to do a copy, in case the parameter is Name_Buffer, which we
2182 -- modify below
2184 function Try_Path_Name is new Find_Name_In_Path
2185 (Check_Filename => Is_Regular_File);
2186 -- Find a file in the project search path.
2188 -- Local Declarations
2190 Result : String_Access;
2191 Has_Dot : Boolean := False;
2192 Key : Name_Id;
2194 -- Start of processing for Find_Project
2196 begin
2197 pragma Assert (Is_Initialized (Self));
2199 if Current_Verbosity = High then
2200 Debug_Increase_Indent
2201 ("Searching for project """ & File & """ in """
2202 & Directory & '"');
2203 end if;
2205 -- Check the project cache
2207 Name_Len := File'Length;
2208 Name_Buffer (1 .. Name_Len) := File;
2209 Key := Name_Find;
2210 Path := Projects_Paths.Get (Self.Cache, Key);
2212 if Path /= No_Path then
2213 Debug_Decrease_Indent;
2214 return;
2215 end if;
2217 -- Check if File contains an extension (a dot before a
2218 -- directory separator). If it is the case we do not try project file
2219 -- with an added extension as it is not possible to have multiple dots
2220 -- on a project file name.
2222 Check_Dot : for K in reverse File'Range loop
2223 if File (K) = '.' then
2224 Has_Dot := True;
2225 exit Check_Dot;
2226 end if;
2228 exit Check_Dot when File (K) = Directory_Separator
2229 or else File (K) = '/';
2230 end loop Check_Dot;
2232 if not Is_Absolute_Path (File) then
2234 -- First we try <directory>/<file_name>.<extension>
2236 if not Has_Dot then
2237 Result := Try_Path_Name
2238 (Self,
2239 Directory & Directory_Separator &
2240 File & Project_File_Extension);
2241 end if;
2243 -- Then we try <directory>/<file_name>
2245 if Result = null then
2246 Result := Try_Path_Name
2247 (Self, Directory & Directory_Separator & File);
2248 end if;
2249 end if;
2251 -- Then we try <file_name>.<extension>
2253 if Result = null and then not Has_Dot then
2254 Result := Try_Path_Name (Self, File & Project_File_Extension);
2255 end if;
2257 -- Then we try <file_name>
2259 if Result = null then
2260 Result := Try_Path_Name (Self, File);
2261 end if;
2263 -- If we cannot find the project file, we return an empty string
2265 if Result = null then
2266 Path := Namet.No_Path;
2267 return;
2269 else
2270 declare
2271 Final_Result : constant String :=
2272 GNAT.OS_Lib.Normalize_Pathname
2273 (Result.all,
2274 Directory => Directory,
2275 Resolve_Links => Opt.Follow_Links_For_Files,
2276 Case_Sensitive => True);
2277 begin
2278 Free (Result);
2279 Name_Len := Final_Result'Length;
2280 Name_Buffer (1 .. Name_Len) := Final_Result;
2281 Path := Name_Find;
2282 Projects_Paths.Set (Self.Cache, Key, Path);
2283 end;
2284 end if;
2286 Debug_Decrease_Indent;
2287 end Find_Project;
2289 ----------
2290 -- Free --
2291 ----------
2293 procedure Free (Self : in out Project_Search_Path) is
2294 begin
2295 Free (Self.Path);
2296 Projects_Paths.Reset (Self.Cache);
2297 end Free;
2299 ----------
2300 -- Copy --
2301 ----------
2303 procedure Copy (From : Project_Search_Path; To : out Project_Search_Path) is
2304 begin
2305 Free (To);
2307 if From.Path /= null then
2308 To.Path := new String'(From.Path.all);
2309 end if;
2311 -- No need to copy the Cache, it will be recomputed as needed
2312 end Copy;
2314 end Prj.Env;