2015-05-22 Eric Botcazou <ebotcazou@adacore.com>
[official-gcc.git] / gcc / ada / prj-conf.adb
blobe48b7fba016800f94f03b220de6df5e27ec0dfde
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- P R J . C O N F --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 2006-2015, 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 Makeutl; use Makeutl;
27 with MLib.Tgt;
28 with Opt; use Opt;
29 with Output; use Output;
30 with Prj.Env;
31 with Prj.Err;
32 with Prj.Part;
33 with Prj.PP;
34 with Prj.Proc; use Prj.Proc;
35 with Prj.Tree; use Prj.Tree;
36 with Prj.Util; use Prj.Util;
37 with Prj; use Prj;
38 with Snames; use Snames;
40 with Ada.Directories; use Ada.Directories;
41 with Ada.Exceptions; use Ada.Exceptions;
43 with GNAT.Case_Util; use GNAT.Case_Util;
44 with GNAT.HTable; use GNAT.HTable;
46 package body Prj.Conf is
48 Auto_Cgpr : constant String := "auto.cgpr";
50 Config_Project_Env_Var : constant String := "GPR_CONFIG";
51 -- Name of the environment variable that provides the name of the
52 -- configuration file to use.
54 Gprconfig_Name : constant String := "gprconfig";
56 Warn_For_RTS : Boolean := True;
57 -- Set to False when gprbuild parse again the project files, to avoid
58 -- an incorrect warning.
60 type Runtime_Root_Data;
61 type Runtime_Root_Ptr is access Runtime_Root_Data;
62 type Runtime_Root_Data is record
63 Root : String_Access;
64 Next : Runtime_Root_Ptr;
65 end record;
66 -- Data for a runtime root to be used when adding directories to the
67 -- project path.
69 type Compiler_Root_Data;
70 type Compiler_Root_Ptr is access Compiler_Root_Data;
71 type Compiler_Root_Data is record
72 Root : String_Access;
73 Runtimes : Runtime_Root_Ptr;
74 Next : Compiler_Root_Ptr;
75 end record;
76 -- Data for a compiler root to be used when adding directories to the
77 -- project path.
79 First_Compiler_Root : Compiler_Root_Ptr := null;
80 -- Head of the list of compiler roots
82 package RTS_Languages is new GNAT.HTable.Simple_HTable
83 (Header_Num => Prj.Header_Num,
84 Element => Name_Id,
85 No_Element => No_Name,
86 Key => Name_Id,
87 Hash => Prj.Hash,
88 Equal => "=");
89 -- Stores the runtime names for the various languages. This is in general
90 -- set from a --RTS command line option.
92 -----------------------
93 -- Local_Subprograms --
94 -----------------------
96 function Check_Target
97 (Config_File : Prj.Project_Id;
98 Autoconf_Specified : Boolean;
99 Project_Tree : Prj.Project_Tree_Ref;
100 Target : String := "") return Boolean;
101 -- Check that the config file's target matches Target.
102 -- Target should be set to the empty string when the user did not specify
103 -- a target. If the target in the configuration file is invalid, this
104 -- function will raise Invalid_Config with an appropriate message.
105 -- Autoconf_Specified should be set to True if the user has used
106 -- autoconf.
108 function Locate_Config_File (Name : String) return String_Access;
109 -- Search for Name in the config files directory. Return full path if
110 -- found, or null otherwise.
112 procedure Raise_Invalid_Config (Msg : String);
113 pragma No_Return (Raise_Invalid_Config);
114 -- Raises exception Invalid_Config with given message
116 procedure Apply_Config_File
117 (Config_File : Prj.Project_Id;
118 Project_Tree : Prj.Project_Tree_Ref);
119 -- Apply the configuration file settings to all the projects in the
120 -- project tree. The Project_Tree must have been parsed first, and
121 -- processed through the first phase so that all its projects are known.
123 -- Currently, this will add new attributes and packages in the various
124 -- projects, so that when the second phase of the processing is performed
125 -- these attributes are automatically taken into account.
127 type State is (No_State);
129 procedure Look_For_Project_Paths
130 (Project : Project_Id;
131 Tree : Project_Tree_Ref;
132 With_State : in out State);
133 -- Check the compilers in the Project and add record them in the list
134 -- rooted at First_Compiler_Root, with their runtimes, if they are not
135 -- already in the list.
137 procedure Update_Project_Path is new
138 For_Every_Project_Imported
139 (State => State,
140 Action => Look_For_Project_Paths);
142 ------------------------------------
143 -- Add_Default_GNAT_Naming_Scheme --
144 ------------------------------------
146 procedure Add_Default_GNAT_Naming_Scheme
147 (Config_File : in out Project_Node_Id;
148 Project_Tree : Project_Node_Tree_Ref)
150 procedure Create_Attribute
151 (Name : Name_Id;
152 Value : String;
153 Index : String := "";
154 Pkg : Project_Node_Id := Empty_Node);
156 ----------------------
157 -- Create_Attribute --
158 ----------------------
160 procedure Create_Attribute
161 (Name : Name_Id;
162 Value : String;
163 Index : String := "";
164 Pkg : Project_Node_Id := Empty_Node)
166 Attr : Project_Node_Id;
167 pragma Unreferenced (Attr);
169 Expr : Name_Id := No_Name;
170 Val : Name_Id := No_Name;
171 Parent : Project_Node_Id := Config_File;
173 begin
174 if Index /= "" then
175 Name_Len := Index'Length;
176 Name_Buffer (1 .. Name_Len) := Index;
177 Val := Name_Find;
178 end if;
180 if Pkg /= Empty_Node then
181 Parent := Pkg;
182 end if;
184 Name_Len := Value'Length;
185 Name_Buffer (1 .. Name_Len) := Value;
186 Expr := Name_Find;
188 Attr := Create_Attribute
189 (Tree => Project_Tree,
190 Prj_Or_Pkg => Parent,
191 Name => Name,
192 Index_Name => Val,
193 Kind => Prj.Single,
194 Value => Create_Literal_String (Expr, Project_Tree));
195 end Create_Attribute;
197 -- Local variables
199 Name : Name_Id;
200 Naming : Project_Node_Id;
201 Compiler : Project_Node_Id;
203 -- Start of processing for Add_Default_GNAT_Naming_Scheme
205 begin
206 if Config_File = Empty_Node then
208 -- Create a dummy config file if none was found
210 Name_Len := Auto_Cgpr'Length;
211 Name_Buffer (1 .. Name_Len) := Auto_Cgpr;
212 Name := Name_Find;
214 -- An invalid project name to avoid conflicts with user-created ones
216 Name_Len := 5;
217 Name_Buffer (1 .. Name_Len) := "_auto";
219 Config_File :=
220 Create_Project
221 (In_Tree => Project_Tree,
222 Name => Name_Find,
223 Full_Path => Path_Name_Type (Name),
224 Is_Config_File => True);
226 -- Setup library support
228 case MLib.Tgt.Support_For_Libraries is
229 when None =>
230 null;
232 when Static_Only =>
233 Create_Attribute (Name_Library_Support, "static_only");
235 when Full =>
236 Create_Attribute (Name_Library_Support, "full");
237 end case;
239 if MLib.Tgt.Standalone_Library_Auto_Init_Is_Supported then
240 Create_Attribute (Name_Library_Auto_Init_Supported, "true");
241 else
242 Create_Attribute (Name_Library_Auto_Init_Supported, "false");
243 end if;
245 -- Declare an empty target
247 Create_Attribute (Name_Target, "");
249 -- Setup Ada support (Ada is the default language here, since this
250 -- is only called when no config file existed initially, ie for
251 -- gnatmake).
253 Create_Attribute (Name_Default_Language, "ada");
255 Compiler := Create_Package (Project_Tree, Config_File, "compiler");
256 Create_Attribute
257 (Name_Driver, "gcc", "ada", Pkg => Compiler);
258 Create_Attribute
259 (Name_Language_Kind, "unit_based", "ada", Pkg => Compiler);
260 Create_Attribute
261 (Name_Dependency_Kind, "ALI_File", "ada", Pkg => Compiler);
263 Naming := Create_Package (Project_Tree, Config_File, "naming");
264 Create_Attribute (Name_Spec_Suffix, ".ads", "ada", Pkg => Naming);
265 Create_Attribute (Name_Separate_Suffix, ".adb", "ada", Pkg => Naming);
266 Create_Attribute (Name_Body_Suffix, ".adb", "ada", Pkg => Naming);
267 Create_Attribute (Name_Dot_Replacement, "-", Pkg => Naming);
268 Create_Attribute (Name_Casing, "lowercase", Pkg => Naming);
270 if Current_Verbosity = High then
271 Write_Line ("Automatically generated (in-memory) config file");
272 Prj.PP.Pretty_Print
273 (Project => Config_File,
274 In_Tree => Project_Tree,
275 Backward_Compatibility => False);
276 end if;
277 end if;
278 end Add_Default_GNAT_Naming_Scheme;
280 -----------------------
281 -- Apply_Config_File --
282 -----------------------
284 procedure Apply_Config_File
285 (Config_File : Prj.Project_Id;
286 Project_Tree : Prj.Project_Tree_Ref)
288 procedure Add_Attributes
289 (Project_Tree : Project_Tree_Ref;
290 Conf_Decl : Declarations;
291 User_Decl : in out Declarations);
292 -- Process the attributes in the config declarations. For
293 -- single string values, if the attribute is not declared in
294 -- the user declarations, declare it with the value in the
295 -- config declarations. For string list values, prepend the
296 -- value in the user declarations with the value in the config
297 -- declarations.
299 --------------------
300 -- Add_Attributes --
301 --------------------
303 procedure Add_Attributes
304 (Project_Tree : Project_Tree_Ref;
305 Conf_Decl : Declarations;
306 User_Decl : in out Declarations)
308 Shared : constant Shared_Project_Tree_Data_Access :=
309 Project_Tree.Shared;
310 Conf_Attr_Id : Variable_Id;
311 Conf_Attr : Variable;
312 Conf_Array_Id : Array_Id;
313 Conf_Array : Array_Data;
314 Conf_Array_Elem_Id : Array_Element_Id;
315 Conf_Array_Elem : Array_Element;
316 Conf_List : String_List_Id;
317 Conf_List_Elem : String_Element;
319 User_Attr_Id : Variable_Id;
320 User_Attr : Variable;
321 User_Array_Id : Array_Id;
322 User_Array : Array_Data;
323 User_Array_Elem_Id : Array_Element_Id;
324 User_Array_Elem : Array_Element;
326 begin
327 Conf_Attr_Id := Conf_Decl.Attributes;
328 User_Attr_Id := User_Decl.Attributes;
330 while Conf_Attr_Id /= No_Variable loop
331 Conf_Attr := Shared.Variable_Elements.Table (Conf_Attr_Id);
332 User_Attr := Shared.Variable_Elements.Table (User_Attr_Id);
334 if not Conf_Attr.Value.Default then
335 if User_Attr.Value.Default then
337 -- No attribute declared in user project file: just copy
338 -- the value of the configuration attribute.
340 User_Attr.Value := Conf_Attr.Value;
341 Shared.Variable_Elements.Table (User_Attr_Id) := User_Attr;
343 elsif User_Attr.Value.Kind = List
344 and then Conf_Attr.Value.Values /= Nil_String
345 then
346 -- List attribute declared in both the user project and the
347 -- configuration project: prepend the user list with the
348 -- configuration list.
350 declare
351 User_List : constant String_List_Id :=
352 User_Attr.Value.Values;
353 Conf_List : String_List_Id := Conf_Attr.Value.Values;
354 Conf_Elem : String_Element;
355 New_List : String_List_Id;
356 New_Elem : String_Element;
358 begin
359 -- Create new list
361 String_Element_Table.Increment_Last
362 (Shared.String_Elements);
363 New_List :=
364 String_Element_Table.Last (Shared.String_Elements);
366 -- Value of attribute is new list
368 User_Attr.Value.Values := New_List;
369 Shared.Variable_Elements.Table (User_Attr_Id) :=
370 User_Attr;
372 loop
373 -- Get each element of configuration list
375 Conf_Elem := Shared.String_Elements.Table (Conf_List);
376 New_Elem := Conf_Elem;
377 Conf_List := Conf_Elem.Next;
379 if Conf_List = Nil_String then
381 -- If it is the last element in the list, connect
382 -- to first element of user list, and we are done.
384 New_Elem.Next := User_List;
385 Shared.String_Elements.Table (New_List) := New_Elem;
386 exit;
388 else
389 -- If it is not the last element in the list, add
390 -- to new list.
392 String_Element_Table.Increment_Last
393 (Shared.String_Elements);
394 New_Elem.Next := String_Element_Table.Last
395 (Shared.String_Elements);
396 Shared.String_Elements.Table (New_List) := New_Elem;
397 New_List := New_Elem.Next;
398 end if;
399 end loop;
400 end;
401 end if;
402 end if;
404 Conf_Attr_Id := Conf_Attr.Next;
405 User_Attr_Id := User_Attr.Next;
406 end loop;
408 Conf_Array_Id := Conf_Decl.Arrays;
409 while Conf_Array_Id /= No_Array loop
410 Conf_Array := Shared.Arrays.Table (Conf_Array_Id);
412 User_Array_Id := User_Decl.Arrays;
413 while User_Array_Id /= No_Array loop
414 User_Array := Shared.Arrays.Table (User_Array_Id);
415 exit when User_Array.Name = Conf_Array.Name;
416 User_Array_Id := User_Array.Next;
417 end loop;
419 -- If this associative array does not exist in the user project
420 -- file, do a shallow copy of the full associative array.
422 if User_Array_Id = No_Array then
423 Array_Table.Increment_Last (Shared.Arrays);
424 User_Array := Conf_Array;
425 User_Array.Next := User_Decl.Arrays;
426 User_Decl.Arrays := Array_Table.Last (Shared.Arrays);
427 Shared.Arrays.Table (User_Decl.Arrays) := User_Array;
429 -- Otherwise, check each array element
431 else
432 Conf_Array_Elem_Id := Conf_Array.Value;
433 while Conf_Array_Elem_Id /= No_Array_Element loop
434 Conf_Array_Elem :=
435 Shared.Array_Elements.Table (Conf_Array_Elem_Id);
437 User_Array_Elem_Id := User_Array.Value;
438 while User_Array_Elem_Id /= No_Array_Element loop
439 User_Array_Elem :=
440 Shared.Array_Elements.Table (User_Array_Elem_Id);
441 exit when User_Array_Elem.Index = Conf_Array_Elem.Index;
442 User_Array_Elem_Id := User_Array_Elem.Next;
443 end loop;
445 -- If the array element doesn't exist in the user array,
446 -- insert a shallow copy of the conf array element in the
447 -- user array.
449 if User_Array_Elem_Id = No_Array_Element then
450 Array_Element_Table.Increment_Last
451 (Shared.Array_Elements);
452 User_Array_Elem := Conf_Array_Elem;
453 User_Array_Elem.Next := User_Array.Value;
454 User_Array.Value :=
455 Array_Element_Table.Last (Shared.Array_Elements);
456 Shared.Array_Elements.Table (User_Array.Value) :=
457 User_Array_Elem;
458 Shared.Arrays.Table (User_Array_Id) := User_Array;
460 -- Otherwise, if the value is a string list, prepend the
461 -- conf array element value to the array element.
463 elsif Conf_Array_Elem.Value.Kind = List then
464 Conf_List := Conf_Array_Elem.Value.Values;
466 if Conf_List /= Nil_String then
467 declare
468 Link : constant String_List_Id :=
469 User_Array_Elem.Value.Values;
470 Previous : String_List_Id := Nil_String;
471 Next : String_List_Id;
473 begin
474 loop
475 Conf_List_Elem :=
476 Shared.String_Elements.Table (Conf_List);
477 String_Element_Table.Increment_Last
478 (Shared.String_Elements);
479 Next :=
480 String_Element_Table.Last
481 (Shared.String_Elements);
482 Shared.String_Elements.Table (Next) :=
483 Conf_List_Elem;
485 if Previous = Nil_String then
486 User_Array_Elem.Value.Values := Next;
487 Shared.Array_Elements.Table
488 (User_Array_Elem_Id) := User_Array_Elem;
490 else
491 Shared.String_Elements.Table
492 (Previous).Next := Next;
493 end if;
495 Previous := Next;
497 Conf_List := Conf_List_Elem.Next;
499 if Conf_List = Nil_String then
500 Shared.String_Elements.Table
501 (Previous).Next := Link;
502 exit;
503 end if;
504 end loop;
505 end;
506 end if;
507 end if;
509 Conf_Array_Elem_Id := Conf_Array_Elem.Next;
510 end loop;
511 end if;
513 Conf_Array_Id := Conf_Array.Next;
514 end loop;
515 end Add_Attributes;
517 Shared : constant Shared_Project_Tree_Data_Access := Project_Tree.Shared;
519 Conf_Decl : constant Declarations := Config_File.Decl;
520 Conf_Pack_Id : Package_Id;
521 Conf_Pack : Package_Element;
523 User_Decl : Declarations;
524 User_Pack_Id : Package_Id;
525 User_Pack : Package_Element;
526 Proj : Project_List;
528 begin
529 Debug_Output ("Applying config file to a project tree");
531 Proj := Project_Tree.Projects;
532 while Proj /= null loop
533 if Proj.Project /= Config_File then
534 User_Decl := Proj.Project.Decl;
535 Add_Attributes
536 (Project_Tree => Project_Tree,
537 Conf_Decl => Conf_Decl,
538 User_Decl => User_Decl);
540 Conf_Pack_Id := Conf_Decl.Packages;
541 while Conf_Pack_Id /= No_Package loop
542 Conf_Pack := Shared.Packages.Table (Conf_Pack_Id);
544 User_Pack_Id := User_Decl.Packages;
545 while User_Pack_Id /= No_Package loop
546 User_Pack := Shared.Packages.Table (User_Pack_Id);
547 exit when User_Pack.Name = Conf_Pack.Name;
548 User_Pack_Id := User_Pack.Next;
549 end loop;
551 if User_Pack_Id = No_Package then
552 Package_Table.Increment_Last (Shared.Packages);
553 User_Pack := Conf_Pack;
554 User_Pack.Next := User_Decl.Packages;
555 User_Decl.Packages := Package_Table.Last (Shared.Packages);
556 Shared.Packages.Table (User_Decl.Packages) := User_Pack;
558 else
559 Add_Attributes
560 (Project_Tree => Project_Tree,
561 Conf_Decl => Conf_Pack.Decl,
562 User_Decl => Shared.Packages.Table
563 (User_Pack_Id).Decl);
564 end if;
566 Conf_Pack_Id := Conf_Pack.Next;
567 end loop;
569 Proj.Project.Decl := User_Decl;
571 -- For aggregate projects, we need to apply the config to all
572 -- their aggregated trees as well.
574 if Proj.Project.Qualifier in Aggregate_Project then
575 declare
576 List : Aggregated_Project_List;
577 begin
578 List := Proj.Project.Aggregated_Projects;
579 while List /= null loop
580 Debug_Output
581 ("Recursively apply config to aggregated tree",
582 List.Project.Name);
583 Apply_Config_File
584 (Config_File, Project_Tree => List.Tree);
585 List := List.Next;
586 end loop;
587 end;
588 end if;
589 end if;
591 Proj := Proj.Next;
592 end loop;
593 end Apply_Config_File;
595 ------------------
596 -- Check_Target --
597 ------------------
599 function Check_Target
600 (Config_File : Project_Id;
601 Autoconf_Specified : Boolean;
602 Project_Tree : Prj.Project_Tree_Ref;
603 Target : String := "") return Boolean
605 Shared : constant Shared_Project_Tree_Data_Access :=
606 Project_Tree.Shared;
607 Variable : constant Variable_Value :=
608 Value_Of
609 (Name_Target, Config_File.Decl.Attributes, Shared);
610 Tgt_Name : Name_Id := No_Name;
611 OK : Boolean;
613 begin
614 if Variable /= Nil_Variable_Value and then not Variable.Default then
615 Tgt_Name := Variable.Value;
616 end if;
618 OK :=
619 Target = ""
620 or else
621 (Tgt_Name /= No_Name
622 and then (Length_Of_Name (Tgt_Name) = 0
623 or else Target = Get_Name_String (Tgt_Name)));
625 if not OK then
626 if Autoconf_Specified then
627 if Verbose_Mode then
628 Write_Line ("inconsistent targets, performing autoconf");
629 end if;
631 return False;
633 else
634 if Tgt_Name /= No_Name then
635 Raise_Invalid_Config
636 ("mismatched targets: """
637 & Get_Name_String (Tgt_Name) & """ in configuration, """
638 & Target & """ specified");
639 else
640 Raise_Invalid_Config
641 ("no target specified in configuration file");
642 end if;
643 end if;
644 end if;
646 return True;
647 end Check_Target;
649 --------------------------------------
650 -- Get_Or_Create_Configuration_File --
651 --------------------------------------
653 procedure Get_Or_Create_Configuration_File
654 (Project : Project_Id;
655 Conf_Project : Project_Id;
656 Project_Tree : Project_Tree_Ref;
657 Project_Node_Tree : Prj.Tree.Project_Node_Tree_Ref;
658 Env : in out Prj.Tree.Environment;
659 Allow_Automatic_Generation : Boolean;
660 Config_File_Name : String := "";
661 Autoconf_Specified : Boolean;
662 Target_Name : String := "";
663 Normalized_Hostname : String;
664 Packages_To_Check : String_List_Access := null;
665 Config : out Prj.Project_Id;
666 Config_File_Path : out String_Access;
667 Automatically_Generated : out Boolean;
668 On_Load_Config : Config_File_Hook := null)
670 Shared : constant Shared_Project_Tree_Data_Access := Project_Tree.Shared;
672 At_Least_One_Compiler_Command : Boolean := False;
673 -- Set to True if at least one attribute Ide'Compiler_Command is
674 -- specified for one language of the system.
676 Conf_File_Name : String_Access := new String'(Config_File_Name);
677 -- The configuration project file name. May be modified if there are
678 -- switches --config= in the Builder package of the main project.
680 Selected_Target : String_Access := new String'(Target_Name);
682 function Default_File_Name return String;
683 -- Return the name of the default config file that should be tested
685 procedure Do_Autoconf;
686 -- Generate a new config file through gprconfig. In case of error, this
687 -- raises the Invalid_Config exception with an appropriate message
689 procedure Check_Builder_Switches;
690 -- Check for switches --config and --RTS in package Builder
692 procedure Get_Project_Target;
693 -- If Target_Name is empty, get the specified target in the project
694 -- file, if any.
696 procedure Get_Project_Runtimes;
697 -- Get the various Runtime (<lang>) in the project file or any project
698 -- it extends, if any are specified.
700 function Get_Config_Switches return Argument_List_Access;
701 -- Return the --config switches to use for gprconfig
703 function Get_Db_Switches return Argument_List_Access;
704 -- Return the --db switches to use for gprconfig
706 function Might_Have_Sources (Project : Project_Id) return Boolean;
707 -- True if the specified project might have sources (ie the user has not
708 -- explicitly specified it. We haven't checked the file system, nor do
709 -- we need to at this stage.
711 ----------------------------
712 -- Check_Builder_Switches --
713 ----------------------------
715 procedure Check_Builder_Switches is
716 Get_RTS_Switches : constant Boolean :=
717 RTS_Languages.Get_First = No_Name;
718 -- If no switch --RTS have been specified on the command line, look
719 -- for --RTS switches in the Builder switches.
721 Builder : constant Package_Id :=
722 Value_Of (Name_Builder, Project.Decl.Packages, Shared);
724 Switch_Array_Id : Array_Element_Id;
725 -- The Switches to be checked
727 procedure Check_Switches;
728 -- Check the switches in Switch_Array_Id
730 --------------------
731 -- Check_Switches --
732 --------------------
734 procedure Check_Switches is
735 Switch_Array : Array_Element;
736 Switch_List : String_List_Id := Nil_String;
737 Switch : String_Element;
738 Lang : Name_Id;
739 Lang_Last : Positive;
741 begin
742 while Switch_Array_Id /= No_Array_Element loop
743 Switch_Array :=
744 Shared.Array_Elements.Table (Switch_Array_Id);
746 Switch_List := Switch_Array.Value.Values;
747 List_Loop : while Switch_List /= Nil_String loop
748 Switch := Shared.String_Elements.Table (Switch_List);
750 if Switch.Value /= No_Name then
751 Get_Name_String (Switch.Value);
753 if Conf_File_Name'Length = 0
754 and then Name_Len > 9
755 and then Name_Buffer (1 .. 9) = "--config="
756 then
757 Conf_File_Name :=
758 new String'(Name_Buffer (10 .. Name_Len));
760 elsif Get_RTS_Switches
761 and then Name_Len >= 7
762 and then Name_Buffer (1 .. 5) = "--RTS"
763 then
764 if Name_Buffer (6) = '=' then
765 if not Runtime_Name_Set_For (Name_Ada) then
766 Set_Runtime_For
767 (Name_Ada,
768 Name_Buffer (7 .. Name_Len));
769 end if;
771 elsif Name_Len > 7
772 and then Name_Buffer (6) = ':'
773 and then Name_Buffer (7) /= '='
774 then
775 Lang_Last := 7;
776 while Lang_Last < Name_Len
777 and then Name_Buffer (Lang_Last + 1) /= '='
778 loop
779 Lang_Last := Lang_Last + 1;
780 end loop;
782 if Name_Buffer (Lang_Last + 1) = '=' then
783 declare
784 RTS : constant String :=
785 Name_Buffer (Lang_Last + 2 .. Name_Len);
786 begin
787 Name_Buffer (1 .. Lang_Last - 6) :=
788 Name_Buffer (7 .. Lang_Last);
789 Name_Len := Lang_Last - 6;
790 To_Lower (Name_Buffer (1 .. Name_Len));
791 Lang := Name_Find;
793 if not Runtime_Name_Set_For (Lang) then
794 Set_Runtime_For (Lang, RTS);
795 end if;
796 end;
797 end if;
798 end if;
799 end if;
800 end if;
802 Switch_List := Switch.Next;
803 end loop List_Loop;
805 Switch_Array_Id := Switch_Array.Next;
806 end loop;
807 end Check_Switches;
809 -- Start of processing for Check_Builder_Switches
811 begin
812 if Builder /= No_Package then
813 Switch_Array_Id :=
814 Value_Of
815 (Name => Name_Switches,
816 In_Arrays => Shared.Packages.Table (Builder).Decl.Arrays,
817 Shared => Shared);
818 Check_Switches;
820 Switch_Array_Id :=
821 Value_Of
822 (Name => Name_Default_Switches,
823 In_Arrays => Shared.Packages.Table (Builder).Decl.Arrays,
824 Shared => Shared);
825 Check_Switches;
826 end if;
827 end Check_Builder_Switches;
829 ------------------------
830 -- Get_Project_Target --
831 ------------------------
833 procedure Get_Project_Target is
834 begin
835 if Selected_Target'Length = 0 then
837 -- Check if attribute Target is specified in the main
838 -- project, or in a project it extends. If it is, use this
839 -- target to invoke gprconfig.
841 declare
842 Variable : Variable_Value;
843 Proj : Project_Id;
844 Tgt_Name : Name_Id := No_Name;
846 begin
847 Proj := Project;
848 Project_Loop :
849 while Proj /= No_Project loop
850 Variable :=
851 Value_Of (Name_Target, Proj.Decl.Attributes, Shared);
853 if Variable /= Nil_Variable_Value
854 and then not Variable.Default
855 and then Variable.Value /= No_Name
856 then
857 Tgt_Name := Variable.Value;
858 exit Project_Loop;
859 end if;
861 Proj := Proj.Extends;
862 end loop Project_Loop;
864 if Tgt_Name /= No_Name then
865 Selected_Target := new String'(Get_Name_String (Tgt_Name));
866 end if;
867 end;
868 end if;
869 end Get_Project_Target;
871 --------------------------
872 -- Get_Project_Runtimes --
873 --------------------------
875 procedure Get_Project_Runtimes is
876 Element : Array_Element;
877 Id : Array_Element_Id;
878 Lang : Name_Id;
879 Proj : Project_Id;
881 begin
882 Proj := Project;
883 while Proj /= No_Project loop
884 Id := Value_Of (Name_Runtime, Proj.Decl.Arrays, Shared);
885 while Id /= No_Array_Element loop
886 Element := Shared.Array_Elements.Table (Id);
887 Lang := Element.Index;
889 if not Runtime_Name_Set_For (Lang) then
890 Set_Runtime_For
891 (Lang, RTS_Name => Get_Name_String (Element.Value.Value));
892 end if;
894 Id := Element.Next;
895 end loop;
897 Proj := Proj.Extends;
898 end loop;
899 end Get_Project_Runtimes;
901 -----------------------
902 -- Default_File_Name --
903 -----------------------
905 function Default_File_Name return String is
906 Ada_RTS : constant String := Runtime_Name_For (Name_Ada);
907 Tmp : String_Access;
909 begin
910 if Selected_Target'Length /= 0 then
911 if Ada_RTS /= "" then
912 return
913 Selected_Target.all & '-' &
914 Ada_RTS & Config_Project_File_Extension;
915 else
916 return
917 Selected_Target.all & Config_Project_File_Extension;
918 end if;
920 elsif Ada_RTS /= "" then
921 return Ada_RTS & Config_Project_File_Extension;
923 else
924 Tmp := Getenv (Config_Project_Env_Var);
926 declare
927 T : constant String := Tmp.all;
929 begin
930 Free (Tmp);
932 if T'Length = 0 then
933 return Default_Config_Name;
934 else
935 return T;
936 end if;
937 end;
938 end if;
939 end Default_File_Name;
941 -----------------
942 -- Do_Autoconf --
943 -----------------
945 procedure Do_Autoconf is
946 Obj_Dir : constant Variable_Value :=
947 Value_Of
948 (Name_Object_Dir,
949 Conf_Project.Decl.Attributes,
950 Shared);
952 Gprconfig_Path : String_Access;
953 Success : Boolean;
955 begin
956 Gprconfig_Path := Locate_Exec_On_Path (Gprconfig_Name);
958 if Gprconfig_Path = null then
959 Raise_Invalid_Config
960 ("could not locate gprconfig for auto-configuration");
961 end if;
963 -- First, find the object directory of the Conf_Project
965 -- If the object directory is a relative one and Build_Tree_Dir is
966 -- set, first add it.
968 Name_Len := 0;
970 if Obj_Dir = Nil_Variable_Value or else Obj_Dir.Default then
972 if Build_Tree_Dir /= null then
973 Add_Str_To_Name_Buffer (Build_Tree_Dir.all);
975 if Get_Name_String (Conf_Project.Directory.Display_Name)'Length
976 < Root_Dir'Length
977 then
978 Raise_Invalid_Config
979 ("cannot relocate deeper than object directory");
980 end if;
982 Add_Str_To_Name_Buffer
983 (Relative_Path
984 (Get_Name_String (Conf_Project.Directory.Display_Name),
985 Root_Dir.all));
986 else
987 Get_Name_String (Conf_Project.Directory.Display_Name);
988 end if;
990 else
991 if Is_Absolute_Path (Get_Name_String (Obj_Dir.Value)) then
992 Get_Name_String (Obj_Dir.Value);
994 else
995 if Build_Tree_Dir /= null then
996 if Get_Name_String
997 (Conf_Project.Directory.Display_Name)'Length <
998 Root_Dir'Length
999 then
1000 Raise_Invalid_Config
1001 ("cannot relocate deeper than object directory");
1002 end if;
1004 Add_Str_To_Name_Buffer (Build_Tree_Dir.all);
1005 Add_Str_To_Name_Buffer
1006 (Relative_Path
1007 (Get_Name_String (Conf_Project.Directory.Display_Name),
1008 Root_Dir.all));
1009 else
1010 Add_Str_To_Name_Buffer
1011 (Get_Name_String (Conf_Project.Directory.Display_Name));
1012 end if;
1014 Add_Str_To_Name_Buffer (Get_Name_String (Obj_Dir.Value));
1015 end if;
1016 end if;
1018 if Subdirs /= null then
1019 Add_Char_To_Name_Buffer (Directory_Separator);
1020 Add_Str_To_Name_Buffer (Subdirs.all);
1021 end if;
1023 for J in 1 .. Name_Len loop
1024 if Name_Buffer (J) = '/' then
1025 Name_Buffer (J) := Directory_Separator;
1026 end if;
1027 end loop;
1029 -- Make sure that Obj_Dir ends with a directory separator
1031 if Name_Buffer (Name_Len) /= Directory_Separator then
1032 Name_Len := Name_Len + 1;
1033 Name_Buffer (Name_Len) := Directory_Separator;
1034 end if;
1036 declare
1037 Obj_Dir : constant String := Name_Buffer (1 .. Name_Len);
1038 Config_Switches : Argument_List_Access;
1039 Db_Switches : Argument_List_Access;
1040 Args : Argument_List (1 .. 5);
1041 Arg_Last : Positive;
1042 Obj_Dir_Exists : Boolean := True;
1044 begin
1045 -- Check if the object directory exists. If Setup_Projects is True
1046 -- (-p) and directory does not exist, attempt to create it.
1047 -- Otherwise, if directory does not exist, fail without calling
1048 -- gprconfig.
1050 if not Is_Directory (Obj_Dir)
1051 and then (Setup_Projects or else Subdirs /= null)
1052 then
1053 begin
1054 Create_Path (Obj_Dir);
1056 if not Quiet_Output then
1057 Write_Str ("object directory """);
1058 Write_Str (Obj_Dir);
1059 Write_Line (""" created");
1060 end if;
1062 exception
1063 when others =>
1064 Raise_Invalid_Config
1065 ("could not create object directory " & Obj_Dir);
1066 end;
1067 end if;
1069 if not Is_Directory (Obj_Dir) then
1070 case Env.Flags.Require_Obj_Dirs is
1071 when Error =>
1072 Raise_Invalid_Config
1073 ("object directory " & Obj_Dir & " does not exist");
1075 when Warning =>
1076 Prj.Err.Error_Msg
1077 (Env.Flags,
1078 "?object directory " & Obj_Dir & " does not exist");
1079 Obj_Dir_Exists := False;
1081 when Silent =>
1082 null;
1083 end case;
1084 end if;
1086 -- Get the config switches. This should be done only now, as some
1087 -- runtimes may have been found in the Builder switches.
1089 Config_Switches := Get_Config_Switches;
1091 -- Get eventual --db switches
1093 Db_Switches := Get_Db_Switches;
1095 -- Invoke gprconfig
1097 Args (1) := new String'("--batch");
1098 Args (2) := new String'("-o");
1100 -- If no config file was specified, set the auto.cgpr one
1102 if Conf_File_Name'Length = 0 then
1103 if Obj_Dir_Exists then
1104 Args (3) := new String'(Obj_Dir & Auto_Cgpr);
1106 else
1107 declare
1108 Path_FD : File_Descriptor;
1109 Path_Name : Path_Name_Type;
1111 begin
1112 Prj.Env.Create_Temp_File
1113 (Shared => Project_Tree.Shared,
1114 Path_FD => Path_FD,
1115 Path_Name => Path_Name,
1116 File_Use => "configuration file");
1118 if Path_FD /= Invalid_FD then
1119 declare
1120 Temp_Dir : constant String :=
1121 Containing_Directory
1122 (Get_Name_String (Path_Name));
1123 begin
1124 GNAT.OS_Lib.Close (Path_FD);
1125 Args (3) :=
1126 new String'(Temp_Dir &
1127 Directory_Separator &
1128 Auto_Cgpr);
1129 Delete_File (Get_Name_String (Path_Name));
1130 end;
1132 else
1133 -- We'll have an error message later on
1135 Args (3) := new String'(Obj_Dir & Auto_Cgpr);
1136 end if;
1137 end;
1138 end if;
1139 else
1140 Args (3) := Conf_File_Name;
1141 end if;
1143 Arg_Last := 3;
1145 if Selected_Target /= null and then
1146 Selected_Target.all /= ""
1148 then
1149 Args (4) :=
1150 new String'("--target=" & Selected_Target.all);
1151 Arg_Last := 4;
1153 elsif Normalized_Hostname /= "" then
1154 if At_Least_One_Compiler_Command then
1155 Args (4) := new String'("--target=all");
1156 else
1157 Args (4) := new String'("--target=" & Normalized_Hostname);
1158 end if;
1160 Arg_Last := 4;
1161 end if;
1163 if not Verbose_Mode then
1164 Arg_Last := Arg_Last + 1;
1165 Args (Arg_Last) := new String'("-q");
1166 end if;
1168 if Verbose_Mode then
1169 Write_Str (Gprconfig_Name);
1171 for J in 1 .. Arg_Last loop
1172 Write_Char (' ');
1173 Write_Str (Args (J).all);
1174 end loop;
1176 for J in Config_Switches'Range loop
1177 Write_Char (' ');
1178 Write_Str (Config_Switches (J).all);
1179 end loop;
1181 for J in Db_Switches'Range loop
1182 Write_Char (' ');
1183 Write_Str (Db_Switches (J).all);
1184 end loop;
1186 Write_Eol;
1188 elsif not Quiet_Output then
1190 -- Display no message if we are creating auto.cgpr, unless in
1191 -- verbose mode.
1193 if Config_File_Name'Length > 0 or else Verbose_Mode then
1194 Write_Str ("creating ");
1195 Write_Str (Simple_Name (Args (3).all));
1196 Write_Eol;
1197 end if;
1198 end if;
1200 Spawn (Gprconfig_Path.all, Args (1 .. Arg_Last) &
1201 Config_Switches.all & Db_Switches.all,
1202 Success);
1204 Free (Config_Switches);
1206 Config_File_Path := Locate_Config_File (Args (3).all);
1208 if Config_File_Path = null then
1209 Raise_Invalid_Config
1210 ("could not create " & Args (3).all);
1211 end if;
1213 for F in Args'Range loop
1214 Free (Args (F));
1215 end loop;
1216 end;
1217 end Do_Autoconf;
1219 ---------------------
1220 -- Get_Db_Switches --
1221 ---------------------
1223 function Get_Db_Switches return Argument_List_Access is
1224 Result : Argument_List_Access;
1225 Nmb_Arg : Natural;
1226 begin
1227 Nmb_Arg :=
1228 (2 * Db_Switch_Args.Last) + Boolean'Pos (not Load_Standard_Base);
1229 Result := new Argument_List (1 .. Nmb_Arg);
1231 if Nmb_Arg /= 0 then
1232 for J in 1 .. Db_Switch_Args.Last loop
1233 Result (2 * J - 1) :=
1234 new String'("--db");
1235 Result (2 * J) :=
1236 new String'(Get_Name_String (Db_Switch_Args.Table (J)));
1237 end loop;
1239 if not Load_Standard_Base then
1240 Result (Result'Last) := new String'("--db-");
1241 end if;
1242 end if;
1244 return Result;
1245 end Get_Db_Switches;
1247 -------------------------
1248 -- Get_Config_Switches --
1249 -------------------------
1251 function Get_Config_Switches return Argument_List_Access is
1253 package Language_Htable is new GNAT.HTable.Simple_HTable
1254 (Header_Num => Prj.Header_Num,
1255 Element => Name_Id,
1256 No_Element => No_Name,
1257 Key => Name_Id,
1258 Hash => Prj.Hash,
1259 Equal => "=");
1260 -- Hash table to keep the languages used in the project tree
1262 IDE : constant Package_Id :=
1263 Value_Of (Name_Ide, Project.Decl.Packages, Shared);
1265 procedure Add_Config_Switches_For_Project
1266 (Project : Project_Id;
1267 Tree : Project_Tree_Ref;
1268 With_State : in out Integer);
1269 -- Add all --config switches for this project. This is also called
1270 -- for aggregate projects.
1272 -------------------------------------
1273 -- Add_Config_Switches_For_Project --
1274 -------------------------------------
1276 procedure Add_Config_Switches_For_Project
1277 (Project : Project_Id;
1278 Tree : Project_Tree_Ref;
1279 With_State : in out Integer)
1281 pragma Unreferenced (With_State);
1283 Shared : constant Shared_Project_Tree_Data_Access := Tree.Shared;
1285 Variable : Variable_Value;
1286 Check_Default : Boolean;
1287 Lang : Name_Id;
1288 List : String_List_Id;
1289 Elem : String_Element;
1291 begin
1292 if Might_Have_Sources (Project) then
1293 Variable :=
1294 Value_Of (Name_Languages, Project.Decl.Attributes, Shared);
1296 if Variable = Nil_Variable_Value or else Variable.Default then
1298 -- Languages is not declared. If it is not an extending
1299 -- project, or if it extends a project with no Languages,
1300 -- check for Default_Language.
1302 Check_Default := Project.Extends = No_Project;
1304 if not Check_Default then
1305 Variable :=
1306 Value_Of
1307 (Name_Languages,
1308 Project.Extends.Decl.Attributes,
1309 Shared);
1310 Check_Default :=
1311 Variable /= Nil_Variable_Value
1312 and then Variable.Values = Nil_String;
1313 end if;
1315 if Check_Default then
1316 Variable :=
1317 Value_Of
1318 (Name_Default_Language,
1319 Project.Decl.Attributes,
1320 Shared);
1322 if Variable /= Nil_Variable_Value
1323 and then not Variable.Default
1324 then
1325 Get_Name_String (Variable.Value);
1326 To_Lower (Name_Buffer (1 .. Name_Len));
1327 Lang := Name_Find;
1328 Language_Htable.Set (Lang, Lang);
1330 -- If no default language is declared, default to Ada
1332 else
1333 Language_Htable.Set (Name_Ada, Name_Ada);
1334 end if;
1335 end if;
1337 elsif Variable.Values /= Nil_String then
1339 -- Attribute Languages is declared with a non empty list:
1340 -- put all the languages in Language_HTable.
1342 List := Variable.Values;
1343 while List /= Nil_String loop
1344 Elem := Shared.String_Elements.Table (List);
1346 Get_Name_String (Elem.Value);
1347 To_Lower (Name_Buffer (1 .. Name_Len));
1348 Lang := Name_Find;
1349 Language_Htable.Set (Lang, Lang);
1351 List := Elem.Next;
1352 end loop;
1353 end if;
1354 end if;
1355 end Add_Config_Switches_For_Project;
1357 procedure For_Every_Imported_Project is new For_Every_Project_Imported
1358 (State => Integer, Action => Add_Config_Switches_For_Project);
1359 -- Document this procedure ???
1361 -- Local variables
1363 Name : Name_Id;
1364 Count : Natural;
1365 Result : Argument_List_Access;
1366 Variable : Variable_Value;
1367 Dummy : Integer := 0;
1369 -- Start of processing for Get_Config_Switches
1371 begin
1372 For_Every_Imported_Project
1373 (By => Project,
1374 Tree => Project_Tree,
1375 With_State => Dummy,
1376 Include_Aggregated => True);
1378 Name := Language_Htable.Get_First;
1379 Count := 0;
1380 while Name /= No_Name loop
1381 Count := Count + 1;
1382 Name := Language_Htable.Get_Next;
1383 end loop;
1385 Result := new String_List (1 .. Count);
1387 Count := 1;
1388 Name := Language_Htable.Get_First;
1389 while Name /= No_Name loop
1391 -- Check if IDE'Compiler_Command is declared for the language.
1392 -- If it is, use its value to invoke gprconfig.
1394 Variable :=
1395 Value_Of
1396 (Name,
1397 Attribute_Or_Array_Name => Name_Compiler_Command,
1398 In_Package => IDE,
1399 Shared => Shared,
1400 Force_Lower_Case_Index => True);
1402 declare
1403 Config_Command : constant String :=
1404 "--config=" & Get_Name_String (Name);
1406 Runtime_Name : constant String := Runtime_Name_For (Name);
1408 begin
1409 -- In CodePeer mode, we do not take into account any compiler
1410 -- command from the package IDE.
1412 if CodePeer_Mode
1413 or else Variable = Nil_Variable_Value
1414 or else Length_Of_Name (Variable.Value) = 0
1415 then
1416 Result (Count) :=
1417 new String'(Config_Command & ",," & Runtime_Name);
1419 else
1420 At_Least_One_Compiler_Command := True;
1422 declare
1423 Compiler_Command : constant String :=
1424 Get_Name_String (Variable.Value);
1426 begin
1427 if Is_Absolute_Path (Compiler_Command) then
1428 Result (Count) :=
1429 new String'
1430 (Config_Command & ",," & Runtime_Name & ","
1431 & Containing_Directory (Compiler_Command) & ","
1432 & Simple_Name (Compiler_Command));
1433 else
1434 Result (Count) :=
1435 new String'
1436 (Config_Command & ",," & Runtime_Name & ",,"
1437 & Compiler_Command);
1438 end if;
1439 end;
1440 end if;
1441 end;
1443 Count := Count + 1;
1444 Name := Language_Htable.Get_Next;
1445 end loop;
1447 return Result;
1448 end Get_Config_Switches;
1450 ------------------------
1451 -- Might_Have_Sources --
1452 ------------------------
1454 function Might_Have_Sources (Project : Project_Id) return Boolean is
1455 Variable : Variable_Value;
1457 begin
1458 Variable :=
1459 Value_Of (Name_Source_Dirs, Project.Decl.Attributes, Shared);
1461 if Variable = Nil_Variable_Value
1462 or else Variable.Default
1463 or else Variable.Values /= Nil_String
1464 then
1465 Variable :=
1466 Value_Of (Name_Source_Files, Project.Decl.Attributes, Shared);
1467 return Variable = Nil_Variable_Value
1468 or else Variable.Default
1469 or else Variable.Values /= Nil_String;
1471 else
1472 return False;
1473 end if;
1474 end Might_Have_Sources;
1476 -- Local Variables
1478 Success : Boolean;
1479 Config_Project_Node : Project_Node_Id := Empty_Node;
1481 -- Start of processing for Get_Or_Create_Configuration_File
1483 begin
1484 pragma Assert (Prj.Env.Is_Initialized (Env.Project_Path));
1486 Free (Config_File_Path);
1487 Config := No_Project;
1489 Get_Project_Target;
1490 Get_Project_Runtimes;
1491 Check_Builder_Switches;
1493 -- Do not attempt to find a configuration project file when
1494 -- Config_File_Name is No_Configuration_File.
1496 if Config_File_Name = No_Configuration_File then
1497 Config_File_Path := null;
1499 else
1500 if Conf_File_Name'Length > 0 then
1501 Config_File_Path := Locate_Config_File (Conf_File_Name.all);
1502 else
1503 Config_File_Path := Locate_Config_File (Default_File_Name);
1504 end if;
1506 if Config_File_Path = null then
1507 if not Allow_Automatic_Generation
1508 and then Conf_File_Name'Length > 0
1509 then
1510 Raise_Invalid_Config
1511 ("could not locate main configuration project "
1512 & Conf_File_Name.all);
1513 end if;
1514 end if;
1515 end if;
1517 Automatically_Generated :=
1518 Allow_Automatic_Generation and then Config_File_Path = null;
1520 <<Process_Config_File>>
1522 if Automatically_Generated then
1524 -- This might raise an Invalid_Config exception
1526 Do_Autoconf;
1528 -- If the config file is not auto-generated, warn if there is any --RTS
1529 -- switch, but not when the config file is generated in memory.
1531 elsif Warn_For_RTS
1532 and then RTS_Languages.Get_First /= No_Name
1533 and then Opt.Warning_Mode /= Opt.Suppress
1534 and then On_Load_Config = null
1535 then
1536 Write_Line
1537 ("warning: " &
1538 "runtimes are taken into account only in auto-configuration");
1539 end if;
1541 -- Parse the configuration file
1543 if Verbose_Mode and then Config_File_Path /= null then
1544 Write_Str ("Checking configuration ");
1545 Write_Line (Config_File_Path.all);
1546 end if;
1548 if Config_File_Path /= null then
1549 Prj.Part.Parse
1550 (In_Tree => Project_Node_Tree,
1551 Project => Config_Project_Node,
1552 Project_File_Name => Config_File_Path.all,
1553 Errout_Handling => Prj.Part.Finalize_If_Error,
1554 Packages_To_Check => Packages_To_Check,
1555 Current_Directory => Current_Directory,
1556 Is_Config_File => True,
1557 Env => Env);
1558 else
1559 Config_Project_Node := Empty_Node;
1560 end if;
1562 if On_Load_Config /= null then
1563 On_Load_Config
1564 (Config_File => Config_Project_Node,
1565 Project_Node_Tree => Project_Node_Tree);
1566 end if;
1568 if Config_Project_Node /= Empty_Node then
1569 Prj.Proc.Process_Project_Tree_Phase_1
1570 (In_Tree => Project_Tree,
1571 Project => Config,
1572 Packages_To_Check => Packages_To_Check,
1573 Success => Success,
1574 From_Project_Node => Config_Project_Node,
1575 From_Project_Node_Tree => Project_Node_Tree,
1576 Env => Env,
1577 Reset_Tree => False,
1578 On_New_Tree_Loaded => null);
1579 end if;
1581 if Config_Project_Node = Empty_Node or else Config = No_Project then
1582 Raise_Invalid_Config
1583 ("processing of configuration project """
1584 & Config_File_Path.all & """ failed");
1585 end if;
1587 -- Check that the target of the configuration file is the one the user
1588 -- specified on the command line. We do not need to check that when in
1589 -- auto-conf mode, since the appropriate target was passed to gprconfig.
1591 if not Automatically_Generated
1592 and then not
1593 Check_Target
1594 (Config, Autoconf_Specified, Project_Tree, Selected_Target.all)
1595 then
1596 Automatically_Generated := True;
1597 goto Process_Config_File;
1598 end if;
1599 end Get_Or_Create_Configuration_File;
1601 ------------------------
1602 -- Locate_Config_File --
1603 ------------------------
1605 function Locate_Config_File (Name : String) return String_Access is
1606 Prefix_Path : constant String := Executable_Prefix_Path;
1607 begin
1608 if Prefix_Path'Length /= 0 then
1609 return Locate_Regular_File
1610 (Name,
1611 "." & Path_Separator &
1612 Prefix_Path & "share" & Directory_Separator & "gpr");
1613 else
1614 return Locate_Regular_File (Name, ".");
1615 end if;
1616 end Locate_Config_File;
1618 ------------------------------------
1619 -- Parse_Project_And_Apply_Config --
1620 ------------------------------------
1622 procedure Parse_Project_And_Apply_Config
1623 (Main_Project : out Prj.Project_Id;
1624 User_Project_Node : out Prj.Tree.Project_Node_Id;
1625 Config_File_Name : String := "";
1626 Autoconf_Specified : Boolean;
1627 Project_File_Name : String;
1628 Project_Tree : Prj.Project_Tree_Ref;
1629 Project_Node_Tree : Prj.Tree.Project_Node_Tree_Ref;
1630 Env : in out Prj.Tree.Environment;
1631 Packages_To_Check : String_List_Access;
1632 Allow_Automatic_Generation : Boolean := True;
1633 Automatically_Generated : out Boolean;
1634 Config_File_Path : out String_Access;
1635 Target_Name : String := "";
1636 Normalized_Hostname : String;
1637 On_Load_Config : Config_File_Hook := null;
1638 Implicit_Project : Boolean := False;
1639 On_New_Tree_Loaded : Prj.Proc.Tree_Loaded_Callback := null)
1641 Success : Boolean := False;
1642 Target_Try_Again : Boolean := True;
1643 Config_Try_Again : Boolean;
1645 Finalization : Prj.Part.Errout_Mode := Prj.Part.Always_Finalize;
1647 S : State := No_State;
1649 Conf_File_Name : String_Access := new String'(Config_File_Name);
1651 procedure Add_Directory (Dir : String);
1652 -- Add a directory at the end of the Project Path
1654 Auto_Generated : Boolean;
1656 -------------------
1657 -- Add_Directory --
1658 -------------------
1660 procedure Add_Directory (Dir : String) is
1661 begin
1662 if Opt.Verbose_Mode then
1663 Write_Line (" Adding directory """ & Dir & """");
1664 end if;
1666 Prj.Env.Add_Directories (Env.Project_Path, Dir);
1667 end Add_Directory;
1669 begin
1670 pragma Assert (Prj.Env.Is_Initialized (Env.Project_Path));
1672 -- Start with ignoring missing withed projects
1674 Set_Ignore_Missing_With (Env.Flags, True);
1676 -- Note: If in fact the config file is automatically generated, then
1677 -- Automatically_Generated will be set to True after invocation of
1678 -- Process_Project_And_Apply_Config.
1680 Automatically_Generated := False;
1682 -- Record Target_Value and Target_Origin
1684 if Target_Name = "" then
1685 Opt.Target_Value := new String'(Normalized_Hostname);
1686 Opt.Target_Origin := Default;
1687 else
1688 Opt.Target_Value := new String'(Target_Name);
1689 Opt.Target_Origin := Specified;
1690 end if;
1692 <<Parse_Again>>
1694 -- Parse the user project tree
1696 Project_Node_Tree.Incomplete_With := False;
1697 Env.Flags.Incomplete_Withs := False;
1698 Prj.Initialize (Project_Tree);
1700 Main_Project := No_Project;
1702 Prj.Part.Parse
1703 (In_Tree => Project_Node_Tree,
1704 Project => User_Project_Node,
1705 Project_File_Name => Project_File_Name,
1706 Errout_Handling => Finalization,
1707 Packages_To_Check => Packages_To_Check,
1708 Current_Directory => Current_Directory,
1709 Is_Config_File => False,
1710 Env => Env,
1711 Implicit_Project => Implicit_Project);
1713 Finalization := Prj.Part.Finalize_If_Error;
1715 if User_Project_Node = Empty_Node then
1716 return;
1717 end if;
1719 -- If --target was not specified on the command line, then do Phase 1 to
1720 -- check if attribute Target is declared in the main project.
1722 if Opt.Target_Origin /= Specified then
1723 Main_Project := No_Project;
1724 Process_Project_Tree_Phase_1
1725 (In_Tree => Project_Tree,
1726 Project => Main_Project,
1727 Packages_To_Check => Packages_To_Check,
1728 Success => Success,
1729 From_Project_Node => User_Project_Node,
1730 From_Project_Node_Tree => Project_Node_Tree,
1731 Env => Env,
1732 Reset_Tree => True,
1733 On_New_Tree_Loaded => On_New_Tree_Loaded);
1735 if not Success then
1736 Main_Project := No_Project;
1737 return;
1738 end if;
1740 declare
1741 Variable : constant Variable_Value :=
1742 Value_Of
1743 (Name_Target,
1744 Main_Project.Decl.Attributes,
1745 Project_Tree.Shared);
1746 begin
1747 if Variable /= Nil_Variable_Value
1748 and then not Variable.Default
1749 and then
1750 Get_Name_String (Variable.Value) /= Opt.Target_Value.all
1751 then
1752 if Target_Try_Again then
1753 Opt.Target_Value :=
1754 new String'(Get_Name_String (Variable.Value));
1755 Target_Try_Again := False;
1756 goto Parse_Again;
1758 else
1759 Fail_Program
1760 (Project_Tree,
1761 "inconsistent value of attribute Target");
1762 end if;
1763 end if;
1764 end;
1765 end if;
1767 -- If there are missing withed projects, the projects will be parsed
1768 -- again after the project path is extended with directories rooted
1769 -- at the compiler roots.
1771 Config_Try_Again := Project_Node_Tree.Incomplete_With;
1773 Process_Project_And_Apply_Config
1774 (Main_Project => Main_Project,
1775 User_Project_Node => User_Project_Node,
1776 Config_File_Name => Conf_File_Name.all,
1777 Autoconf_Specified => Autoconf_Specified,
1778 Project_Tree => Project_Tree,
1779 Project_Node_Tree => Project_Node_Tree,
1780 Env => Env,
1781 Packages_To_Check => Packages_To_Check,
1782 Allow_Automatic_Generation => Allow_Automatic_Generation,
1783 Automatically_Generated => Auto_Generated,
1784 Config_File_Path => Config_File_Path,
1785 Target_Name => Target_Name,
1786 Normalized_Hostname => Normalized_Hostname,
1787 On_Load_Config => On_Load_Config,
1788 On_New_Tree_Loaded => On_New_Tree_Loaded,
1789 Do_Phase_1 => Opt.Target_Origin = Specified);
1791 if Auto_Generated then
1792 Automatically_Generated := True;
1793 end if;
1795 -- Exit if there was an error. Otherwise, if Config_Try_Again is True,
1796 -- update the project path and try again.
1798 if Main_Project /= No_Project and then Config_Try_Again then
1799 Set_Ignore_Missing_With (Env.Flags, False);
1801 if Config_File_Path /= null then
1802 Conf_File_Name := new String'(Config_File_Path.all);
1803 end if;
1805 -- For the second time the project files are parsed, the warning for
1806 -- --RTS= being only taken into account in auto-configuration are
1807 -- suppressed, as we are no longer in auto-configuration.
1809 Warn_For_RTS := False;
1811 -- Add the default directories corresponding to the compilers
1813 Update_Project_Path
1814 (By => Main_Project,
1815 Tree => Project_Tree,
1816 With_State => S,
1817 Include_Aggregated => True,
1818 Imported_First => False);
1820 declare
1821 Compiler_Root : Compiler_Root_Ptr;
1822 Prefix : String_Access;
1823 Runtime_Root : Runtime_Root_Ptr;
1824 Path_Value : constant String_Access := Getenv ("PATH");
1826 begin
1827 if Opt.Verbose_Mode then
1828 Write_Line ("Setting the default project search directories");
1830 if Prj.Current_Verbosity = High then
1831 if Path_Value = null or else Path_Value'Length = 0 then
1832 Write_Line ("No environment variable PATH");
1834 else
1835 Write_Line ("PATH =");
1836 Write_Line (" " & Path_Value.all);
1837 end if;
1838 end if;
1839 end if;
1841 -- Reorder the compiler roots in the PATH order
1843 if First_Compiler_Root /= null
1844 and then First_Compiler_Root.Next /= null
1845 then
1846 declare
1847 Pred : Compiler_Root_Ptr;
1848 First_New_Comp : Compiler_Root_Ptr := null;
1849 New_Comp : Compiler_Root_Ptr := null;
1850 First : Positive := Path_Value'First;
1851 Last : Positive;
1852 Path_Last : Positive;
1853 begin
1854 while First <= Path_Value'Last loop
1855 Last := First;
1857 if Path_Value (First) /= Path_Separator then
1858 while Last < Path_Value'Last
1859 and then Path_Value (Last + 1) /= Path_Separator
1860 loop
1861 Last := Last + 1;
1862 end loop;
1864 Path_Last := Last;
1865 while Path_Last > First
1866 and then
1867 Path_Value (Path_Last) = Directory_Separator
1868 loop
1869 Path_Last := Path_Last - 1;
1870 end loop;
1872 if Path_Last > First + 4
1873 and then
1874 Path_Value (Path_Last - 2 .. Path_Last) = "bin"
1875 and then
1876 Path_Value (Path_Last - 3) = Directory_Separator
1877 then
1878 Path_Last := Path_Last - 4;
1879 Pred := null;
1880 Compiler_Root := First_Compiler_Root;
1881 while Compiler_Root /= null
1882 and then Compiler_Root.Root.all /=
1883 Path_Value (First .. Path_Last)
1884 loop
1885 Pred := Compiler_Root;
1886 Compiler_Root := Compiler_Root.Next;
1887 end loop;
1889 if Compiler_Root /= null then
1890 if Pred = null then
1891 First_Compiler_Root :=
1892 First_Compiler_Root.Next;
1893 else
1894 Pred.Next := Compiler_Root.Next;
1895 end if;
1897 if First_New_Comp = null then
1898 First_New_Comp := Compiler_Root;
1899 else
1900 New_Comp.Next := Compiler_Root;
1901 end if;
1903 New_Comp := Compiler_Root;
1904 New_Comp.Next := null;
1905 end if;
1906 end if;
1907 end if;
1909 First := Last + 1;
1910 end loop;
1912 if First_New_Comp /= null then
1913 New_Comp.Next := First_Compiler_Root;
1914 First_Compiler_Root := First_New_Comp;
1915 end if;
1916 end;
1917 end if;
1919 -- Now that the compiler roots are in a correct order, add the
1920 -- directories corresponding to these compiler roots in the
1921 -- project path.
1923 Compiler_Root := First_Compiler_Root;
1924 while Compiler_Root /= null loop
1925 Prefix := Compiler_Root.Root;
1927 Runtime_Root := Compiler_Root.Runtimes;
1928 while Runtime_Root /= null loop
1929 Add_Directory
1930 (Runtime_Root.Root.all &
1931 Directory_Separator &
1932 "lib" &
1933 Directory_Separator &
1934 "gnat");
1935 Add_Directory
1936 (Runtime_Root.Root.all &
1937 Directory_Separator &
1938 "share" &
1939 Directory_Separator &
1940 "gpr");
1941 Runtime_Root := Runtime_Root.Next;
1942 end loop;
1944 Add_Directory
1945 (Prefix.all &
1946 Directory_Separator &
1947 Opt.Target_Value.all &
1948 Directory_Separator &
1949 "lib" &
1950 Directory_Separator &
1951 "gnat");
1952 Add_Directory
1953 (Prefix.all &
1954 Directory_Separator &
1955 Opt.Target_Value.all &
1956 Directory_Separator &
1957 "share" &
1958 Directory_Separator &
1959 "gpr");
1960 Add_Directory
1961 (Prefix.all &
1962 Directory_Separator &
1963 "share" &
1964 Directory_Separator &
1965 "gpr");
1966 Add_Directory
1967 (Prefix.all &
1968 Directory_Separator &
1969 "lib" &
1970 Directory_Separator &
1971 "gnat");
1972 Compiler_Root := Compiler_Root.Next;
1973 end loop;
1974 end;
1976 -- And parse again the project files. There will be no missing
1977 -- withed projects, as Ignore_Missing_With is set to False in
1978 -- the environment flags, so there is no risk of endless loop here.
1980 goto Parse_Again;
1981 end if;
1982 end Parse_Project_And_Apply_Config;
1984 --------------------------------------
1985 -- Process_Project_And_Apply_Config --
1986 --------------------------------------
1988 procedure Process_Project_And_Apply_Config
1989 (Main_Project : out Prj.Project_Id;
1990 User_Project_Node : Prj.Tree.Project_Node_Id;
1991 Config_File_Name : String := "";
1992 Autoconf_Specified : Boolean;
1993 Project_Tree : Prj.Project_Tree_Ref;
1994 Project_Node_Tree : Prj.Tree.Project_Node_Tree_Ref;
1995 Env : in out Prj.Tree.Environment;
1996 Packages_To_Check : String_List_Access;
1997 Allow_Automatic_Generation : Boolean := True;
1998 Automatically_Generated : out Boolean;
1999 Config_File_Path : out String_Access;
2000 Target_Name : String := "";
2001 Normalized_Hostname : String;
2002 On_Load_Config : Config_File_Hook := null;
2003 Reset_Tree : Boolean := True;
2004 On_New_Tree_Loaded : Prj.Proc.Tree_Loaded_Callback := null;
2005 Do_Phase_1 : Boolean := True)
2007 Shared : constant Shared_Project_Tree_Data_Access :=
2008 Project_Tree.Shared;
2009 Main_Config_Project : Project_Id;
2010 Success : Boolean;
2012 Conf_Project : Project_Id := No_Project;
2013 -- The object directory of this project is used to store the config
2014 -- project file in auto-configuration. Set by Check_Project below.
2016 procedure Check_Project (Project : Project_Id);
2017 -- Look for a non aggregate project. If one is found, put its project Id
2018 -- in Conf_Project.
2020 -------------------
2021 -- Check_Project --
2022 -------------------
2024 procedure Check_Project (Project : Project_Id) is
2025 begin
2026 if Project.Qualifier = Aggregate
2027 or else
2028 Project.Qualifier = Aggregate_Library
2029 then
2030 declare
2031 List : Aggregated_Project_List := Project.Aggregated_Projects;
2033 begin
2034 -- Look for a non aggregate project until one is found
2036 while Conf_Project = No_Project and then List /= null loop
2037 Check_Project (List.Project);
2038 List := List.Next;
2039 end loop;
2040 end;
2042 else
2043 Conf_Project := Project;
2044 end if;
2045 end Check_Project;
2047 -- Start of processing for Process_Project_And_Apply_Config
2049 begin
2050 Automatically_Generated := False;
2052 if Do_Phase_1 then
2053 Main_Project := No_Project;
2054 Process_Project_Tree_Phase_1
2055 (In_Tree => Project_Tree,
2056 Project => Main_Project,
2057 Packages_To_Check => Packages_To_Check,
2058 Success => Success,
2059 From_Project_Node => User_Project_Node,
2060 From_Project_Node_Tree => Project_Node_Tree,
2061 Env => Env,
2062 Reset_Tree => Reset_Tree,
2063 On_New_Tree_Loaded => On_New_Tree_Loaded);
2065 if not Success then
2066 Main_Project := No_Project;
2067 return;
2068 end if;
2069 end if;
2071 if Project_Tree.Source_Info_File_Name /= null then
2072 if not Is_Absolute_Path (Project_Tree.Source_Info_File_Name.all) then
2073 declare
2074 Obj_Dir : constant Variable_Value :=
2075 Value_Of
2076 (Name_Object_Dir,
2077 Main_Project.Decl.Attributes,
2078 Shared);
2080 begin
2081 if Obj_Dir = Nil_Variable_Value or else Obj_Dir.Default then
2082 Get_Name_String (Main_Project.Directory.Display_Name);
2084 else
2085 if Is_Absolute_Path (Get_Name_String (Obj_Dir.Value)) then
2086 Get_Name_String (Obj_Dir.Value);
2088 else
2089 Name_Len := 0;
2090 Add_Str_To_Name_Buffer
2091 (Get_Name_String (Main_Project.Directory.Display_Name));
2092 Add_Str_To_Name_Buffer (Get_Name_String (Obj_Dir.Value));
2093 end if;
2094 end if;
2096 Add_Char_To_Name_Buffer (Directory_Separator);
2097 Add_Str_To_Name_Buffer (Project_Tree.Source_Info_File_Name.all);
2098 Free (Project_Tree.Source_Info_File_Name);
2099 Project_Tree.Source_Info_File_Name :=
2100 new String'(Name_Buffer (1 .. Name_Len));
2101 end;
2102 end if;
2104 Read_Source_Info_File (Project_Tree);
2105 end if;
2107 -- Get the first project that is not an aggregate project or an
2108 -- aggregate library project. The object directory of this project will
2109 -- be used to store the config project file in auto-configuration.
2111 Check_Project (Main_Project);
2113 -- Fail if there is only aggregate projects and aggregate library
2114 -- projects in the project tree.
2116 if Conf_Project = No_Project then
2117 Raise_Invalid_Config ("there are no non-aggregate projects");
2118 end if;
2120 -- Find configuration file
2122 Get_Or_Create_Configuration_File
2123 (Config => Main_Config_Project,
2124 Project => Main_Project,
2125 Conf_Project => Conf_Project,
2126 Project_Tree => Project_Tree,
2127 Project_Node_Tree => Project_Node_Tree,
2128 Env => Env,
2129 Allow_Automatic_Generation => Allow_Automatic_Generation,
2130 Config_File_Name => Config_File_Name,
2131 Autoconf_Specified => Autoconf_Specified,
2132 Target_Name => Target_Name,
2133 Normalized_Hostname => Normalized_Hostname,
2134 Packages_To_Check => Packages_To_Check,
2135 Config_File_Path => Config_File_Path,
2136 Automatically_Generated => Automatically_Generated,
2137 On_Load_Config => On_Load_Config);
2139 Apply_Config_File (Main_Config_Project, Project_Tree);
2141 -- Finish processing the user's project
2143 Prj.Proc.Process_Project_Tree_Phase_2
2144 (In_Tree => Project_Tree,
2145 Project => Main_Project,
2146 Success => Success,
2147 From_Project_Node => User_Project_Node,
2148 From_Project_Node_Tree => Project_Node_Tree,
2149 Env => Env);
2151 if Success then
2152 if Project_Tree.Source_Info_File_Name /= null
2153 and then not Project_Tree.Source_Info_File_Exists
2154 then
2155 Write_Source_Info_File (Project_Tree);
2156 end if;
2158 else
2159 Main_Project := No_Project;
2160 end if;
2161 end Process_Project_And_Apply_Config;
2163 --------------------------
2164 -- Raise_Invalid_Config --
2165 --------------------------
2167 procedure Raise_Invalid_Config (Msg : String) is
2168 begin
2169 Raise_Exception (Invalid_Config'Identity, Msg);
2170 end Raise_Invalid_Config;
2172 ----------------------
2173 -- Runtime_Name_For --
2174 ----------------------
2176 function Runtime_Name_For (Language : Name_Id) return String is
2177 begin
2178 if RTS_Languages.Get (Language) /= No_Name then
2179 return Get_Name_String (RTS_Languages.Get (Language));
2180 else
2181 return "";
2182 end if;
2183 end Runtime_Name_For;
2185 --------------------------
2186 -- Runtime_Name_Set_For --
2187 --------------------------
2189 function Runtime_Name_Set_For (Language : Name_Id) return Boolean is
2190 begin
2191 return RTS_Languages.Get (Language) /= No_Name;
2192 end Runtime_Name_Set_For;
2194 ---------------------
2195 -- Set_Runtime_For --
2196 ---------------------
2198 procedure Set_Runtime_For (Language : Name_Id; RTS_Name : String) is
2199 begin
2200 Name_Len := RTS_Name'Length;
2201 Name_Buffer (1 .. Name_Len) := RTS_Name;
2202 RTS_Languages.Set (Language, Name_Find);
2203 end Set_Runtime_For;
2205 ----------------------------
2206 -- Look_For_Project_Paths --
2207 ----------------------------
2209 procedure Look_For_Project_Paths
2210 (Project : Project_Id;
2211 Tree : Project_Tree_Ref;
2212 With_State : in out State)
2214 Lang_Id : Language_Ptr;
2215 Compiler_Root : Compiler_Root_Ptr;
2216 Runtime_Root : Runtime_Root_Ptr;
2217 Comp_Driver : String_Access;
2218 Comp_Dir : String_Access;
2219 Prefix : String_Access;
2221 pragma Unreferenced (Tree);
2223 begin
2224 With_State := No_State;
2226 Lang_Id := Project.Languages;
2227 while Lang_Id /= No_Language_Index loop
2228 if Lang_Id.Config.Compiler_Driver /= No_File then
2229 Comp_Driver :=
2230 new String'
2231 (Get_Name_String (Lang_Id.Config.Compiler_Driver));
2233 -- Get the absolute path of the compiler driver
2235 if not Is_Absolute_Path (Comp_Driver.all) then
2236 Comp_Driver := Locate_Exec_On_Path (Comp_Driver.all);
2237 end if;
2239 if Comp_Driver /= null and then Comp_Driver'Length > 0 then
2240 Comp_Dir :=
2241 new String'
2242 (Containing_Directory (Comp_Driver.all));
2244 -- Consider only the compiler drivers that are in "bin"
2245 -- subdirectories.
2247 if Simple_Name (Comp_Dir.all) = "bin" then
2248 Prefix :=
2249 new String'(Containing_Directory (Comp_Dir.all));
2251 -- Check if the compiler root is already in the list. If it
2252 -- is not, add it to the list.
2254 Compiler_Root := First_Compiler_Root;
2255 while Compiler_Root /= null loop
2256 exit when Prefix.all = Compiler_Root.Root.all;
2257 Compiler_Root := Compiler_Root.Next;
2258 end loop;
2260 if Compiler_Root = null then
2261 First_Compiler_Root :=
2262 new Compiler_Root_Data'
2263 (Root => Prefix,
2264 Runtimes => null,
2265 Next => First_Compiler_Root);
2266 Compiler_Root := First_Compiler_Root;
2267 end if;
2269 -- If there is a runtime for this compiler, check if it is
2270 -- recorded with the compiler root. If it is not, record
2271 -- the runtime.
2273 declare
2274 Runtime : constant String :=
2275 Runtime_Name_For (Lang_Id.Name);
2276 Root : String_Access;
2278 begin
2279 if Runtime'Length > 0 then
2280 if Is_Absolute_Path (Runtime) then
2281 Root := new String'(Runtime);
2283 else
2284 Root :=
2285 new String'
2286 (Prefix.all &
2287 Directory_Separator &
2288 Opt.Target_Value.all &
2289 Directory_Separator &
2290 Runtime);
2291 end if;
2293 Runtime_Root := Compiler_Root.Runtimes;
2294 while Runtime_Root /= null loop
2295 exit when Root.all = Runtime_Root.Root.all;
2296 Runtime_Root := Runtime_Root.Next;
2297 end loop;
2299 if Runtime_Root = null then
2300 Compiler_Root.Runtimes :=
2301 new Runtime_Root_Data'
2302 (Root => Root,
2303 Next => Compiler_Root.Runtimes);
2304 end if;
2305 end if;
2306 end;
2307 end if;
2308 end if;
2309 end if;
2311 Lang_Id := Lang_Id.Next;
2312 end loop;
2313 end Look_For_Project_Paths;
2314 end Prj.Conf;