OSDN Git Service

2009-06-23 Javier Miranda <miranda@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / prj-conf.adb
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-2009, 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 2,  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 COPYING.  If not, write --
19 -- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
20 -- Boston, MA 02110-1301, USA.                                              --
21 --                                                                          --
22 -- GNAT was originally developed  by the GNAT team at  New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
24 --                                                                          --
25 ------------------------------------------------------------------------------
26
27 with Ada.Directories;  use Ada.Directories;
28 with GNAT.HTable;      use GNAT.HTable;
29 with Makeutl;          use Makeutl;
30 with Opt;              use Opt;
31 with Output;           use Output;
32 with Prj.Part;
33 with Prj.Proc;         use Prj.Proc;
34 with Prj.Tree;         use Prj.Tree;
35 with Prj.Util;         use Prj.Util;
36 with Prj;              use Prj;
37 with Sinput.P;
38 with Snames;           use Snames;
39 with System.Case_Util; use System.Case_Util;
40 with System;
41
42 package body Prj.Conf is
43
44    Auto_Cgpr : constant String := "auto.cgpr";
45
46    Default_Name : constant String := "default.cgpr";
47    --  Default configuration file that will be used if found
48
49    Config_Project_Env_Var : constant String := "GPR_CONFIG";
50    --  Name of the environment variable that provides the name of the
51    --  configuration file to use.
52
53    Gprconfig_Name : constant String := "gprconfig";
54
55    package RTS_Languages is new GNAT.HTable.Simple_HTable
56      (Header_Num => Prj.Header_Num,
57       Element    => Name_Id,
58       No_Element => No_Name,
59       Key        => Name_Id,
60       Hash       => Prj.Hash,
61       Equal      => "=");
62    --  Stores the runtime names for the various languages. This is in general
63    --  set from a --RTS command line option.
64
65    procedure Add_Attributes
66      (Project_Tree : Project_Tree_Ref;
67       Conf_Decl    : Declarations;
68       User_Decl    : in out Declarations);
69    --  Process the attributes in the config declarations.
70    --  For single string values, if the attribute is not declared in the user
71    --  declarations, declare it with the value in the config declarations.
72    --  For string list values, prepend the value in the user declarations with
73    --  the value in the config declarations.
74
75    function Locate_Config_File (Name : String) return String_Access;
76    --  Search for Name in the config files directory. Return full path if
77    --  found, or null otherwise
78
79    function Check_Target
80      (Config_File        : Prj.Project_Id;
81       Autoconf_Specified : Boolean;
82       Project_Tree       : Prj.Project_Tree_Ref;
83       Target             : String := "") return Boolean;
84    --  Check that the config file's target matches Target.
85    --  Target should be set to the empty string when the user did not specify
86    --  a target. If the target in the configuration file is invalid, this
87    --  function will raise Invalid_Config with an appropriate message.
88    --  Autoconf_Specified should be set to True if the user has used --autoconf
89
90    --------------------
91    -- Add_Attributes --
92    --------------------
93
94    procedure Add_Attributes
95      (Project_Tree : Project_Tree_Ref;
96       Conf_Decl    : Declarations;
97       User_Decl    : in out Declarations)
98    is
99       Conf_Attr_Id       : Variable_Id;
100       Conf_Attr          : Variable;
101       Conf_Array_Id      : Array_Id;
102       Conf_Array         : Array_Data;
103       Conf_Array_Elem_Id : Array_Element_Id;
104       Conf_Array_Elem    : Array_Element;
105       Conf_List          : String_List_Id;
106       Conf_List_Elem     : String_Element;
107
108       User_Attr_Id       : Variable_Id;
109       User_Attr          : Variable;
110       User_Array_Id      : Array_Id;
111       User_Array         : Array_Data;
112       User_Array_Elem_Id : Array_Element_Id;
113       User_Array_Elem    : Array_Element;
114
115    begin
116       Conf_Attr_Id := Conf_Decl.Attributes;
117       User_Attr_Id := User_Decl.Attributes;
118       while Conf_Attr_Id /= No_Variable loop
119          Conf_Attr :=
120            Project_Tree.Variable_Elements.Table (Conf_Attr_Id);
121          User_Attr :=
122            Project_Tree.Variable_Elements.Table (User_Attr_Id);
123
124          if not Conf_Attr.Value.Default then
125             if User_Attr.Value.Default then
126
127                --  No attribute declared in user project file: just copy the
128                --  value of the configuration attribute.
129
130                User_Attr.Value := Conf_Attr.Value;
131                Project_Tree.Variable_Elements.Table (User_Attr_Id) :=
132                  User_Attr;
133
134             elsif User_Attr.Value.Kind = List
135               and then Conf_Attr.Value.Values /= Nil_String
136             then
137                --  List attribute declared in both the user project and the
138                --  configuration project: prepend the user list with the
139                --  configuration list.
140
141                declare
142                   Conf_List : String_List_Id := Conf_Attr.Value.Values;
143                   Conf_Elem : String_Element;
144                   User_List : constant String_List_Id :=
145                                 User_Attr.Value.Values;
146                   New_List : String_List_Id;
147                   New_Elem : String_Element;
148
149                begin
150                   --  Create new list
151
152                   String_Element_Table.Increment_Last
153                     (Project_Tree.String_Elements);
154                   New_List := String_Element_Table.Last
155                     (Project_Tree.String_Elements);
156
157                   --  Value of attribute is new list
158
159                   User_Attr.Value.Values := New_List;
160                   Project_Tree.Variable_Elements.Table (User_Attr_Id) :=
161                     User_Attr;
162
163                   loop
164
165                      --  Get each element of configuration list
166
167                      Conf_Elem :=
168                        Project_Tree.String_Elements.Table (Conf_List);
169                      New_Elem := Conf_Elem;
170                      Conf_List := Conf_Elem.Next;
171
172                      if Conf_List = Nil_String then
173
174                         --  If it is the last element in the list, connect to
175                         --  first element of user list, and we are done.
176
177                         New_Elem.Next := User_List;
178                         Project_Tree.String_Elements.Table
179                           (New_List) := New_Elem;
180                         exit;
181
182                      else
183                         --  If it is not the last element in the list, add to
184                         --  new list.
185
186                         String_Element_Table.Increment_Last
187                           (Project_Tree.String_Elements);
188                         New_Elem.Next :=
189                           String_Element_Table.Last
190                             (Project_Tree.String_Elements);
191                         Project_Tree.String_Elements.Table
192                           (New_List) := New_Elem;
193                         New_List := New_Elem.Next;
194                      end if;
195                   end loop;
196                end;
197             end if;
198          end if;
199
200          Conf_Attr_Id := Conf_Attr.Next;
201          User_Attr_Id := User_Attr.Next;
202       end loop;
203
204       Conf_Array_Id := Conf_Decl.Arrays;
205       while Conf_Array_Id /= No_Array loop
206          Conf_Array := Project_Tree.Arrays.Table (Conf_Array_Id);
207
208          User_Array_Id := User_Decl.Arrays;
209          while User_Array_Id /= No_Array loop
210             User_Array := Project_Tree.Arrays.Table (User_Array_Id);
211             exit when User_Array.Name = Conf_Array.Name;
212             User_Array_Id := User_Array.Next;
213          end loop;
214
215          --  If this associative array does not exist in the user project file,
216          --  do a shallow copy of the full associative array.
217
218          if User_Array_Id = No_Array then
219             Array_Table.Increment_Last (Project_Tree.Arrays);
220             User_Array := Conf_Array;
221             User_Array.Next := User_Decl.Arrays;
222             User_Decl.Arrays := Array_Table.Last (Project_Tree.Arrays);
223             Project_Tree.Arrays.Table (User_Decl.Arrays) := User_Array;
224
225          else
226             --  Otherwise, check each array element
227
228             Conf_Array_Elem_Id := Conf_Array.Value;
229             while Conf_Array_Elem_Id /= No_Array_Element loop
230                Conf_Array_Elem :=
231                  Project_Tree.Array_Elements.Table (Conf_Array_Elem_Id);
232
233                User_Array_Elem_Id := User_Array.Value;
234                while User_Array_Elem_Id /= No_Array_Element loop
235                   User_Array_Elem :=
236                     Project_Tree.Array_Elements.Table (User_Array_Elem_Id);
237                   exit when User_Array_Elem.Index = Conf_Array_Elem.Index;
238                   User_Array_Elem_Id := User_Array_Elem.Next;
239                end loop;
240
241                --  If the array element does not exist in the user array,
242                --  insert a shallow copy of the conf array element in the
243                --  user array.
244
245                if User_Array_Elem_Id = No_Array_Element then
246                   Array_Element_Table.Increment_Last
247                     (Project_Tree.Array_Elements);
248                   User_Array_Elem := Conf_Array_Elem;
249                   User_Array_Elem.Next := User_Array.Value;
250                   User_Array.Value :=
251                     Array_Element_Table.Last (Project_Tree.Array_Elements);
252                   Project_Tree.Array_Elements.Table (User_Array.Value) :=
253                     User_Array_Elem;
254                   Project_Tree.Arrays.Table (User_Array_Id) := User_Array;
255
256                --  Otherwise, if the value is a string list, prepend the
257                --  user array element with the conf array element value.
258
259                elsif Conf_Array_Elem.Value.Kind = List then
260                   Conf_List := Conf_Array_Elem.Value.Values;
261
262                   if Conf_List /= Nil_String then
263                      declare
264                         Link     : constant String_List_Id :=
265                                      User_Array_Elem.Value.Values;
266                         Previous : String_List_Id := Nil_String;
267                         Next     : String_List_Id;
268
269                      begin
270                         loop
271                            Conf_List_Elem :=
272                              Project_Tree.String_Elements.Table
273                                (Conf_List);
274                            String_Element_Table.Increment_Last
275                              (Project_Tree.String_Elements);
276                            Next :=
277                              String_Element_Table.Last
278                                (Project_Tree.String_Elements);
279                            Project_Tree.String_Elements.Table (Next) :=
280                              Conf_List_Elem;
281
282                            if Previous = Nil_String then
283                               User_Array_Elem.Value.Values := Next;
284                               Project_Tree.Array_Elements.Table
285                                 (User_Array_Elem_Id) := User_Array_Elem;
286
287                            else
288                               Project_Tree.String_Elements.Table
289                                 (Previous).Next := Next;
290                            end if;
291
292                            Previous := Next;
293
294                            Conf_List := Conf_List_Elem.Next;
295
296                            if Conf_List = Nil_String then
297                               Project_Tree.String_Elements.Table
298                                 (Previous).Next := Link;
299                               exit;
300                            end if;
301                         end loop;
302                      end;
303                   end if;
304                end if;
305
306                Conf_Array_Elem_Id := Conf_Array_Elem.Next;
307             end loop;
308          end if;
309
310          Conf_Array_Id := Conf_Array.Next;
311       end loop;
312    end Add_Attributes;
313
314    ------------------------
315    -- Locate_Config_File --
316    ------------------------
317
318    function Locate_Config_File (Name : String) return String_Access is
319       Prefix_Path : constant String := Executable_Prefix_Path;
320    begin
321       if Prefix_Path'Length /= 0 then
322          return Locate_Regular_File
323            (Name,
324             "." & Path_Separator &
325             Prefix_Path & "share" & Directory_Separator & "gpr");
326       else
327          return Locate_Regular_File (Name, ".");
328       end if;
329    end Locate_Config_File;
330
331    ------------------
332    -- Check_Target --
333    ------------------
334
335    function Check_Target
336      (Config_File  : Project_Id;
337       Autoconf_Specified : Boolean;
338       Project_Tree : Prj.Project_Tree_Ref;
339       Target       : String := "") return Boolean
340    is
341       Variable : constant Variable_Value :=
342                    Value_Of
343                      (Name_Target, Config_File.Decl.Attributes, Project_Tree);
344       Tgt_Name : Name_Id := No_Name;
345       OK       : Boolean;
346
347    begin
348       if Variable /= Nil_Variable_Value and then not Variable.Default then
349          Tgt_Name := Variable.Value;
350       end if;
351
352       if Target = "" then
353          OK := not Autoconf_Specified or Tgt_Name = No_Name;
354       else
355          OK := Tgt_Name /= No_Name
356                  and then Target = Get_Name_String (Tgt_Name);
357       end if;
358
359       if not OK then
360          if Autoconf_Specified then
361             if Verbose_Mode then
362                Write_Line ("inconsistent targets, performing autoconf");
363             end if;
364
365             return False;
366
367          else
368             if Tgt_Name /= No_Name then
369                raise Invalid_Config
370                  with "invalid target name """
371                    & Get_Name_String (Tgt_Name) & """ in configuration";
372
373             else
374                raise Invalid_Config
375                  with "no target specified in configuration file";
376             end if;
377          end if;
378       end if;
379
380       return True;
381    end Check_Target;
382
383    --------------------------------------
384    -- Get_Or_Create_Configuration_File --
385    --------------------------------------
386
387    procedure Get_Or_Create_Configuration_File
388      (Project                    : Project_Id;
389       Project_Tree               : Project_Tree_Ref;
390       Project_Node_Tree          : Prj.Tree.Project_Node_Tree_Ref;
391       Allow_Automatic_Generation : Boolean;
392       Config_File_Name           : String := "";
393       Autoconf_Specified         : Boolean;
394       Target_Name                : String := "";
395       Normalized_Hostname        : String;
396       Packages_To_Check          : String_List_Access := null;
397       Config                     : out Prj.Project_Id;
398       Config_File_Path           : out String_Access;
399       Automatically_Generated    : out Boolean;
400       On_Load_Config             : Config_File_Hook := null)
401    is
402       function Default_File_Name return String;
403       --  Return the name of the default config file that should be tested
404
405       procedure Do_Autoconf;
406       --  Generate a new config file through gprconfig.
407       --  In case of error, this raises the Invalid_Config exception with an
408       --  appropriate message
409
410       function Get_Config_Switches return Argument_List_Access;
411       --  Return the --config switches to use for gprconfig
412
413       function Might_Have_Sources (Project : Project_Id) return Boolean;
414       --  True if the specified project might have sources (ie the user has not
415       --  explicitly specified it. We haven't checked the file system, nor do
416       --  we need to at this stage.
417
418       -----------------------
419       -- Default_File_Name --
420       -----------------------
421
422       function Default_File_Name return String is
423          Ada_RTS : constant String := Runtime_Name_For (Name_Ada);
424          Tmp     : String_Access;
425
426       begin
427          if Target_Name /= "" then
428             if Ada_RTS /= "" then
429                return Target_Name & '-' & Ada_RTS
430                  & Config_Project_File_Extension;
431             else
432                return Target_Name & Config_Project_File_Extension;
433             end if;
434
435          elsif Ada_RTS /= "" then
436             return Ada_RTS & Config_Project_File_Extension;
437
438          else
439             Tmp := Getenv (Config_Project_Env_Var);
440
441             declare
442                T : constant String := Tmp.all;
443             begin
444                Free (Tmp);
445
446                if T'Length = 0 then
447                   return Default_Name;
448                else
449                   return T;
450                end if;
451             end;
452          end if;
453       end Default_File_Name;
454
455       ------------------------
456       -- Might_Have_Sources --
457       ------------------------
458
459       function Might_Have_Sources (Project : Project_Id) return Boolean is
460          Variable : Variable_Value;
461
462       begin
463          Variable :=
464            Value_Of
465              (Name_Source_Dirs,
466               Project.Decl.Attributes,
467               Project_Tree);
468
469          if Variable = Nil_Variable_Value
470            or else Variable.Default
471            or else Variable.Values /= Nil_String
472          then
473             Variable :=
474               Value_Of
475                 (Name_Source_Files,
476                  Project.Decl.Attributes,
477                  Project_Tree);
478             return Variable = Nil_Variable_Value
479               or else Variable.Default
480               or else Variable.Values /= Nil_String;
481
482          else
483             return False;
484          end if;
485       end Might_Have_Sources;
486
487       -------------------------
488       -- Get_Config_Switches --
489       -------------------------
490
491       function Get_Config_Switches return Argument_List_Access is
492          package Language_Htable is new GNAT.HTable.Simple_HTable
493            (Header_Num => Prj.Header_Num,
494             Element    => Name_Id,
495             No_Element => No_Name,
496             Key        => Name_Id,
497             Hash       => Prj.Hash,
498             Equal      => "=");
499          --  Hash table to keep the languages used in the project tree
500
501          IDE : constant Package_Id :=
502                  Value_Of
503                    (Name_Ide,
504                     Project.Decl.Packages,
505                     Project_Tree);
506
507          Prj_Iter : Project_List;
508          List     : String_List_Id;
509          Elem     : String_Element;
510          Lang     : Name_Id;
511          Variable : Variable_Value;
512          Name     : Name_Id;
513          Count    : Natural;
514          Result   : Argument_List_Access;
515
516       begin
517          Prj_Iter := Project_Tree.Projects;
518          while Prj_Iter /= null loop
519             if Might_Have_Sources (Prj_Iter.Project) then
520                Variable :=
521                  Value_Of
522                    (Name_Languages,
523                     Prj_Iter.Project.Decl.Attributes,
524                     Project_Tree);
525
526                if Variable = Nil_Variable_Value
527                  or else Variable.Default
528                then
529                   --  Languages is not declared. If it is not an extending
530                   --  project, check for Default_Language
531
532                   if Prj_Iter.Project.Extends = No_Project then
533                      Variable :=
534                        Value_Of
535                          (Name_Default_Language,
536                           Prj_Iter.Project.Decl.Attributes,
537                           Project_Tree);
538
539                      if Variable /= Nil_Variable_Value
540                        and then not Variable.Default
541                      then
542                         Get_Name_String (Variable.Value);
543                         To_Lower (Name_Buffer (1 .. Name_Len));
544                         Lang := Name_Find;
545                         Language_Htable.Set (Lang, Lang);
546
547                      else
548                         --  If no language is declared, default to Ada
549
550                         Language_Htable.Set (Name_Ada, Name_Ada);
551                      end if;
552                   end if;
553
554                elsif Variable.Values /= Nil_String then
555
556                   --  Attribute Languages is declared with a non empty
557                   --  list: put all the languages in Language_HTable.
558
559                   List := Variable.Values;
560                   while List /= Nil_String loop
561                      Elem := Project_Tree.String_Elements.Table (List);
562
563                      Get_Name_String (Elem.Value);
564                      To_Lower (Name_Buffer (1 .. Name_Len));
565                      Lang := Name_Find;
566                      Language_Htable.Set (Lang, Lang);
567
568                      List := Elem.Next;
569                   end loop;
570                end if;
571             end if;
572
573             Prj_Iter := Prj_Iter.Next;
574          end loop;
575
576          Name  := Language_Htable.Get_First;
577          Count := 0;
578          while Name /= No_Name loop
579             Count := Count + 1;
580             Name := Language_Htable.Get_Next;
581          end loop;
582
583          Result := new String_List (1 .. Count);
584
585          Count := 1;
586          Name  := Language_Htable.Get_First;
587          while Name /= No_Name loop
588             --  Check if IDE'Compiler_Command is declared for the language.
589             --  If it is, use its value to invoke gprconfig.
590
591             Variable :=
592               Value_Of
593                 (Name,
594                  Attribute_Or_Array_Name => Name_Compiler_Command,
595                  In_Package              => IDE,
596                  In_Tree                 => Project_Tree,
597                  Force_Lower_Case_Index  => True);
598
599             declare
600                Config_Command : constant String :=
601                  "--config=" & Get_Name_String (Name);
602
603                Runtime_Name   : constant String :=
604                  Runtime_Name_For (Name);
605
606             begin
607                if Variable = Nil_Variable_Value
608                  or else Length_Of_Name (Variable.Value) = 0
609                then
610                   Result (Count) :=
611                     new String'(Config_Command & ",," & Runtime_Name);
612
613                else
614                   declare
615                      Compiler_Command : constant String :=
616                        Get_Name_String (Variable.Value);
617
618                   begin
619                      if Is_Absolute_Path (Compiler_Command) then
620                         Result (Count) :=
621                           new String'
622                             (Config_Command & ",," & Runtime_Name & "," &
623                              Containing_Directory (Compiler_Command) & "," &
624                              Simple_Name (Compiler_Command));
625                      else
626                         Result (Count) :=
627                           new String'
628                             (Config_Command & ",," & Runtime_Name & ",," &
629                              Compiler_Command);
630                      end if;
631                   end;
632                end if;
633             end;
634
635             Count := Count + 1;
636             Name  := Language_Htable.Get_Next;
637          end loop;
638
639          return Result;
640       end Get_Config_Switches;
641
642       -----------------
643       -- Do_Autoconf --
644       -----------------
645
646       procedure Do_Autoconf is
647          Obj_Dir : constant Variable_Value :=
648                      Value_Of
649                        (Name_Object_Dir,
650                         Project.Decl.Attributes,
651                         Project_Tree);
652
653          Gprconfig_Path  : String_Access;
654          Success         : Boolean;
655
656       begin
657          Gprconfig_Path := Locate_Exec_On_Path (Gprconfig_Name);
658
659          if Gprconfig_Path = null then
660             raise Invalid_Config
661               with "could not locate gprconfig for auto-configuration";
662          end if;
663
664          --  First, find the object directory of the user's project
665
666          if Obj_Dir = Nil_Variable_Value or else Obj_Dir.Default then
667             Get_Name_String (Project.Directory.Name);
668
669          else
670             if Is_Absolute_Path (Get_Name_String (Obj_Dir.Value)) then
671                Get_Name_String (Obj_Dir.Value);
672
673             else
674                Name_Len := 0;
675                Add_Str_To_Name_Buffer
676                  (Get_Name_String (Project.Directory.Name));
677                Add_Char_To_Name_Buffer (Directory_Separator);
678                Add_Str_To_Name_Buffer (Get_Name_String (Obj_Dir.Value));
679             end if;
680          end if;
681
682          if Subdirs /= null then
683             Add_Char_To_Name_Buffer (Directory_Separator);
684             Add_Str_To_Name_Buffer (Subdirs.all);
685          end if;
686
687          for J in 1 .. Name_Len loop
688             if Name_Buffer (J) = '/' then
689                Name_Buffer (J) := Directory_Separator;
690             end if;
691          end loop;
692
693          declare
694             Obj_Dir  : constant String := Name_Buffer (1 .. Name_Len);
695             Switches : Argument_List_Access := Get_Config_Switches;
696             Args     : Argument_List (1 .. 5);
697             Arg_Last : Positive;
698
699          begin
700             --  Check if the object directory exists. If Setup_Projects is True
701             --  (-p) and directory does not exist, attempt to create it.
702             --  Otherwise, if directory does not exist, fail without calling
703             --  gprconfig.
704
705             if not Is_Directory (Obj_Dir)
706               and then (Setup_Projects or Subdirs /= null)
707             then
708                begin
709                   Create_Path (Obj_Dir);
710
711                   if not Quiet_Output then
712                      Write_Str ("object directory """);
713                      Write_Str (Obj_Dir);
714                      Write_Line (""" created");
715                   end if;
716
717                exception
718                   when others =>
719                      raise Invalid_Config
720                        with "could not create object directory " & Obj_Dir;
721                end;
722             end if;
723
724             if not Is_Directory (Obj_Dir) then
725                raise Invalid_Config
726                  with "object directory " & Obj_Dir & " does not exist";
727             end if;
728
729             --  Invoke gprconfig
730
731             Args (1) := new String'("--batch");
732             Args (2) := new String'("-o");
733
734             --  If no config file was specified, set the auto.cgpr one
735
736             if Config_File_Name = "" then
737                Args (3) := new String'
738                  (Obj_Dir & Directory_Separator & Auto_Cgpr);
739             else
740                Args (3) := new String'(Config_File_Name);
741             end if;
742
743             if Normalized_Hostname = "" then
744                Arg_Last := 3;
745             else
746                if Target_Name = "" then
747                   Args (4) := new String'("--target=" & Normalized_Hostname);
748                else
749                   Args (4) := new String'("--target=" & Target_Name);
750                end if;
751
752                Arg_Last := 4;
753             end if;
754
755             if not Verbose_Mode then
756                Arg_Last := Arg_Last + 1;
757                Args (Arg_Last) := new String'("-q");
758             end if;
759
760             if Verbose_Mode then
761                Write_Str (Gprconfig_Name);
762
763                for J in 1 .. Arg_Last loop
764                   Write_Char (' ');
765                   Write_Str (Args (J).all);
766                end loop;
767
768                for J in Switches'Range loop
769                   Write_Char (' ');
770                   Write_Str (Switches (J).all);
771                end loop;
772
773                Write_Eol;
774
775             elsif not Quiet_Output then
776                Write_Str ("creating ");
777                Write_Str (Simple_Name (Args (3).all));
778                Write_Eol;
779             end if;
780
781             Spawn (Gprconfig_Path.all, Args (1 .. Arg_Last) & Switches.all,
782                    Success);
783
784             Free (Switches);
785
786             Config_File_Path := Locate_Config_File (Args (3).all);
787
788             if Config_File_Path = null then
789                raise Invalid_Config
790                  with "could not create " & Args (3).all;
791             end if;
792
793             for F in Args'Range loop
794                Free (Args (F));
795             end loop;
796          end;
797       end Do_Autoconf;
798
799       Success             : Boolean;
800       Config_Project_Node : Project_Node_Id := Empty_Node;
801
802    begin
803       Free (Config_File_Path);
804
805       if Config_File_Name /= "" then
806          Config_File_Path := Locate_Config_File (Config_File_Name);
807       else
808          Config_File_Path := Locate_Config_File (Default_File_Name);
809       end if;
810
811       if Config_File_Path = null then
812          if (not Allow_Automatic_Generation) and then
813             Config_File_Name /= ""
814          then
815             raise Invalid_Config
816               with "could not locate main configuration project "
817                 & Config_File_Name;
818          end if;
819       end if;
820
821       Automatically_Generated :=
822         Allow_Automatic_Generation and then Config_File_Path = null;
823
824       <<Process_Config_File>>
825
826       if Automatically_Generated then
827          --  This might raise an Invalid_Config exception
828          Do_Autoconf;
829       end if;
830
831       --  Parse the configuration file
832
833       if Verbose_Mode then
834          Write_Str  ("Checking configuration ");
835          Write_Line (Config_File_Path.all);
836       end if;
837
838       Prj.Part.Parse
839         (In_Tree                => Project_Node_Tree,
840          Project                => Config_Project_Node,
841          Project_File_Name      => Config_File_Path.all,
842          Always_Errout_Finalize => False,
843          Packages_To_Check      => Packages_To_Check,
844          Current_Directory      => Current_Directory,
845          Is_Config_File         => True);
846
847       if Config_Project_Node /= Empty_Node then
848
849          if On_Load_Config /= null then
850             On_Load_Config
851               (Config_File       => Config_Project_Node,
852                Project_Node_Tree => Project_Node_Tree);
853          end if;
854
855          Prj.Proc.Process_Project_Tree_Phase_1
856            (In_Tree                => Project_Tree,
857             Project                => Config,
858             Success                => Success,
859             From_Project_Node      => Config_Project_Node,
860             From_Project_Node_Tree => Project_Node_Tree,
861             Report_Error           => null,
862             Reset_Tree             => False);
863       end if;
864
865       if Config_Project_Node = Empty_Node
866         or else Config = No_Project
867       then
868          raise Invalid_Config
869            with "processing of configuration project """
870              & Config_File_Path.all & """ failed";
871       end if;
872
873       --  Check that the target of the configuration file is the one the user
874       --  specified on the command line. We do not need to check that when in
875       --  auto-conf mode, since the appropriate target was passed to gprconfig.
876
877       if not Automatically_Generated
878         and not Check_Target
879           (Config, Autoconf_Specified, Project_Tree, Target_Name)
880       then
881          Automatically_Generated := True;
882          goto Process_Config_File;
883       end if;
884    end Get_Or_Create_Configuration_File;
885
886    --------------------------------------
887    -- Process_Project_And_Apply_Config --
888    --------------------------------------
889
890    procedure Process_Project_And_Apply_Config
891      (Main_Project               : out Prj.Project_Id;
892       User_Project_Node          : Prj.Tree.Project_Node_Id;
893       Config_File_Name           : String := "";
894       Autoconf_Specified         : Boolean;
895       Project_Tree               : Prj.Project_Tree_Ref;
896       Project_Node_Tree          : Prj.Tree.Project_Node_Tree_Ref;
897       Packages_To_Check          : String_List_Access;
898       Allow_Automatic_Generation : Boolean := True;
899       Automatically_Generated    : out Boolean;
900       Config_File_Path           : out String_Access;
901       Target_Name                : String := "";
902       Normalized_Hostname        : String;
903       Report_Error               : Put_Line_Access := null;
904       On_Load_Config             : Config_File_Hook := null)
905    is
906       Main_Config_Project : Project_Id;
907       Success : Boolean;
908
909    begin
910       Main_Project := No_Project;
911       Automatically_Generated := False;
912
913       Process_Project_Tree_Phase_1
914         (In_Tree                => Project_Tree,
915          Project                => Main_Project,
916          Success                => Success,
917          From_Project_Node      => User_Project_Node,
918          From_Project_Node_Tree => Project_Node_Tree,
919          Report_Error           => Report_Error);
920
921       if not Success then
922          Main_Project := No_Project;
923          return;
924       end if;
925
926       --  Find configuration file
927
928       Get_Or_Create_Configuration_File
929         (Config                     => Main_Config_Project,
930          Project                    => Main_Project,
931          Project_Tree               => Project_Tree,
932          Project_Node_Tree          => Project_Node_Tree,
933          Allow_Automatic_Generation => Allow_Automatic_Generation,
934          Config_File_Name           => Config_File_Name,
935          Autoconf_Specified         => Autoconf_Specified,
936          Target_Name                => Target_Name,
937          Normalized_Hostname        => Normalized_Hostname,
938          Packages_To_Check          => Packages_To_Check,
939          Config_File_Path           => Config_File_Path,
940          Automatically_Generated    => Automatically_Generated,
941          On_Load_Config             => On_Load_Config);
942
943       Apply_Config_File (Main_Config_Project, Project_Tree);
944
945       --  Finish processing the user's project
946
947       Sinput.P.Reset_First;
948
949       Prj.Proc.Process_Project_Tree_Phase_2
950         (In_Tree                => Project_Tree,
951          Project                => Main_Project,
952          Success                => Success,
953          From_Project_Node      => User_Project_Node,
954          From_Project_Node_Tree => Project_Node_Tree,
955          Report_Error           => Report_Error,
956          Current_Dir            => Current_Directory,
957          When_No_Sources        => Warning,
958          Is_Config_File         => False);
959
960       if not Success then
961          Main_Project := No_Project;
962       end if;
963    end Process_Project_And_Apply_Config;
964
965    ------------------------------------
966    -- Parse_Project_And_Apply_Config --
967    ------------------------------------
968
969    procedure Parse_Project_And_Apply_Config
970      (Main_Project               : out Prj.Project_Id;
971       User_Project_Node          : out Prj.Tree.Project_Node_Id;
972       Config_File_Name           : String := "";
973       Autoconf_Specified         : Boolean;
974       Project_File_Name          : String;
975       Project_Tree               : Prj.Project_Tree_Ref;
976       Project_Node_Tree          : Prj.Tree.Project_Node_Tree_Ref;
977       Packages_To_Check          : String_List_Access;
978       Allow_Automatic_Generation : Boolean := True;
979       Automatically_Generated    : out Boolean;
980       Config_File_Path           : out String_Access;
981       Target_Name                : String := "";
982       Normalized_Hostname        : String;
983       Report_Error               : Put_Line_Access := null;
984       On_Load_Config             : Config_File_Hook := null)
985    is
986    begin
987       --  Parse the user project tree
988
989       Prj.Tree.Initialize (Project_Node_Tree);
990       Prj.Initialize (Project_Tree);
991
992       Main_Project      := No_Project;
993       Automatically_Generated := False;
994
995       Prj.Part.Parse
996         (In_Tree                => Project_Node_Tree,
997          Project                => User_Project_Node,
998          Project_File_Name      => Project_File_Name,
999          Always_Errout_Finalize => False,
1000          Packages_To_Check      => Packages_To_Check,
1001          Current_Directory      => Current_Directory,
1002          Is_Config_File         => False);
1003
1004       if User_Project_Node = Empty_Node then
1005          User_Project_Node := Empty_Node;
1006          return;
1007       end if;
1008
1009       Process_Project_And_Apply_Config
1010         (Main_Project               => Main_Project,
1011          User_Project_Node          => User_Project_Node,
1012          Config_File_Name           => Config_File_Name,
1013          Autoconf_Specified         => Autoconf_Specified,
1014          Project_Tree               => Project_Tree,
1015          Project_Node_Tree          => Project_Node_Tree,
1016          Packages_To_Check          => Packages_To_Check,
1017          Allow_Automatic_Generation => Allow_Automatic_Generation,
1018          Automatically_Generated    => Automatically_Generated,
1019          Config_File_Path           => Config_File_Path,
1020          Target_Name                => Target_Name,
1021          Normalized_Hostname        => Normalized_Hostname,
1022          Report_Error               => Report_Error,
1023          On_Load_Config             => On_Load_Config);
1024    end Parse_Project_And_Apply_Config;
1025
1026    -----------------------
1027    -- Apply_Config_File --
1028    -----------------------
1029
1030    procedure Apply_Config_File
1031      (Config_File  : Prj.Project_Id;
1032       Project_Tree : Prj.Project_Tree_Ref)
1033    is
1034       Conf_Decl    : constant Declarations := Config_File.Decl;
1035       Conf_Pack_Id : Package_Id;
1036       Conf_Pack    : Package_Element;
1037
1038       User_Decl    : Declarations;
1039       User_Pack_Id : Package_Id;
1040       User_Pack    : Package_Element;
1041       Proj         : Project_List;
1042
1043    begin
1044       Proj := Project_Tree.Projects;
1045       while Proj /= null loop
1046          if Proj.Project /= Config_File then
1047             User_Decl := Proj.Project.Decl;
1048             Add_Attributes
1049               (Project_Tree => Project_Tree,
1050                Conf_Decl    => Conf_Decl,
1051                User_Decl    => User_Decl);
1052
1053             Conf_Pack_Id := Conf_Decl.Packages;
1054             while Conf_Pack_Id /= No_Package loop
1055                Conf_Pack := Project_Tree.Packages.Table (Conf_Pack_Id);
1056
1057                User_Pack_Id := User_Decl.Packages;
1058                while User_Pack_Id /= No_Package loop
1059                   User_Pack := Project_Tree.Packages.Table (User_Pack_Id);
1060                   exit when User_Pack.Name = Conf_Pack.Name;
1061                   User_Pack_Id := User_Pack.Next;
1062                end loop;
1063
1064                if User_Pack_Id = No_Package then
1065                   Package_Table.Increment_Last (Project_Tree.Packages);
1066                   User_Pack := Conf_Pack;
1067                   User_Pack.Next := User_Decl.Packages;
1068                   User_Decl.Packages :=
1069                     Package_Table.Last (Project_Tree.Packages);
1070                   Project_Tree.Packages.Table (User_Decl.Packages) :=
1071                     User_Pack;
1072
1073                else
1074                   Add_Attributes
1075                     (Project_Tree => Project_Tree,
1076                      Conf_Decl    => Conf_Pack.Decl,
1077                      User_Decl    => Project_Tree.Packages.Table
1078                        (User_Pack_Id).Decl);
1079                end if;
1080
1081                Conf_Pack_Id := Conf_Pack.Next;
1082             end loop;
1083
1084             Proj.Project.Decl := User_Decl;
1085          end if;
1086
1087          Proj := Proj.Next;
1088       end loop;
1089    end Apply_Config_File;
1090
1091    ---------------------
1092    -- Set_Runtime_For --
1093    ---------------------
1094
1095    procedure Set_Runtime_For (Language : Name_Id; RTS_Name : String) is
1096    begin
1097       Name_Len := RTS_Name'Length;
1098       Name_Buffer (1 .. Name_Len) := RTS_Name;
1099       RTS_Languages.Set (Language, Name_Find);
1100    end Set_Runtime_For;
1101
1102    ----------------------
1103    -- Runtime_Name_For --
1104    ----------------------
1105
1106    function Runtime_Name_For (Language : Name_Id) return String is
1107    begin
1108       if RTS_Languages.Get (Language) /= No_Name then
1109          return Get_Name_String (RTS_Languages.Get (Language));
1110       else
1111          return "";
1112       end if;
1113    end Runtime_Name_For;
1114
1115 end Prj.Conf;