OSDN Git Service

2009-11-30 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
701             Obj_Dir_Exists : Boolean := True;
702
703          begin
704             --  Check if the object directory exists. If Setup_Projects is True
705             --  (-p) and directory does not exist, attempt to create it.
706             --  Otherwise, if directory does not exist, fail without calling
707             --  gprconfig.
708
709             if not Is_Directory (Obj_Dir)
710               and then (Setup_Projects or else Subdirs /= null)
711             then
712                begin
713                   Create_Path (Obj_Dir);
714
715                   if not Quiet_Output then
716                      Write_Str ("object directory """);
717                      Write_Str (Obj_Dir);
718                      Write_Line (""" created");
719                   end if;
720
721                exception
722                   when others =>
723                      raise Invalid_Config
724                        with "could not create object directory " & Obj_Dir;
725                end;
726             end if;
727
728             if not Is_Directory (Obj_Dir) then
729                case Flags.Require_Obj_Dirs is
730                   when Error =>
731                      raise Invalid_Config
732                        with "object directory " & Obj_Dir & " does not exist";
733                   when Warning =>
734                      Prj.Err.Error_Msg
735                        (Flags,
736                         "?object directory " & Obj_Dir & " does not exist");
737                      Obj_Dir_Exists := False;
738                   when Silent =>
739                      null;
740                end case;
741             end if;
742
743             --  Invoke gprconfig
744
745             Args (1) := new String'("--batch");
746             Args (2) := new String'("-o");
747
748             --  If no config file was specified, set the auto.cgpr one
749
750             if Config_File_Name = "" then
751                if Obj_Dir_Exists then
752                   Args (3) :=
753                     new String'(Obj_Dir & Directory_Separator & Auto_Cgpr);
754
755                else
756                   declare
757                      Path_FD   : File_Descriptor;
758                      Path_Name : Path_Name_Type;
759
760                   begin
761                      Prj.Env.Create_Temp_File
762                        (In_Tree   => Project_Tree,
763                         Path_FD   => Path_FD,
764                         Path_Name => Path_Name,
765                         File_Use  => "configuration file");
766
767                      if Path_FD /= Invalid_FD then
768                         Args (3) := new String'(Get_Name_String (Path_Name));
769                         GNAT.OS_Lib.Close (Path_FD);
770
771                      else
772                         --  We'll have an error message later on
773
774                         Args (3) :=
775                           new String'
776                             (Obj_Dir & Directory_Separator & Auto_Cgpr);
777                      end if;
778                   end;
779                end if;
780             else
781                Args (3) := new String'(Config_File_Name);
782             end if;
783
784             if Normalized_Hostname = "" then
785                Arg_Last := 3;
786             else
787                if Target_Name = "" then
788                   Args (4) := new String'("--target=" & Normalized_Hostname);
789                else
790                   Args (4) := new String'("--target=" & Target_Name);
791                end if;
792
793                Arg_Last := 4;
794             end if;
795
796             if not Verbose_Mode then
797                Arg_Last := Arg_Last + 1;
798                Args (Arg_Last) := new String'("-q");
799             end if;
800
801             if Verbose_Mode then
802                Write_Str (Gprconfig_Name);
803
804                for J in 1 .. Arg_Last loop
805                   Write_Char (' ');
806                   Write_Str (Args (J).all);
807                end loop;
808
809                for J in Switches'Range loop
810                   Write_Char (' ');
811                   Write_Str (Switches (J).all);
812                end loop;
813
814                Write_Eol;
815
816             elsif not Quiet_Output then
817                --  Display no message if we are creating auto.cgpr, unless in
818                --  verbose mode
819
820                if Config_File_Name /= ""
821                  or else Verbose_Mode
822                then
823                   Write_Str ("creating ");
824                   Write_Str (Simple_Name (Args (3).all));
825                   Write_Eol;
826                end if;
827             end if;
828
829             Spawn (Gprconfig_Path.all, Args (1 .. Arg_Last) & Switches.all,
830                    Success);
831
832             Free (Switches);
833
834             Config_File_Path := Locate_Config_File (Args (3).all);
835
836             if Config_File_Path = null then
837                raise Invalid_Config
838                  with "could not create " & Args (3).all;
839             end if;
840
841             for F in Args'Range loop
842                Free (Args (F));
843             end loop;
844          end;
845       end Do_Autoconf;
846
847       Success             : Boolean;
848       Config_Project_Node : Project_Node_Id := Empty_Node;
849
850    begin
851       Free (Config_File_Path);
852       Config := No_Project;
853
854       if Config_File_Name /= "" then
855          Config_File_Path := Locate_Config_File (Config_File_Name);
856       else
857          Config_File_Path := Locate_Config_File (Default_File_Name);
858       end if;
859
860       if Config_File_Path = null then
861          if (not Allow_Automatic_Generation) and then
862             Config_File_Name /= ""
863          then
864             raise Invalid_Config
865               with "could not locate main configuration project "
866                 & Config_File_Name;
867          end if;
868       end if;
869
870       Automatically_Generated :=
871         Allow_Automatic_Generation and then Config_File_Path = null;
872
873       <<Process_Config_File>>
874
875       if Automatically_Generated then
876          --  This might raise an Invalid_Config exception
877          Do_Autoconf;
878       end if;
879
880       --  Parse the configuration file
881
882       if Verbose_Mode and then Config_File_Path /= null then
883          Write_Str  ("Checking configuration ");
884          Write_Line (Config_File_Path.all);
885       end if;
886
887       if Config_File_Path /= null then
888          Prj.Part.Parse
889            (In_Tree                => Project_Node_Tree,
890             Project                => Config_Project_Node,
891             Project_File_Name      => Config_File_Path.all,
892             Always_Errout_Finalize => False,
893             Packages_To_Check      => Packages_To_Check,
894             Current_Directory      => Current_Directory,
895             Is_Config_File         => True,
896             Flags                  => Flags);
897       else
898          --  Maybe the user will want to create his own configuration file
899          Config_Project_Node := Empty_Node;
900       end if;
901
902       if On_Load_Config /= null then
903          On_Load_Config
904            (Config_File       => Config_Project_Node,
905             Project_Node_Tree => Project_Node_Tree);
906       end if;
907
908       if Config_Project_Node /= Empty_Node then
909          Prj.Proc.Process_Project_Tree_Phase_1
910            (In_Tree                => Project_Tree,
911             Project                => Config,
912             Success                => Success,
913             From_Project_Node      => Config_Project_Node,
914             From_Project_Node_Tree => Project_Node_Tree,
915             Flags                  => Flags,
916             Reset_Tree             => False);
917       end if;
918
919       if Config_Project_Node = Empty_Node
920         or else Config = No_Project
921       then
922          raise Invalid_Config
923            with "processing of configuration project """
924              & Config_File_Path.all & """ failed";
925       end if;
926
927       --  Check that the target of the configuration file is the one the user
928       --  specified on the command line. We do not need to check that when in
929       --  auto-conf mode, since the appropriate target was passed to gprconfig.
930
931       if not Automatically_Generated
932         and then not
933           Check_Target (Config, Autoconf_Specified, Project_Tree, Target_Name)
934       then
935          Automatically_Generated := True;
936          goto Process_Config_File;
937       end if;
938    end Get_Or_Create_Configuration_File;
939
940    --------------------------------------
941    -- Process_Project_And_Apply_Config --
942    --------------------------------------
943
944    procedure Process_Project_And_Apply_Config
945      (Main_Project               : out Prj.Project_Id;
946       User_Project_Node          : Prj.Tree.Project_Node_Id;
947       Config_File_Name           : String := "";
948       Autoconf_Specified         : Boolean;
949       Project_Tree               : Prj.Project_Tree_Ref;
950       Project_Node_Tree          : Prj.Tree.Project_Node_Tree_Ref;
951       Packages_To_Check          : String_List_Access;
952       Allow_Automatic_Generation : Boolean := True;
953       Automatically_Generated    : out Boolean;
954       Config_File_Path           : out String_Access;
955       Target_Name                : String := "";
956       Normalized_Hostname        : String;
957       Flags                      : Processing_Flags;
958       On_Load_Config             : Config_File_Hook := null;
959       Reset_Tree                 : Boolean := True)
960    is
961       Main_Config_Project : Project_Id;
962       Success : Boolean;
963
964    begin
965       Main_Project := No_Project;
966       Automatically_Generated := False;
967
968       Process_Project_Tree_Phase_1
969         (In_Tree                => Project_Tree,
970          Project                => Main_Project,
971          Success                => Success,
972          From_Project_Node      => User_Project_Node,
973          From_Project_Node_Tree => Project_Node_Tree,
974          Flags                  => Flags,
975          Reset_Tree             => Reset_Tree);
976
977       if not Success then
978          Main_Project := No_Project;
979          return;
980       end if;
981
982       --  Find configuration file
983
984       Get_Or_Create_Configuration_File
985         (Config                     => Main_Config_Project,
986          Project                    => Main_Project,
987          Project_Tree               => Project_Tree,
988          Project_Node_Tree          => Project_Node_Tree,
989          Allow_Automatic_Generation => Allow_Automatic_Generation,
990          Config_File_Name           => Config_File_Name,
991          Autoconf_Specified         => Autoconf_Specified,
992          Target_Name                => Target_Name,
993          Normalized_Hostname        => Normalized_Hostname,
994          Packages_To_Check          => Packages_To_Check,
995          Config_File_Path           => Config_File_Path,
996          Automatically_Generated    => Automatically_Generated,
997          Flags                      => Flags,
998          On_Load_Config             => On_Load_Config);
999
1000       Apply_Config_File (Main_Config_Project, Project_Tree);
1001
1002       --  Finish processing the user's project
1003
1004       Prj.Proc.Process_Project_Tree_Phase_2
1005         (In_Tree                    => Project_Tree,
1006          Project                    => Main_Project,
1007          Success                    => Success,
1008          From_Project_Node          => User_Project_Node,
1009          From_Project_Node_Tree     => Project_Node_Tree,
1010          Flags                      => Flags);
1011
1012       if not Success then
1013          Main_Project := No_Project;
1014       end if;
1015    end Process_Project_And_Apply_Config;
1016
1017    ------------------------------------
1018    -- Parse_Project_And_Apply_Config --
1019    ------------------------------------
1020
1021    procedure Parse_Project_And_Apply_Config
1022      (Main_Project               : out Prj.Project_Id;
1023       User_Project_Node          : out Prj.Tree.Project_Node_Id;
1024       Config_File_Name           : String := "";
1025       Autoconf_Specified         : Boolean;
1026       Project_File_Name          : String;
1027       Project_Tree               : Prj.Project_Tree_Ref;
1028       Project_Node_Tree          : Prj.Tree.Project_Node_Tree_Ref;
1029       Packages_To_Check          : String_List_Access;
1030       Allow_Automatic_Generation : Boolean := True;
1031       Automatically_Generated    : out Boolean;
1032       Config_File_Path           : out String_Access;
1033       Target_Name                : String := "";
1034       Normalized_Hostname        : String;
1035       Flags                      : Processing_Flags;
1036       On_Load_Config             : Config_File_Hook := null)
1037    is
1038    begin
1039       --  Parse the user project tree
1040
1041       Prj.Initialize (Project_Tree);
1042
1043       Main_Project      := No_Project;
1044       Automatically_Generated := False;
1045
1046       Prj.Part.Parse
1047         (In_Tree                => Project_Node_Tree,
1048          Project                => User_Project_Node,
1049          Project_File_Name      => Project_File_Name,
1050          Always_Errout_Finalize => False,
1051          Packages_To_Check      => Packages_To_Check,
1052          Current_Directory      => Current_Directory,
1053          Is_Config_File         => False,
1054          Flags                  => Flags);
1055
1056       if User_Project_Node = Empty_Node then
1057          User_Project_Node := Empty_Node;
1058          return;
1059       end if;
1060
1061       Process_Project_And_Apply_Config
1062         (Main_Project               => Main_Project,
1063          User_Project_Node          => User_Project_Node,
1064          Config_File_Name           => Config_File_Name,
1065          Autoconf_Specified         => Autoconf_Specified,
1066          Project_Tree               => Project_Tree,
1067          Project_Node_Tree          => Project_Node_Tree,
1068          Packages_To_Check          => Packages_To_Check,
1069          Allow_Automatic_Generation => Allow_Automatic_Generation,
1070          Automatically_Generated    => Automatically_Generated,
1071          Config_File_Path           => Config_File_Path,
1072          Target_Name                => Target_Name,
1073          Normalized_Hostname        => Normalized_Hostname,
1074          Flags                      => Flags,
1075          On_Load_Config             => On_Load_Config);
1076    end Parse_Project_And_Apply_Config;
1077
1078    -----------------------
1079    -- Apply_Config_File --
1080    -----------------------
1081
1082    procedure Apply_Config_File
1083      (Config_File  : Prj.Project_Id;
1084       Project_Tree : Prj.Project_Tree_Ref)
1085    is
1086       Conf_Decl    : constant Declarations := Config_File.Decl;
1087       Conf_Pack_Id : Package_Id;
1088       Conf_Pack    : Package_Element;
1089
1090       User_Decl    : Declarations;
1091       User_Pack_Id : Package_Id;
1092       User_Pack    : Package_Element;
1093       Proj         : Project_List;
1094
1095    begin
1096       Proj := Project_Tree.Projects;
1097       while Proj /= null loop
1098          if Proj.Project /= Config_File then
1099             User_Decl := Proj.Project.Decl;
1100             Add_Attributes
1101               (Project_Tree => Project_Tree,
1102                Conf_Decl    => Conf_Decl,
1103                User_Decl    => User_Decl);
1104
1105             Conf_Pack_Id := Conf_Decl.Packages;
1106             while Conf_Pack_Id /= No_Package loop
1107                Conf_Pack := Project_Tree.Packages.Table (Conf_Pack_Id);
1108
1109                User_Pack_Id := User_Decl.Packages;
1110                while User_Pack_Id /= No_Package loop
1111                   User_Pack := Project_Tree.Packages.Table (User_Pack_Id);
1112                   exit when User_Pack.Name = Conf_Pack.Name;
1113                   User_Pack_Id := User_Pack.Next;
1114                end loop;
1115
1116                if User_Pack_Id = No_Package then
1117                   Package_Table.Increment_Last (Project_Tree.Packages);
1118                   User_Pack := Conf_Pack;
1119                   User_Pack.Next := User_Decl.Packages;
1120                   User_Decl.Packages :=
1121                     Package_Table.Last (Project_Tree.Packages);
1122                   Project_Tree.Packages.Table (User_Decl.Packages) :=
1123                     User_Pack;
1124
1125                else
1126                   Add_Attributes
1127                     (Project_Tree => Project_Tree,
1128                      Conf_Decl    => Conf_Pack.Decl,
1129                      User_Decl    => Project_Tree.Packages.Table
1130                        (User_Pack_Id).Decl);
1131                end if;
1132
1133                Conf_Pack_Id := Conf_Pack.Next;
1134             end loop;
1135
1136             Proj.Project.Decl := User_Decl;
1137          end if;
1138
1139          Proj := Proj.Next;
1140       end loop;
1141    end Apply_Config_File;
1142
1143    ---------------------
1144    -- Set_Runtime_For --
1145    ---------------------
1146
1147    procedure Set_Runtime_For (Language : Name_Id; RTS_Name : String) is
1148    begin
1149       Name_Len := RTS_Name'Length;
1150       Name_Buffer (1 .. Name_Len) := RTS_Name;
1151       RTS_Languages.Set (Language, Name_Find);
1152    end Set_Runtime_For;
1153
1154    ----------------------
1155    -- Runtime_Name_For --
1156    ----------------------
1157
1158    function Runtime_Name_For (Language : Name_Id) return String is
1159    begin
1160       if RTS_Languages.Get (Language) /= No_Name then
1161          return Get_Name_String (RTS_Languages.Get (Language));
1162       else
1163          return "";
1164       end if;
1165    end Runtime_Name_For;
1166
1167    ------------------------------------
1168    -- Add_Default_GNAT_Naming_Scheme --
1169    ------------------------------------
1170
1171    procedure Add_Default_GNAT_Naming_Scheme
1172      (Config_File  : in out Project_Node_Id;
1173       Project_Tree : Project_Node_Tree_Ref)
1174    is
1175       procedure Create_Attribute
1176         (Name  : Name_Id;
1177          Value : String;
1178          Index : String := "";
1179          Pkg   : Project_Node_Id := Empty_Node);
1180
1181       ----------------------
1182       -- Create_Attribute --
1183       ----------------------
1184
1185       procedure Create_Attribute
1186         (Name  : Name_Id;
1187          Value : String;
1188          Index : String := "";
1189          Pkg   : Project_Node_Id := Empty_Node)
1190       is
1191          Attr       : Project_Node_Id;
1192          pragma Unreferenced (Attr);
1193
1194          Expr   : Name_Id         := No_Name;
1195          Val    : Name_Id         := No_Name;
1196          Parent : Project_Node_Id := Config_File;
1197       begin
1198          if Index /= "" then
1199             Name_Len := Index'Length;
1200             Name_Buffer (1 .. Name_Len) := Index;
1201             Val := Name_Find;
1202          end if;
1203
1204          if Pkg /= Empty_Node then
1205             Parent := Pkg;
1206          end if;
1207
1208          Name_Len := Value'Length;
1209          Name_Buffer (1 .. Name_Len) := Value;
1210          Expr := Name_Find;
1211
1212          Attr := Create_Attribute
1213            (Tree       => Project_Tree,
1214             Prj_Or_Pkg => Parent,
1215             Name       => Name,
1216             Index_Name => Val,
1217             Kind       => Prj.Single,
1218             Value      => Create_Literal_String (Expr, Project_Tree));
1219       end Create_Attribute;
1220
1221       --  Local variables
1222
1223       Name   : Name_Id;
1224       Naming : Project_Node_Id;
1225
1226    --  Start of processing for Add_Default_GNAT_Naming_Scheme
1227
1228    begin
1229       if Config_File = Empty_Node then
1230
1231          --  Create a dummy config file is none was found
1232
1233          Name_Len := Auto_Cgpr'Length;
1234          Name_Buffer (1 .. Name_Len) := Auto_Cgpr;
1235          Name := Name_Find;
1236
1237          --  An invalid project name to avoid conflicts with user-created ones
1238
1239          Name_Len := 5;
1240          Name_Buffer (1 .. Name_Len) := "_auto";
1241
1242          Config_File :=
1243            Create_Project
1244              (In_Tree        => Project_Tree,
1245               Name           => Name_Find,
1246               Full_Path      => Path_Name_Type (Name),
1247               Is_Config_File => True);
1248
1249          --  Setup library support
1250
1251          case MLib.Tgt.Support_For_Libraries is
1252             when None =>
1253                null;
1254
1255             when Static_Only =>
1256                Create_Attribute (Name_Library_Support, "static_only");
1257
1258             when Full =>
1259                Create_Attribute (Name_Library_Support, "full");
1260          end case;
1261
1262          if MLib.Tgt.Standalone_Library_Auto_Init_Is_Supported then
1263             Create_Attribute (Name_Library_Auto_Init_Supported, "true");
1264          else
1265             Create_Attribute (Name_Library_Auto_Init_Supported, "false");
1266          end if;
1267
1268          --  Setup Ada support (Ada is the default language here, since this
1269          --  is only called when no config file existed initially, ie for
1270          --  gnatmake).
1271
1272          Create_Attribute (Name_Default_Language, "ada");
1273
1274          Naming := Create_Package (Project_Tree, Config_File, "naming");
1275          Create_Attribute (Name_Spec_Suffix, ".ads", "ada",     Pkg => Naming);
1276          Create_Attribute (Name_Separate_Suffix, ".adb", "ada", Pkg => Naming);
1277          Create_Attribute (Name_Body_Suffix, ".adb", "ada",     Pkg => Naming);
1278          Create_Attribute (Name_Dot_Replacement, "-",           Pkg => Naming);
1279          Create_Attribute (Name_Casing,          "lowercase",   Pkg => Naming);
1280
1281          if Current_Verbosity = High then
1282             Write_Line ("Automatically generated (in-memory) config file");
1283             Prj.PP.Pretty_Print
1284               (Project                => Config_File,
1285                In_Tree                => Project_Tree,
1286                Backward_Compatibility => False);
1287          end if;
1288       end if;
1289    end Add_Default_GNAT_Naming_Scheme;
1290
1291 end Prj.Conf;