OSDN Git Service

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