OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / ada / prj-nmsc.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                             P R J . N M S C                              --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 2000-2012, Free Software Foundation, Inc.         --
10 --                                                                          --
11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNAT; see file COPYING3.  If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license.          --
20 --                                                                          --
21 -- GNAT was originally developed  by the GNAT team at  New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
23 --                                                                          --
24 ------------------------------------------------------------------------------
25
26 with Err_Vars; use Err_Vars;
27 with Opt;      use Opt;
28 with Osint;    use Osint;
29 with Output;   use Output;
30 with Prj.Com;
31 with Prj.Env;  use Prj.Env;
32 with Prj.Err;  use Prj.Err;
33 with Prj.Tree; use Prj.Tree;
34 with Prj.Util; use Prj.Util;
35 with Sinput.P;
36 with Snames;   use Snames;
37 with Targparm; use Targparm;
38
39 with Ada;                        use Ada;
40 with Ada.Characters.Handling;    use Ada.Characters.Handling;
41 with Ada.Directories;            use Ada.Directories;
42 with Ada.Strings;                use Ada.Strings;
43 with Ada.Strings.Fixed;          use Ada.Strings.Fixed;
44 with Ada.Strings.Maps.Constants; use Ada.Strings.Maps.Constants;
45
46 with GNAT.Case_Util;            use GNAT.Case_Util;
47 with GNAT.Directory_Operations; use GNAT.Directory_Operations;
48 with GNAT.Dynamic_HTables;
49 with GNAT.Regexp;               use GNAT.Regexp;
50 with GNAT.Table;
51
52 package body Prj.Nmsc is
53
54    No_Continuation_String : aliased String := "";
55    Continuation_String    : aliased String := "\";
56    --  Used in Check_Library for continuation error messages at the same
57    --  location.
58
59    type Name_Location is record
60       Name     : File_Name_Type;
61       --  Key is duplicated, so that it is known when using functions Get_First
62       --  and Get_Next, as these functions only return an Element.
63
64       Location : Source_Ptr;
65       Source   : Source_Id := No_Source;
66       Listed   : Boolean := False;
67       Found    : Boolean := False;
68    end record;
69
70    No_Name_Location : constant Name_Location :=
71                         (Name     => No_File,
72                          Location => No_Location,
73                          Source   => No_Source,
74                          Listed   => False,
75                          Found    => False);
76
77    package Source_Names_Htable is new GNAT.Dynamic_HTables.Simple_HTable
78      (Header_Num => Header_Num,
79       Element    => Name_Location,
80       No_Element => No_Name_Location,
81       Key        => File_Name_Type,
82       Hash       => Hash,
83       Equal      => "=");
84    --  File name information found in string list attribute (Source_Files or
85    --  Source_List_File). Used to check that all referenced files were indeed
86    --  found on the disk.
87
88    type Unit_Exception is record
89       Name : Name_Id;
90       --  Key is duplicated, so that it is known when using functions Get_First
91       --  and Get_Next, as these functions only return an Element.
92
93       Spec : File_Name_Type;
94       Impl : File_Name_Type;
95    end record;
96
97    No_Unit_Exception : constant Unit_Exception := (No_Name, No_File, No_File);
98
99    package Unit_Exceptions_Htable is new GNAT.Dynamic_HTables.Simple_HTable
100      (Header_Num => Header_Num,
101       Element    => Unit_Exception,
102       No_Element => No_Unit_Exception,
103       Key        => Name_Id,
104       Hash       => Hash,
105       Equal      => "=");
106    --  Record special naming schemes for Ada units (name of spec file and name
107    --  of implementation file). The elements in this list come from the naming
108    --  exceptions specified in the project files.
109
110    type File_Found is record
111       File      : File_Name_Type := No_File;
112       Excl_File : File_Name_Type := No_File;
113       Excl_Line : Natural        := 0;
114       Found     : Boolean        := False;
115       Location  : Source_Ptr     := No_Location;
116    end record;
117
118    No_File_Found : constant File_Found :=
119                      (No_File, No_File, 0, False, No_Location);
120
121    package Excluded_Sources_Htable is new GNAT.Dynamic_HTables.Simple_HTable
122      (Header_Num => Header_Num,
123       Element    => File_Found,
124       No_Element => No_File_Found,
125       Key        => File_Name_Type,
126       Hash       => Hash,
127       Equal      => "=");
128    --  A hash table to store the base names of excluded files, if any
129
130    package Object_File_Names_Htable is new GNAT.Dynamic_HTables.Simple_HTable
131      (Header_Num => Header_Num,
132       Element    => Source_Id,
133       No_Element => No_Source,
134       Key        => File_Name_Type,
135       Hash       => Hash,
136       Equal      => "=");
137    --  A hash table to store the object file names for a project, to check that
138    --  two different sources have different object file names.
139
140    type Project_Processing_Data is record
141       Project         : Project_Id;
142       Source_Names    : Source_Names_Htable.Instance;
143       Unit_Exceptions : Unit_Exceptions_Htable.Instance;
144       Excluded        : Excluded_Sources_Htable.Instance;
145
146       Source_List_File_Location : Source_Ptr;
147       --  Location of the Source_List_File attribute, for error messages
148    end record;
149    --  This is similar to Tree_Processing_Data, but contains project-specific
150    --  information which is only useful while processing the project, and can
151    --  be discarded as soon as we have finished processing the project
152
153    type Tree_Processing_Data is record
154       Tree             : Project_Tree_Ref;
155       Node_Tree        : Prj.Tree.Project_Node_Tree_Ref;
156       Flags            : Prj.Processing_Flags;
157       In_Aggregate_Lib : Boolean;
158    end record;
159    --  Temporary data which is needed while parsing a project. It does not need
160    --  to be kept in memory once a project has been fully loaded, but is
161    --  necessary while performing consistency checks (duplicate sources,...)
162    --  This data must be initialized before processing any project, and the
163    --  same data is used for processing all projects in the tree.
164
165    type Lib_Data is record
166       Name : Name_Id;
167       Proj : Project_Id;
168    end record;
169
170    package Lib_Data_Table is new GNAT.Table
171      (Table_Component_Type => Lib_Data,
172       Table_Index_Type     => Natural,
173       Table_Low_Bound      => 1,
174       Table_Initial        => 10,
175       Table_Increment      => 100);
176    --  A table to record library names in order to check that two library
177    --  projects do not have the same library names.
178
179    procedure Initialize
180      (Data      : out Tree_Processing_Data;
181       Tree      : Project_Tree_Ref;
182       Node_Tree : Prj.Tree.Project_Node_Tree_Ref;
183       Flags     : Prj.Processing_Flags);
184    --  Initialize Data
185
186    procedure Free (Data : in out Tree_Processing_Data);
187    --  Free the memory occupied by Data
188
189    procedure Initialize
190      (Data    : in out Project_Processing_Data;
191       Project : Project_Id);
192    procedure Free (Data : in out Project_Processing_Data);
193    --  Initialize or free memory for a project-specific data
194
195    procedure Find_Excluded_Sources
196      (Project : in out Project_Processing_Data;
197       Data    : in out Tree_Processing_Data);
198    --  Find the list of files that should not be considered as source files
199    --  for this project. Sets the list in the Project.Excluded_Sources_Htable.
200
201    procedure Override_Kind (Source : Source_Id; Kind : Source_Kind);
202    --  Override the reference kind for a source file. This properly updates
203    --  the unit data if necessary.
204
205    procedure Load_Naming_Exceptions
206      (Project : in out Project_Processing_Data;
207       Data    : in out Tree_Processing_Data);
208    --  All source files in Data.First_Source are considered as naming
209    --  exceptions, and copied into the Source_Names and Unit_Exceptions tables
210    --  as appropriate.
211
212    type Search_Type is (Search_Files, Search_Directories);
213
214    generic
215       with procedure Callback
216         (Path          : Path_Information;
217          Pattern_Index : Natural);
218    procedure Expand_Subdirectory_Pattern
219      (Project       : Project_Id;
220       Data          : in out Tree_Processing_Data;
221       Patterns      : String_List_Id;
222       Ignore        : String_List_Id;
223       Search_For    : Search_Type;
224       Resolve_Links : Boolean);
225    --  Search the subdirectories of Project's directory for files or
226    --  directories that match the globbing patterns found in Patterns (for
227    --  instance "**/*.adb"). Typically, Patterns will be the value of the
228    --  Source_Dirs or Excluded_Source_Dirs attributes.
229    --
230    --  Every time such a file or directory is found, the callback is called.
231    --  Resolve_Links indicates whether we should resolve links while
232    --  normalizing names.
233    --
234    --  In the callback, Pattern_Index is the index within Patterns where the
235    --  expanded pattern was found (1 for the first element of Patterns and
236    --  all its matching directories, then 2,...).
237    --
238    --  We use a generic and not an access-to-subprogram because in some cases
239    --  this code is compiled with the restriction No_Implicit_Dynamic_Code.
240    --  An error message is raised if a pattern does not match any file.
241
242    procedure Add_Source
243      (Id                  : out Source_Id;
244       Data                : in out Tree_Processing_Data;
245       Project             : Project_Id;
246       Source_Dir_Rank     : Natural;
247       Lang_Id             : Language_Ptr;
248       Kind                : Source_Kind;
249       File_Name           : File_Name_Type;
250       Display_File        : File_Name_Type;
251       Naming_Exception    : Naming_Exception_Type := No;
252       Path                : Path_Information      := No_Path_Information;
253       Alternate_Languages : Language_List         := null;
254       Unit                : Name_Id               := No_Name;
255       Index               : Int                   := 0;
256       Locally_Removed     : Boolean               := False;
257       Location            : Source_Ptr            := No_Location);
258    --  Add a new source to the different lists: list of all sources in the
259    --  project tree, list of source of a project and list of sources of a
260    --  language. If Path is specified, the file is also added to
261    --  Source_Paths_HT. Location is used for error messages
262
263    function Canonical_Case_File_Name (Name : Name_Id) return File_Name_Type;
264    --  Same as Osint.Canonical_Case_File_Name but applies to Name_Id.
265    --  This alters Name_Buffer.
266
267    function Suffix_Matches
268      (Filename : String;
269       Suffix   : File_Name_Type) return Boolean;
270    --  True if the file name ends with the given suffix. Always returns False
271    --  if Suffix is No_Name.
272
273    procedure Replace_Into_Name_Buffer
274      (Str         : String;
275       Pattern     : String;
276       Replacement : Character);
277    --  Copy Str into Name_Buffer, replacing Pattern with Replacement. Str is
278    --  converted to lower-case at the same time.
279
280    procedure Check_Abstract_Project
281      (Project : Project_Id;
282       Data    : in out Tree_Processing_Data);
283    --  Check abstract projects attributes
284
285    procedure Check_Configuration
286      (Project : Project_Id;
287       Data    : in out Tree_Processing_Data);
288    --  Check the configuration attributes for the project
289
290    procedure Check_If_Externally_Built
291      (Project : Project_Id;
292       Data    : in out Tree_Processing_Data);
293    --  Check attribute Externally_Built of project Project in project tree
294    --  Data.Tree and modify its data Data if it has the value "true".
295
296    procedure Check_Interfaces
297      (Project : Project_Id;
298       Data    : in out Tree_Processing_Data);
299    --  If a list of sources is specified in attribute Interfaces, set
300    --  In_Interfaces only for the sources specified in the list.
301
302    procedure Check_Library_Attributes
303      (Project : Project_Id;
304       Data    : in out Tree_Processing_Data);
305    --  Check the library attributes of project Project in project tree
306    --  and modify its data Data accordingly.
307
308    procedure Check_Package_Naming
309      (Project : Project_Id;
310       Data    : in out Tree_Processing_Data);
311    --  Check the naming scheme part of Data, and initialize the naming scheme
312    --  data in the config of the various languages.
313
314    procedure Check_Programming_Languages
315      (Project : Project_Id;
316       Data    : in out Tree_Processing_Data);
317    --  Check attribute Languages for the project with data Data in project
318    --  tree Data.Tree and set the components of Data for all the programming
319    --  languages indicated in attribute Languages, if any.
320
321    procedure Check_Stand_Alone_Library
322      (Project : Project_Id;
323       Data    : in out Tree_Processing_Data);
324    --  Check if project Project in project tree Data.Tree is a Stand-Alone
325    --  Library project, and modify its data Data accordingly if it is one.
326
327    procedure Check_Unit_Name (Name : String; Unit : out Name_Id);
328    --  Check that a name is a valid unit name
329
330    function Compute_Directory_Last (Dir : String) return Natural;
331    --  Return the index of the last significant character in Dir. This is used
332    --  to avoid duplicate '/' (slash) characters at the end of directory names.
333
334    procedure Search_Directories
335      (Project         : in out Project_Processing_Data;
336       Data            : in out Tree_Processing_Data;
337       For_All_Sources : Boolean);
338    --  Search the source directories to find the sources. If For_All_Sources is
339    --  True, check each regular file name against the naming schemes of the
340    --  various languages. Otherwise consider only the file names in hash table
341    --  Source_Names. If Allow_Duplicate_Basenames then files with identical
342    --  base names are permitted within a project for source-based languages
343    --  (never for unit based languages).
344
345    procedure Check_File
346      (Project           : in out Project_Processing_Data;
347       Data              : in out Tree_Processing_Data;
348       Source_Dir_Rank   : Natural;
349       Path              : Path_Name_Type;
350       Display_Path      : Path_Name_Type;
351       File_Name         : File_Name_Type;
352       Display_File_Name : File_Name_Type;
353       Locally_Removed   : Boolean;
354       For_All_Sources   : Boolean);
355    --  Check if file File_Name is a valid source of the project. This is used
356    --  in multi-language mode only. When the file matches one of the naming
357    --  schemes, it is added to various htables through Add_Source and to
358    --  Source_Paths_Htable.
359    --
360    --  File_Name is the same as Display_File_Name, but has been normalized.
361    --  They do not include the directory information.
362    --
363    --  Path and Display_Path on the other hand are the full path to the file.
364    --  Path must have been normalized (canonical casing and possibly links
365    --  resolved).
366    --
367    --  Source_Directory is the directory in which the file was found. It is
368    --  neither normalized nor has had links resolved, and must not end with a
369    --  a directory separator, to avoid duplicates later on.
370    --
371    --  If For_All_Sources is True, then all possible file names are analyzed
372    --  otherwise only those currently set in the Source_Names hash table.
373
374    procedure Check_File_Naming_Schemes
375      (Project               : Project_Processing_Data;
376       File_Name             : File_Name_Type;
377       Alternate_Languages   : out Language_List;
378       Language              : out Language_Ptr;
379       Display_Language_Name : out Name_Id;
380       Unit                  : out Name_Id;
381       Lang_Kind             : out Language_Kind;
382       Kind                  : out Source_Kind);
383    --  Check if the file name File_Name conforms to one of the naming schemes
384    --  of the project. If the file does not match one of the naming schemes,
385    --  set Language to No_Language_Index. Filename is the name of the file
386    --  being investigated. It has been normalized (case-folded). File_Name is
387    --  the same value.
388
389    procedure Get_Directories
390      (Project : Project_Id;
391       Data    : in out Tree_Processing_Data);
392    --  Get the object directory, the exec directory and the source directories
393    --  of a project.
394
395    procedure Get_Mains
396      (Project : Project_Id;
397       Data    : in out Tree_Processing_Data);
398    --  Get the mains of a project from attribute Main, if it exists, and put
399    --  them in the project data.
400
401    procedure Get_Sources_From_File
402      (Path     : String;
403       Location : Source_Ptr;
404       Project  : in out Project_Processing_Data;
405       Data     : in out Tree_Processing_Data);
406    --  Get the list of sources from a text file and put them in hash table
407    --  Source_Names.
408
409    procedure Find_Sources
410      (Project : in out Project_Processing_Data;
411       Data    : in out Tree_Processing_Data);
412    --  Process the Source_Files and Source_List_File attributes, and store the
413    --  list of source files into the Source_Names htable. When these attributes
414    --  are not defined, find all files matching the naming schemes in the
415    --  source directories. If Allow_Duplicate_Basenames, then files with the
416    --  same base names are authorized within a project for source-based
417    --  languages (never for unit based languages)
418
419    procedure Compute_Unit_Name
420      (File_Name : File_Name_Type;
421       Naming    : Lang_Naming_Data;
422       Kind      : out Source_Kind;
423       Unit      : out Name_Id;
424       Project   : Project_Processing_Data);
425    --  Check whether the file matches the naming scheme. If it does,
426    --  compute its unit name. If Unit is set to No_Name on exit, none of the
427    --  other out parameters are relevant.
428
429    procedure Check_Illegal_Suffix
430      (Project         : Project_Id;
431       Suffix          : File_Name_Type;
432       Dot_Replacement : File_Name_Type;
433       Attribute_Name  : String;
434       Location        : Source_Ptr;
435       Data            : in out Tree_Processing_Data);
436    --  Display an error message if the given suffix is illegal for some reason.
437    --  The name of the attribute we are testing is specified in Attribute_Name,
438    --  which is used in the error message. Location is the location where the
439    --  suffix is defined.
440
441    procedure Locate_Directory
442      (Project          : Project_Id;
443       Name             : File_Name_Type;
444       Path             : out Path_Information;
445       Dir_Exists       : out Boolean;
446       Data             : in out Tree_Processing_Data;
447       Create           : String := "";
448       Location         : Source_Ptr := No_Location;
449       Must_Exist       : Boolean := True;
450       Externally_Built : Boolean := False);
451    --  Locate a directory. Name is the directory name. Relative paths are
452    --  resolved relative to the project's directory. If the directory does not
453    --  exist and Setup_Projects is True and Create is a non null string, an
454    --  attempt is made to create the directory. If the directory does not
455    --  exist, it is either created if Setup_Projects is False (and then
456    --  returned), or simply returned without checking for its existence (if
457    --  Must_Exist is False) or No_Path_Information is returned. In all cases,
458    --  Dir_Exists indicates whether the directory now exists. Create is also
459    --  used for debugging traces to show which path we are computing.
460
461    procedure Look_For_Sources
462      (Project : in out Project_Processing_Data;
463       Data    : in out Tree_Processing_Data);
464    --  Find all the sources of project Project in project tree Data.Tree and
465    --  update its Data accordingly. This assumes that the special naming
466    --  exceptions have already been processed.
467
468    function Path_Name_Of
469      (File_Name : File_Name_Type;
470       Directory : Path_Name_Type) return String;
471    --  Returns the path name of a (non project) file. Returns an empty string
472    --  if file cannot be found.
473
474    procedure Remove_Source
475      (Tree        : Project_Tree_Ref;
476       Id          : Source_Id;
477       Replaced_By : Source_Id);
478    --  Remove a file from the list of sources of a project. This might be
479    --  because the file is replaced by another one in an extending project,
480    --  or because a file was added as a naming exception but was not found
481    --  in the end.
482
483    procedure Report_No_Sources
484      (Project      : Project_Id;
485       Lang_Name    : String;
486       Data         : Tree_Processing_Data;
487       Location     : Source_Ptr;
488       Continuation : Boolean := False);
489    --  Report an error or a warning depending on the value of When_No_Sources
490    --  when there are no sources for language Lang_Name.
491
492    procedure Show_Source_Dirs
493      (Project : Project_Id;
494       Shared  : Shared_Project_Tree_Data_Access);
495    --  List all the source directories of a project
496
497    procedure Write_Attr (Name, Value : String);
498    --  Debug print a value for a specific property. Does nothing when not in
499    --  debug mode
500
501    procedure Error_Or_Warning
502      (Flags    : Processing_Flags;
503       Kind     : Error_Warning;
504       Msg      : String;
505       Location : Source_Ptr;
506       Project  : Project_Id);
507    --  Emits either an error or warning message (or nothing), depending on Kind
508
509    function No_Space_Img (N : Natural) return String;
510    --  Image of a Natural without the initial space
511
512    ----------------------
513    -- Error_Or_Warning --
514    ----------------------
515
516    procedure Error_Or_Warning
517      (Flags    : Processing_Flags;
518       Kind     : Error_Warning;
519       Msg      : String;
520       Location : Source_Ptr;
521       Project  : Project_Id) is
522    begin
523       case Kind is
524          when Error   => Error_Msg (Flags, Msg, Location, Project);
525          when Warning => Error_Msg (Flags, "?" & Msg, Location, Project);
526          when Silent  => null;
527       end case;
528    end Error_Or_Warning;
529
530    ------------------------------
531    -- Replace_Into_Name_Buffer --
532    ------------------------------
533
534    procedure Replace_Into_Name_Buffer
535      (Str         : String;
536       Pattern     : String;
537       Replacement : Character)
538    is
539       Max : constant Integer := Str'Last - Pattern'Length + 1;
540       J   : Positive;
541
542    begin
543       Name_Len := 0;
544
545       J := Str'First;
546       while J <= Str'Last loop
547          Name_Len := Name_Len + 1;
548
549          if J <= Max
550            and then Str (J .. J + Pattern'Length - 1) = Pattern
551          then
552             Name_Buffer (Name_Len) := Replacement;
553             J := J + Pattern'Length;
554
555          else
556             Name_Buffer (Name_Len) := GNAT.Case_Util.To_Lower (Str (J));
557             J := J + 1;
558          end if;
559       end loop;
560    end Replace_Into_Name_Buffer;
561
562    --------------------
563    -- Suffix_Matches --
564    --------------------
565
566    function Suffix_Matches
567      (Filename : String;
568       Suffix   : File_Name_Type) return Boolean
569    is
570       Min_Prefix_Length : Natural := 0;
571
572    begin
573       if Suffix = No_File or else Suffix = Empty_File then
574          return False;
575       end if;
576
577       declare
578          Suf : String := Get_Name_String (Suffix);
579
580       begin
581          --  On non case-sensitive systems, use proper suffix casing
582
583          Canonical_Case_File_Name (Suf);
584
585          --  The file name must end with the suffix (which is not an extension)
586          --  For instance a suffix "configure.in" must match a file with the
587          --  same name. To avoid dummy cases, though, a suffix starting with
588          --  '.' requires a file that is at least one character longer ('.cpp'
589          --  should not match a file with the same name).
590
591          if Suf (Suf'First) = '.' then
592             Min_Prefix_Length := 1;
593          end if;
594
595          return Filename'Length >= Suf'Length + Min_Prefix_Length
596            and then
597              Filename (Filename'Last - Suf'Length + 1 .. Filename'Last) = Suf;
598       end;
599    end Suffix_Matches;
600
601    ----------------
602    -- Write_Attr --
603    ----------------
604
605    procedure Write_Attr (Name, Value : String) is
606    begin
607       if Current_Verbosity = High then
608          Debug_Output (Name & " = """ & Value & '"');
609       end if;
610    end Write_Attr;
611
612    ----------------
613    -- Add_Source --
614    ----------------
615
616    procedure Add_Source
617      (Id                  : out Source_Id;
618       Data                : in out Tree_Processing_Data;
619       Project             : Project_Id;
620       Source_Dir_Rank     : Natural;
621       Lang_Id             : Language_Ptr;
622       Kind                : Source_Kind;
623       File_Name           : File_Name_Type;
624       Display_File        : File_Name_Type;
625       Naming_Exception    : Naming_Exception_Type := No;
626       Path                : Path_Information      := No_Path_Information;
627       Alternate_Languages : Language_List         := null;
628       Unit                : Name_Id               := No_Name;
629       Index               : Int                   := 0;
630       Locally_Removed     : Boolean               := False;
631       Location            : Source_Ptr            := No_Location)
632    is
633       Config            : constant Language_Config := Lang_Id.Config;
634       UData             : Unit_Index;
635       Add_Src           : Boolean;
636       Source            : Source_Id;
637       Prev_Unit         : Unit_Index := No_Unit_Index;
638       Source_To_Replace : Source_Id := No_Source;
639
640    begin
641       --  Check if the same file name or unit is used in the prj tree
642
643       Add_Src := True;
644
645       if Unit /= No_Name then
646          Prev_Unit := Units_Htable.Get (Data.Tree.Units_HT, Unit);
647       end if;
648
649       if Prev_Unit /= No_Unit_Index
650         and then (Kind = Impl or else Kind = Spec)
651         and then Prev_Unit.File_Names (Kind) /= null
652       then
653          --  Suspicious, we need to check later whether this is authorized
654
655          Add_Src := False;
656          Source := Prev_Unit.File_Names (Kind);
657
658       else
659          Source := Source_Files_Htable.Get
660            (Data.Tree.Source_Files_HT, File_Name);
661
662          if Source /= No_Source and then Source.Index = Index then
663             Add_Src := False;
664          end if;
665       end if;
666
667       --  Duplication of file/unit in same project is allowed if order of
668       --  source directories is known, or if there is no compiler for the
669       --  language.
670
671       if Add_Src = False then
672          Add_Src := True;
673
674          if Project = Source.Project then
675             if Prev_Unit = No_Unit_Index then
676                if Data.Flags.Allow_Duplicate_Basenames then
677                   Add_Src := True;
678
679                elsif Lang_Id.Config.Compiler_Driver = Empty_File then
680                   Add_Src := True;
681
682                elsif Source_Dir_Rank /= Source.Source_Dir_Rank then
683                   Add_Src := False;
684
685                else
686                   Error_Msg_File_1 := File_Name;
687                   Error_Msg
688                     (Data.Flags, "duplicate source file name {",
689                      Location, Project);
690                   Add_Src := False;
691                end if;
692
693             else
694                if Source_Dir_Rank /= Source.Source_Dir_Rank then
695                   Add_Src := False;
696
697                --  We might be seeing the same file through a different path
698                --  (for instance because of symbolic links).
699
700                elsif Source.Path.Name /= Path.Name then
701                   if not Source.Duplicate_Unit then
702                      Error_Msg_Name_1 := Unit;
703                      Error_Msg
704                        (Data.Flags, "\duplicate unit %%", Location, Project);
705                      Source.Duplicate_Unit := True;
706                   end if;
707
708                   Add_Src := False;
709                end if;
710             end if;
711
712             --  Do not allow the same unit name in different projects, except
713             --  if one is extending the other.
714
715             --  For a file based language, the same file name replaces a file
716             --  in a project being extended, but it is allowed to have the same
717             --  file name in unrelated projects.
718
719          elsif Is_Extending (Project, Source.Project) then
720             if not Locally_Removed and then Naming_Exception /= Inherited then
721                Source_To_Replace := Source;
722             end if;
723
724          elsif Prev_Unit /= No_Unit_Index
725            and then Prev_Unit.File_Names (Kind) /= null
726            and then not Source.Locally_Removed
727            and then not Data.In_Aggregate_Lib
728          then
729             --  Path is set if this is a source we found on the disk, in which
730             --  case we can provide more explicit error message. Path is unset
731             --  when the source is added from one of the naming exceptions in
732             --  the project.
733
734             if Path /= No_Path_Information then
735                Error_Msg_Name_1 := Unit;
736                Error_Msg
737                  (Data.Flags,
738                   "unit %% cannot belong to several projects",
739                   Location, Project);
740
741                Error_Msg_Name_1 := Project.Name;
742                Error_Msg_Name_2 := Name_Id (Path.Display_Name);
743                Error_Msg
744                  (Data.Flags, "\  project %%, %%", Location, Project);
745
746                Error_Msg_Name_1 := Source.Project.Name;
747                Error_Msg_Name_2 := Name_Id (Source.Path.Display_Name);
748                Error_Msg
749                  (Data.Flags, "\  project %%, %%", Location, Project);
750
751             else
752                Error_Msg_Name_1 := Unit;
753                Error_Msg_Name_2 := Source.Project.Name;
754                Error_Msg
755                  (Data.Flags, "unit %% already belongs to project %%",
756                   Location, Project);
757             end if;
758
759             Add_Src := False;
760
761          elsif not Source.Locally_Removed
762            and then not Data.Flags.Allow_Duplicate_Basenames
763            and then Lang_Id.Config.Kind = Unit_Based
764            and then Source.Language.Config.Kind = Unit_Based
765            and then not Data.In_Aggregate_Lib
766          then
767             Error_Msg_File_1 := File_Name;
768             Error_Msg_File_2 := File_Name_Type (Source.Project.Name);
769             Error_Msg
770               (Data.Flags,
771                "{ is already a source of project {", Location, Project);
772
773             --  Add the file anyway, to avoid further warnings like "language
774             --  unknown".
775
776             Add_Src := True;
777          end if;
778       end if;
779
780       if not Add_Src then
781          return;
782       end if;
783
784       --  Add the new file
785
786       Id := new Source_Data;
787
788       if Current_Verbosity = High then
789          Debug_Indent;
790          Write_Str ("adding source File: ");
791          Write_Str (Get_Name_String (Display_File));
792
793          if Index /= 0 then
794             Write_Str (" at" & Index'Img);
795          end if;
796
797          if Lang_Id.Config.Kind = Unit_Based then
798             Write_Str (" Unit: ");
799
800             --  ??? in gprclean, it seems we sometimes pass an empty Unit name
801             --  (see test extended_projects).
802
803             if Unit /= No_Name then
804                Write_Str (Get_Name_String (Unit));
805             end if;
806
807             Write_Str (" Kind: ");
808             Write_Str (Source_Kind'Image (Kind));
809          end if;
810
811          Write_Eol;
812       end if;
813
814       Id.Project             := Project;
815       Id.Location            := Location;
816       Id.Source_Dir_Rank     := Source_Dir_Rank;
817       Id.Language            := Lang_Id;
818       Id.Kind                := Kind;
819       Id.Alternate_Languages := Alternate_Languages;
820       Id.Locally_Removed     := Locally_Removed;
821       Id.Index               := Index;
822       Id.File                := File_Name;
823       Id.Display_File        := Display_File;
824       Id.Dep_Name            := Dependency_Name
825                                   (File_Name, Lang_Id.Config.Dependency_Kind);
826       Id.Naming_Exception    := Naming_Exception;
827       Id.Object              := Object_Name
828                                   (File_Name, Config.Object_File_Suffix);
829       Id.Switches            := Switches_Name (File_Name);
830
831       --  Add the source id to the Unit_Sources_HT hash table, if the unit name
832       --  is not null.
833
834       if Unit /= No_Name then
835
836          --  Note: we might be creating a dummy unit here, when we in fact have
837          --  a separate. For instance, file file-bar.adb will initially be
838          --  assumed to be the IMPL of unit "file.bar". Only later on (in
839          --  Check_Object_Files) will we parse those units that only have an
840          --  impl and no spec to make sure whether we have a Separate in fact
841          --  (that significantly reduces the number of times we need to parse
842          --  the files, since we are then only interested in those with no
843          --  spec). We still need those dummy units in the table, since that's
844          --  the name we find in the ALI file
845
846          UData := Units_Htable.Get (Data.Tree.Units_HT, Unit);
847
848          if UData = No_Unit_Index then
849             UData := new Unit_Data;
850             UData.Name := Unit;
851
852             if Naming_Exception /= Inherited then
853                Units_Htable.Set (Data.Tree.Units_HT, Unit, UData);
854             end if;
855          end if;
856
857          Id.Unit := UData;
858
859          --  Note that this updates Unit information as well
860
861          if Naming_Exception /= Inherited then
862             Override_Kind (Id, Kind);
863          end if;
864       end if;
865
866       if Path /= No_Path_Information then
867          Id.Path := Path;
868          Source_Paths_Htable.Set (Data.Tree.Source_Paths_HT, Path.Name, Id);
869       end if;
870
871       Id.Next_With_File_Name :=
872         Source_Files_Htable.Get (Data.Tree.Source_Files_HT, File_Name);
873       Source_Files_Htable.Set (Data.Tree.Source_Files_HT, File_Name, Id);
874
875       if Index /= 0 then
876          Project.Has_Multi_Unit_Sources := True;
877       end if;
878
879       --  Add the source to the language list
880
881       Id.Next_In_Lang := Lang_Id.First_Source;
882       Lang_Id.First_Source := Id;
883
884       if Source_To_Replace /= No_Source then
885          Remove_Source (Data.Tree, Source_To_Replace, Id);
886       end if;
887
888       if Data.Tree.Replaced_Source_Number > 0
889         and then
890           Replaced_Source_HTable.Get
891             (Data.Tree.Replaced_Sources, Id.File) /= No_File
892       then
893          Replaced_Source_HTable.Remove (Data.Tree.Replaced_Sources, Id.File);
894          Data.Tree.Replaced_Source_Number :=
895            Data.Tree.Replaced_Source_Number - 1;
896       end if;
897    end Add_Source;
898
899    ------------------------------
900    -- Canonical_Case_File_Name --
901    ------------------------------
902
903    function Canonical_Case_File_Name (Name : Name_Id) return File_Name_Type is
904    begin
905       if Osint.File_Names_Case_Sensitive then
906          return File_Name_Type (Name);
907       else
908          Get_Name_String (Name);
909          Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
910          return Name_Find;
911       end if;
912    end Canonical_Case_File_Name;
913
914    ---------------------------------
915    -- Process_Aggregated_Projects --
916    ---------------------------------
917
918    procedure Process_Aggregated_Projects
919      (Tree      : Project_Tree_Ref;
920       Project   : Project_Id;
921       Node_Tree : Prj.Tree.Project_Node_Tree_Ref;
922       Flags     : Processing_Flags)
923    is
924       Data : Tree_Processing_Data :=
925                (Tree             => Tree,
926                 Node_Tree        => Node_Tree,
927                 Flags            => Flags,
928                 In_Aggregate_Lib => False);
929
930       Project_Files : constant Prj.Variable_Value :=
931                         Prj.Util.Value_Of
932                           (Snames.Name_Project_Files,
933                            Project.Decl.Attributes,
934                            Tree.Shared);
935
936       Project_Path_For_Aggregate : Prj.Env.Project_Search_Path;
937
938       procedure Found_Project_File (Path : Path_Information; Rank : Natural);
939       --  Called for each project file aggregated by Project
940
941       procedure Expand_Project_Files is
942         new Expand_Subdirectory_Pattern (Callback => Found_Project_File);
943       --  Search for all project files referenced by the patterns given in
944       --  parameter. Calls Found_Project_File for each of them.
945
946       ------------------------
947       -- Found_Project_File --
948       ------------------------
949
950       procedure Found_Project_File (Path : Path_Information; Rank : Natural) is
951          pragma Unreferenced (Rank);
952
953       begin
954          if Path.Name /= Project.Path.Name then
955             Debug_Output ("aggregates: ", Name_Id (Path.Display_Name));
956
957             --  For usual "with" statement, this phase will have been done when
958             --  parsing the project itself. However, for aggregate projects, we
959             --  can only do this when processing the aggregate project, since
960             --  the exact list of project files or project directories can
961             --  depend on scenario variables.
962             --
963             --  We only load the projects explicitly here, but do not process
964             --  them. For the processing, Prj.Proc will take care of processing
965             --  them, within the same call to Recursive_Process (thus avoiding
966             --  the processing of a given project multiple times).
967             --
968             --  ??? We might already have loaded the project
969
970             Add_Aggregated_Project (Project, Path => Path.Name);
971
972          else
973             Debug_Output ("pattern returned the aggregate itself, ignored");
974          end if;
975       end Found_Project_File;
976
977    --  Start of processing for Check_Aggregate_Project
978
979    begin
980       pragma Assert (Project.Qualifier in Aggregate_Project);
981
982       if Project_Files.Default then
983          Error_Msg_Name_1 := Snames.Name_Project_Files;
984          Error_Msg
985            (Flags,
986             "Attribute %% must be specified in aggregate project",
987             Project.Location, Project);
988          return;
989       end if;
990
991       --  The aggregated projects are only searched relative to the directory
992       --  of the aggregate project, not in the default project path.
993
994       Initialize_Empty (Project_Path_For_Aggregate);
995
996       Free (Project.Aggregated_Projects);
997
998       --  Look for aggregated projects. For similarity with source files and
999       --  dirs, the aggregated project files are not searched for on the
1000       --  project path, and are only found through the path specified in
1001       --  the Project_Files attribute.
1002
1003       Expand_Project_Files
1004         (Project       => Project,
1005          Data          => Data,
1006          Patterns      => Project_Files.Values,
1007          Ignore        => Nil_String,
1008          Search_For    => Search_Files,
1009          Resolve_Links => Opt.Follow_Links_For_Files);
1010
1011       Free (Project_Path_For_Aggregate);
1012    end Process_Aggregated_Projects;
1013
1014    ----------------------------
1015    -- Check_Abstract_Project --
1016    ----------------------------
1017
1018    procedure Check_Abstract_Project
1019      (Project : Project_Id;
1020       Data    : in out Tree_Processing_Data)
1021    is
1022       Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
1023
1024       Source_Dirs      : constant Variable_Value :=
1025                            Util.Value_Of
1026                              (Name_Source_Dirs,
1027                               Project.Decl.Attributes, Shared);
1028       Source_Files     : constant Variable_Value :=
1029                            Util.Value_Of
1030                              (Name_Source_Files,
1031                               Project.Decl.Attributes, Shared);
1032       Source_List_File : constant Variable_Value :=
1033                            Util.Value_Of
1034                              (Name_Source_List_File,
1035                               Project.Decl.Attributes, Shared);
1036       Languages        : constant Variable_Value :=
1037                            Util.Value_Of
1038                              (Name_Languages,
1039                               Project.Decl.Attributes, Shared);
1040
1041    begin
1042       if Project.Source_Dirs /= Nil_String then
1043          if Source_Dirs.Values  = Nil_String
1044            and then Source_Files.Values = Nil_String
1045            and then Languages.Values = Nil_String
1046            and then Source_List_File.Default
1047          then
1048             Project.Source_Dirs := Nil_String;
1049
1050          else
1051             Error_Msg
1052               (Data.Flags,
1053                "at least one of Source_Files, Source_Dirs or Languages "
1054                & "must be declared empty for an abstract project",
1055                Project.Location, Project);
1056          end if;
1057       end if;
1058    end Check_Abstract_Project;
1059
1060    -------------------------
1061    -- Check_Configuration --
1062    -------------------------
1063
1064    procedure Check_Configuration
1065      (Project : Project_Id;
1066       Data    : in out Tree_Processing_Data)
1067    is
1068       Shared          : constant Shared_Project_Tree_Data_Access :=
1069                           Data.Tree.Shared;
1070
1071       Dot_Replacement : File_Name_Type := No_File;
1072       Casing          : Casing_Type    := All_Lower_Case;
1073       Separate_Suffix : File_Name_Type := No_File;
1074
1075       Lang_Index : Language_Ptr := No_Language_Index;
1076       --  The index of the language data being checked
1077
1078       Prev_Index : Language_Ptr := No_Language_Index;
1079       --  The index of the previous language
1080
1081       procedure Process_Project_Level_Simple_Attributes;
1082       --  Process the simple attributes at the project level
1083
1084       procedure Process_Project_Level_Array_Attributes;
1085       --  Process the associate array attributes at the project level
1086
1087       procedure Process_Packages;
1088       --  Read the packages of the project
1089
1090       ----------------------
1091       -- Process_Packages --
1092       ----------------------
1093
1094       procedure Process_Packages is
1095          Packages : Package_Id;
1096          Element  : Package_Element;
1097
1098          procedure Process_Binder (Arrays : Array_Id);
1099          --  Process the associate array attributes of package Binder
1100
1101          procedure Process_Builder (Attributes : Variable_Id);
1102          --  Process the simple attributes of package Builder
1103
1104          procedure Process_Compiler (Arrays : Array_Id);
1105          --  Process the associate array attributes of package Compiler
1106
1107          procedure Process_Naming (Attributes : Variable_Id);
1108          --  Process the simple attributes of package Naming
1109
1110          procedure Process_Naming (Arrays : Array_Id);
1111          --  Process the associate array attributes of package Naming
1112
1113          procedure Process_Linker (Attributes : Variable_Id);
1114          --  Process the simple attributes of package Linker of a
1115          --  configuration project.
1116
1117          --------------------
1118          -- Process_Binder --
1119          --------------------
1120
1121          procedure Process_Binder (Arrays : Array_Id) is
1122             Current_Array_Id : Array_Id;
1123             Current_Array    : Array_Data;
1124             Element_Id       : Array_Element_Id;
1125             Element          : Array_Element;
1126
1127          begin
1128             --  Process the associative array attribute of package Binder
1129
1130             Current_Array_Id := Arrays;
1131             while Current_Array_Id /= No_Array loop
1132                Current_Array := Shared.Arrays.Table (Current_Array_Id);
1133
1134                Element_Id := Current_Array.Value;
1135                while Element_Id /= No_Array_Element loop
1136                   Element := Shared.Array_Elements.Table (Element_Id);
1137
1138                   if Element.Index /= All_Other_Names then
1139
1140                      --  Get the name of the language
1141
1142                      Lang_Index :=
1143                        Get_Language_From_Name
1144                          (Project, Get_Name_String (Element.Index));
1145
1146                      if Lang_Index /= No_Language_Index then
1147                         case Current_Array.Name is
1148                            when Name_Driver =>
1149
1150                               --  Attribute Driver (<language>)
1151
1152                               Lang_Index.Config.Binder_Driver :=
1153                                 File_Name_Type (Element.Value.Value);
1154
1155                            when Name_Required_Switches =>
1156                               Put
1157                                 (Into_List =>
1158                                    Lang_Index.Config.Binder_Required_Switches,
1159                                  From_List => Element.Value.Values,
1160                                  In_Tree   => Data.Tree);
1161
1162                            when Name_Prefix =>
1163
1164                               --  Attribute Prefix (<language>)
1165
1166                               Lang_Index.Config.Binder_Prefix :=
1167                                 Element.Value.Value;
1168
1169                            when Name_Objects_Path =>
1170
1171                               --  Attribute Objects_Path (<language>)
1172
1173                               Lang_Index.Config.Objects_Path :=
1174                                 Element.Value.Value;
1175
1176                            when Name_Objects_Path_File =>
1177
1178                               --  Attribute Objects_Path (<language>)
1179
1180                               Lang_Index.Config.Objects_Path_File :=
1181                                 Element.Value.Value;
1182
1183                            when others =>
1184                               null;
1185                         end case;
1186                      end if;
1187                   end if;
1188
1189                   Element_Id := Element.Next;
1190                end loop;
1191
1192                Current_Array_Id := Current_Array.Next;
1193             end loop;
1194          end Process_Binder;
1195
1196          ---------------------
1197          -- Process_Builder --
1198          ---------------------
1199
1200          procedure Process_Builder (Attributes : Variable_Id) is
1201             Attribute_Id : Variable_Id;
1202             Attribute    : Variable;
1203
1204          begin
1205             --  Process non associated array attribute from package Builder
1206
1207             Attribute_Id := Attributes;
1208             while Attribute_Id /= No_Variable loop
1209                Attribute := Shared.Variable_Elements.Table (Attribute_Id);
1210
1211                if not Attribute.Value.Default then
1212                   if Attribute.Name = Name_Executable_Suffix then
1213
1214                      --  Attribute Executable_Suffix: the suffix of the
1215                      --  executables.
1216
1217                      Project.Config.Executable_Suffix :=
1218                        Attribute.Value.Value;
1219                   end if;
1220                end if;
1221
1222                Attribute_Id := Attribute.Next;
1223             end loop;
1224          end Process_Builder;
1225
1226          ----------------------
1227          -- Process_Compiler --
1228          ----------------------
1229
1230          procedure Process_Compiler (Arrays : Array_Id) is
1231             Current_Array_Id : Array_Id;
1232             Current_Array    : Array_Data;
1233             Element_Id       : Array_Element_Id;
1234             Element          : Array_Element;
1235             List             : String_List_Id;
1236
1237          begin
1238             --  Process the associative array attribute of package Compiler
1239
1240             Current_Array_Id := Arrays;
1241             while Current_Array_Id /= No_Array loop
1242                Current_Array := Shared.Arrays.Table (Current_Array_Id);
1243
1244                Element_Id := Current_Array.Value;
1245                while Element_Id /= No_Array_Element loop
1246                   Element := Shared.Array_Elements.Table (Element_Id);
1247
1248                   if Element.Index /= All_Other_Names then
1249
1250                      --  Get the name of the language
1251
1252                      Lang_Index := Get_Language_From_Name
1253                        (Project, Get_Name_String (Element.Index));
1254
1255                      if Lang_Index /= No_Language_Index then
1256                         case Current_Array.Name is
1257
1258                         --  Attribute Dependency_Kind (<language>)
1259
1260                         when Name_Dependency_Kind =>
1261                            Get_Name_String (Element.Value.Value);
1262
1263                            begin
1264                               Lang_Index.Config.Dependency_Kind :=
1265                                 Dependency_File_Kind'Value
1266                                   (Name_Buffer (1 .. Name_Len));
1267
1268                            exception
1269                               when Constraint_Error =>
1270                                  Error_Msg
1271                                    (Data.Flags,
1272                                     "illegal value for Dependency_Kind",
1273                                     Element.Value.Location,
1274                                     Project);
1275                            end;
1276
1277                         --  Attribute Dependency_Switches (<language>)
1278
1279                         when Name_Dependency_Switches =>
1280                            if Lang_Index.Config.Dependency_Kind = None then
1281                               Lang_Index.Config.Dependency_Kind := Makefile;
1282                            end if;
1283
1284                            List := Element.Value.Values;
1285
1286                            if List /= Nil_String then
1287                               Put (Into_List =>
1288                                      Lang_Index.Config.Dependency_Option,
1289                                    From_List => List,
1290                                    In_Tree   => Data.Tree);
1291                            end if;
1292
1293                         --  Attribute Dependency_Driver (<language>)
1294
1295                         when Name_Dependency_Driver =>
1296                            if Lang_Index.Config.Dependency_Kind = None then
1297                               Lang_Index.Config.Dependency_Kind := Makefile;
1298                            end if;
1299
1300                            List := Element.Value.Values;
1301
1302                            if List /= Nil_String then
1303                               Put (Into_List =>
1304                                      Lang_Index.Config.Compute_Dependency,
1305                                    From_List => List,
1306                                    In_Tree   => Data.Tree);
1307                            end if;
1308
1309                         --  Attribute Language_Kind (<language>)
1310
1311                         when Name_Language_Kind =>
1312                            Get_Name_String (Element.Value.Value);
1313
1314                            begin
1315                               Lang_Index.Config.Kind :=
1316                                 Language_Kind'Value
1317                                   (Name_Buffer (1 .. Name_Len));
1318
1319                            exception
1320                               when Constraint_Error =>
1321                                  Error_Msg
1322                                    (Data.Flags,
1323                                     "illegal value for Language_Kind",
1324                                     Element.Value.Location,
1325                                     Project);
1326                            end;
1327
1328                         --  Attribute Include_Switches (<language>)
1329
1330                         when Name_Include_Switches =>
1331                            List := Element.Value.Values;
1332
1333                            if List = Nil_String then
1334                               Error_Msg
1335                                 (Data.Flags, "include option cannot be null",
1336                                  Element.Value.Location, Project);
1337                            end if;
1338
1339                            Put (Into_List => Lang_Index.Config.Include_Option,
1340                                 From_List => List,
1341                                 In_Tree   => Data.Tree);
1342
1343                         --  Attribute Include_Path (<language>)
1344
1345                         when Name_Include_Path =>
1346                            Lang_Index.Config.Include_Path :=
1347                              Element.Value.Value;
1348
1349                         --  Attribute Include_Path_File (<language>)
1350
1351                         when Name_Include_Path_File =>
1352                            Lang_Index.Config.Include_Path_File :=
1353                              Element.Value.Value;
1354
1355                         --  Attribute Driver (<language>)
1356
1357                         when Name_Driver =>
1358                            Lang_Index.Config.Compiler_Driver :=
1359                              File_Name_Type (Element.Value.Value);
1360
1361                         when Name_Required_Switches
1362                            | Name_Leading_Required_Switches
1363                            =>
1364                            Put (Into_List =>
1365                                   Lang_Index.Config.
1366                                     Compiler_Leading_Required_Switches,
1367                                 From_List => Element.Value.Values,
1368                                 In_Tree   => Data.Tree);
1369
1370                         when Name_Trailing_Required_Switches =>
1371                            Put (Into_List =>
1372                                   Lang_Index.Config.
1373                                     Compiler_Trailing_Required_Switches,
1374                                 From_List => Element.Value.Values,
1375                                 In_Tree   => Data.Tree);
1376
1377                         when Name_Multi_Unit_Switches =>
1378                            Put (Into_List =>
1379                                   Lang_Index.Config.Multi_Unit_Switches,
1380                                 From_List => Element.Value.Values,
1381                                 In_Tree   => Data.Tree);
1382
1383                         when Name_Multi_Unit_Object_Separator =>
1384                            Get_Name_String (Element.Value.Value);
1385
1386                            if Name_Len /= 1 then
1387                               Error_Msg
1388                                 (Data.Flags,
1389                                  "multi-unit object separator must have " &
1390                                  "a single character",
1391                                  Element.Value.Location, Project);
1392
1393                            elsif Name_Buffer (1) = ' ' then
1394                               Error_Msg
1395                                 (Data.Flags,
1396                                  "multi-unit object separator cannot be " &
1397                                  "a space",
1398                                  Element.Value.Location, Project);
1399
1400                            else
1401                               Lang_Index.Config.Multi_Unit_Object_Separator :=
1402                                 Name_Buffer (1);
1403                            end if;
1404
1405                         when Name_Path_Syntax =>
1406                            begin
1407                               Lang_Index.Config.Path_Syntax :=
1408                                   Path_Syntax_Kind'Value
1409                                     (Get_Name_String (Element.Value.Value));
1410
1411                            exception
1412                               when Constraint_Error =>
1413                                  Error_Msg
1414                                    (Data.Flags,
1415                                     "invalid value for Path_Syntax",
1416                                     Element.Value.Location, Project);
1417                            end;
1418
1419                         when Name_Source_File_Switches =>
1420                            Put (Into_List =>
1421                                   Lang_Index.Config.Source_File_Switches,
1422                                 From_List => Element.Value.Values,
1423                                 In_Tree   => Data.Tree);
1424
1425                         when Name_Object_File_Suffix =>
1426                            if Get_Name_String (Element.Value.Value) = "" then
1427                               Error_Msg
1428                                 (Data.Flags,
1429                                  "object file suffix cannot be empty",
1430                                  Element.Value.Location, Project);
1431
1432                            else
1433                               Lang_Index.Config.Object_File_Suffix :=
1434                                 Element.Value.Value;
1435                            end if;
1436
1437                         when Name_Object_File_Switches =>
1438                            Put (Into_List =>
1439                                   Lang_Index.Config.Object_File_Switches,
1440                                 From_List => Element.Value.Values,
1441                                 In_Tree   => Data.Tree);
1442
1443                         --  Attribute Compiler_Pic_Option (<language>)
1444
1445                         when Name_Pic_Option =>
1446                            List := Element.Value.Values;
1447
1448                            if List = Nil_String then
1449                               Error_Msg
1450                                 (Data.Flags,
1451                                  "compiler PIC option cannot be null",
1452                                  Element.Value.Location, Project);
1453                            end if;
1454
1455                            Put (Into_List =>
1456                                   Lang_Index.Config.Compilation_PIC_Option,
1457                                 From_List => List,
1458                                 In_Tree   => Data.Tree);
1459
1460                         --  Attribute Mapping_File_Switches (<language>)
1461
1462                         when Name_Mapping_File_Switches =>
1463                            List := Element.Value.Values;
1464
1465                            if List = Nil_String then
1466                               Error_Msg
1467                                 (Data.Flags,
1468                                  "mapping file switches cannot be null",
1469                                  Element.Value.Location, Project);
1470                            end if;
1471
1472                            Put (Into_List =>
1473                                 Lang_Index.Config.Mapping_File_Switches,
1474                                 From_List => List,
1475                                 In_Tree   => Data.Tree);
1476
1477                         --  Attribute Mapping_Spec_Suffix (<language>)
1478
1479                         when Name_Mapping_Spec_Suffix =>
1480                            Lang_Index.Config.Mapping_Spec_Suffix :=
1481                              File_Name_Type (Element.Value.Value);
1482
1483                         --  Attribute Mapping_Body_Suffix (<language>)
1484
1485                         when Name_Mapping_Body_Suffix =>
1486                            Lang_Index.Config.Mapping_Body_Suffix :=
1487                              File_Name_Type (Element.Value.Value);
1488
1489                         --  Attribute Config_File_Switches (<language>)
1490
1491                         when Name_Config_File_Switches =>
1492                            List := Element.Value.Values;
1493
1494                            if List = Nil_String then
1495                               Error_Msg
1496                                 (Data.Flags,
1497                                  "config file switches cannot be null",
1498                                  Element.Value.Location, Project);
1499                            end if;
1500
1501                            Put (Into_List =>
1502                                   Lang_Index.Config.Config_File_Switches,
1503                                 From_List => List,
1504                                 In_Tree   => Data.Tree);
1505
1506                         --  Attribute Objects_Path (<language>)
1507
1508                         when Name_Objects_Path =>
1509                            Lang_Index.Config.Objects_Path :=
1510                              Element.Value.Value;
1511
1512                         --  Attribute Objects_Path_File (<language>)
1513
1514                         when Name_Objects_Path_File =>
1515                            Lang_Index.Config.Objects_Path_File :=
1516                              Element.Value.Value;
1517
1518                         --  Attribute Config_Body_File_Name (<language>)
1519
1520                         when Name_Config_Body_File_Name =>
1521                            Lang_Index.Config.Config_Body :=
1522                              Element.Value.Value;
1523
1524                         --  Attribute Config_Body_File_Name_Index (< Language>)
1525
1526                         when Name_Config_Body_File_Name_Index =>
1527                            Lang_Index.Config.Config_Body_Index :=
1528                              Element.Value.Value;
1529
1530                         --  Attribute Config_Body_File_Name_Pattern(<language>)
1531
1532                         when Name_Config_Body_File_Name_Pattern =>
1533                            Lang_Index.Config.Config_Body_Pattern :=
1534                              Element.Value.Value;
1535
1536                            --  Attribute Config_Spec_File_Name (<language>)
1537
1538                         when Name_Config_Spec_File_Name =>
1539                            Lang_Index.Config.Config_Spec :=
1540                              Element.Value.Value;
1541
1542                         --  Attribute Config_Spec_File_Name_Index (<language>)
1543
1544                         when Name_Config_Spec_File_Name_Index =>
1545                            Lang_Index.Config.Config_Spec_Index :=
1546                              Element.Value.Value;
1547
1548                         --  Attribute Config_Spec_File_Name_Pattern(<language>)
1549
1550                         when Name_Config_Spec_File_Name_Pattern =>
1551                            Lang_Index.Config.Config_Spec_Pattern :=
1552                              Element.Value.Value;
1553
1554                         --  Attribute Config_File_Unique (<language>)
1555
1556                         when Name_Config_File_Unique =>
1557                            begin
1558                               Lang_Index.Config.Config_File_Unique :=
1559                                 Boolean'Value
1560                                   (Get_Name_String (Element.Value.Value));
1561                            exception
1562                               when Constraint_Error =>
1563                                  Error_Msg
1564                                    (Data.Flags,
1565                                     "illegal value for Config_File_Unique",
1566                                     Element.Value.Location, Project);
1567                            end;
1568
1569                         when others =>
1570                            null;
1571                         end case;
1572                      end if;
1573                   end if;
1574
1575                   Element_Id := Element.Next;
1576                end loop;
1577
1578                Current_Array_Id := Current_Array.Next;
1579             end loop;
1580          end Process_Compiler;
1581
1582          --------------------
1583          -- Process_Naming --
1584          --------------------
1585
1586          procedure Process_Naming (Attributes : Variable_Id) is
1587             Attribute_Id : Variable_Id;
1588             Attribute    : Variable;
1589
1590          begin
1591             --  Process non associated array attribute from package Naming
1592
1593             Attribute_Id := Attributes;
1594             while Attribute_Id /= No_Variable loop
1595                Attribute := Shared.Variable_Elements.Table (Attribute_Id);
1596
1597                if not Attribute.Value.Default then
1598                   if Attribute.Name = Name_Separate_Suffix then
1599
1600                      --  Attribute Separate_Suffix
1601
1602                      Get_Name_String (Attribute.Value.Value);
1603                      Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1604                      Separate_Suffix := Name_Find;
1605
1606                   elsif Attribute.Name = Name_Casing then
1607
1608                      --  Attribute Casing
1609
1610                      begin
1611                         Casing :=
1612                           Value (Get_Name_String (Attribute.Value.Value));
1613
1614                      exception
1615                         when Constraint_Error =>
1616                            Error_Msg
1617                              (Data.Flags,
1618                               "invalid value for Casing",
1619                               Attribute.Value.Location, Project);
1620                      end;
1621
1622                   elsif Attribute.Name = Name_Dot_Replacement then
1623
1624                      --  Attribute Dot_Replacement
1625
1626                      Dot_Replacement := File_Name_Type (Attribute.Value.Value);
1627
1628                   end if;
1629                end if;
1630
1631                Attribute_Id := Attribute.Next;
1632             end loop;
1633          end Process_Naming;
1634
1635          procedure Process_Naming (Arrays : Array_Id) is
1636             Current_Array_Id : Array_Id;
1637             Current_Array    : Array_Data;
1638             Element_Id       : Array_Element_Id;
1639             Element          : Array_Element;
1640
1641          begin
1642             --  Process the associative array attribute of package Naming
1643
1644             Current_Array_Id := Arrays;
1645             while Current_Array_Id /= No_Array loop
1646                Current_Array := Shared.Arrays.Table (Current_Array_Id);
1647
1648                Element_Id := Current_Array.Value;
1649                while Element_Id /= No_Array_Element loop
1650                   Element := Shared.Array_Elements.Table (Element_Id);
1651
1652                   --  Get the name of the language
1653
1654                   Lang_Index := Get_Language_From_Name
1655                     (Project, Get_Name_String (Element.Index));
1656
1657                   if Lang_Index /= No_Language_Index then
1658                      case Current_Array.Name is
1659                         when Name_Spec_Suffix | Name_Specification_Suffix =>
1660
1661                            --  Attribute Spec_Suffix (<language>)
1662
1663                            Get_Name_String (Element.Value.Value);
1664                            Canonical_Case_File_Name
1665                              (Name_Buffer (1 .. Name_Len));
1666                            Lang_Index.Config.Naming_Data.Spec_Suffix :=
1667                              Name_Find;
1668
1669                         when Name_Implementation_Suffix | Name_Body_Suffix =>
1670
1671                            Get_Name_String (Element.Value.Value);
1672                            Canonical_Case_File_Name
1673                              (Name_Buffer (1 .. Name_Len));
1674
1675                            --  Attribute Body_Suffix (<language>)
1676
1677                            Lang_Index.Config.Naming_Data.Body_Suffix :=
1678                              Name_Find;
1679                            Lang_Index.Config.Naming_Data.Separate_Suffix :=
1680                              Lang_Index.Config.Naming_Data.Body_Suffix;
1681
1682                         when others =>
1683                            null;
1684                      end case;
1685                   end if;
1686
1687                   Element_Id := Element.Next;
1688                end loop;
1689
1690                Current_Array_Id := Current_Array.Next;
1691             end loop;
1692          end Process_Naming;
1693
1694          --------------------
1695          -- Process_Linker --
1696          --------------------
1697
1698          procedure Process_Linker (Attributes : Variable_Id) is
1699             Attribute_Id : Variable_Id;
1700             Attribute    : Variable;
1701
1702          begin
1703             --  Process non associated array attribute from package Linker
1704
1705             Attribute_Id := Attributes;
1706             while Attribute_Id /= No_Variable loop
1707                Attribute := Shared.Variable_Elements.Table (Attribute_Id);
1708
1709                if not Attribute.Value.Default then
1710                   if Attribute.Name = Name_Driver then
1711
1712                      --  Attribute Linker'Driver: the default linker to use
1713
1714                      Project.Config.Linker :=
1715                        Path_Name_Type (Attribute.Value.Value);
1716
1717                      --  Linker'Driver is also used to link shared libraries
1718                      --  if the obsolescent attribute Library_GCC has not been
1719                      --  specified.
1720
1721                      if Project.Config.Shared_Lib_Driver = No_File then
1722                         Project.Config.Shared_Lib_Driver :=
1723                           File_Name_Type (Attribute.Value.Value);
1724                      end if;
1725
1726                   elsif Attribute.Name = Name_Required_Switches then
1727
1728                      --  Attribute Required_Switches: the minimum trailing
1729                      --  options to use when invoking the linker
1730
1731                      Put (Into_List =>
1732                             Project.Config.Trailing_Linker_Required_Switches,
1733                           From_List => Attribute.Value.Values,
1734                           In_Tree   => Data.Tree);
1735
1736                   elsif Attribute.Name = Name_Map_File_Option then
1737                      Project.Config.Map_File_Option := Attribute.Value.Value;
1738
1739                   elsif Attribute.Name = Name_Max_Command_Line_Length then
1740                      begin
1741                         Project.Config.Max_Command_Line_Length :=
1742                           Natural'Value (Get_Name_String
1743                                          (Attribute.Value.Value));
1744
1745                      exception
1746                         when Constraint_Error =>
1747                            Error_Msg
1748                              (Data.Flags,
1749                               "value must be positive or equal to 0",
1750                               Attribute.Value.Location, Project);
1751                      end;
1752
1753                   elsif Attribute.Name = Name_Response_File_Format then
1754                      declare
1755                         Name  : Name_Id;
1756
1757                      begin
1758                         Get_Name_String (Attribute.Value.Value);
1759                         To_Lower (Name_Buffer (1 .. Name_Len));
1760                         Name := Name_Find;
1761
1762                         if Name = Name_None then
1763                            Project.Config.Resp_File_Format := None;
1764
1765                         elsif Name = Name_Gnu then
1766                            Project.Config.Resp_File_Format := GNU;
1767
1768                         elsif Name = Name_Object_List then
1769                            Project.Config.Resp_File_Format := Object_List;
1770
1771                         elsif Name = Name_Option_List then
1772                            Project.Config.Resp_File_Format := Option_List;
1773
1774                         elsif Name_Buffer (1 .. Name_Len) = "gcc" then
1775                            Project.Config.Resp_File_Format := GCC;
1776
1777                         elsif Name_Buffer (1 .. Name_Len) = "gcc_gnu" then
1778                            Project.Config.Resp_File_Format := GCC_GNU;
1779
1780                         elsif
1781                           Name_Buffer (1 .. Name_Len) = "gcc_option_list"
1782                         then
1783                            Project.Config.Resp_File_Format := GCC_Option_List;
1784
1785                         elsif
1786                           Name_Buffer (1 .. Name_Len) = "gcc_object_list"
1787                         then
1788                            Project.Config.Resp_File_Format := GCC_Object_List;
1789
1790                         else
1791                            Error_Msg
1792                              (Data.Flags,
1793                               "illegal response file format",
1794                               Attribute.Value.Location, Project);
1795                         end if;
1796                      end;
1797
1798                   elsif Attribute.Name = Name_Response_File_Switches then
1799                      Put (Into_List => Project.Config.Resp_File_Options,
1800                           From_List => Attribute.Value.Values,
1801                           In_Tree   => Data.Tree);
1802                   end if;
1803                end if;
1804
1805                Attribute_Id := Attribute.Next;
1806             end loop;
1807          end Process_Linker;
1808
1809       --  Start of processing for Process_Packages
1810
1811       begin
1812          Packages := Project.Decl.Packages;
1813          while Packages /= No_Package loop
1814             Element := Shared.Packages.Table (Packages);
1815
1816             case Element.Name is
1817                when Name_Binder =>
1818
1819                   --  Process attributes of package Binder
1820
1821                   Process_Binder (Element.Decl.Arrays);
1822
1823                when Name_Builder =>
1824
1825                   --  Process attributes of package Builder
1826
1827                   Process_Builder (Element.Decl.Attributes);
1828
1829                when Name_Compiler =>
1830
1831                   --  Process attributes of package Compiler
1832
1833                   Process_Compiler (Element.Decl.Arrays);
1834
1835                when Name_Linker =>
1836
1837                   --  Process attributes of package Linker
1838
1839                   Process_Linker (Element.Decl.Attributes);
1840
1841                when Name_Naming =>
1842
1843                   --  Process attributes of package Naming
1844
1845                   Process_Naming (Element.Decl.Attributes);
1846                   Process_Naming (Element.Decl.Arrays);
1847
1848                when others =>
1849                   null;
1850             end case;
1851
1852             Packages := Element.Next;
1853          end loop;
1854       end Process_Packages;
1855
1856       ---------------------------------------------
1857       -- Process_Project_Level_Simple_Attributes --
1858       ---------------------------------------------
1859
1860       procedure Process_Project_Level_Simple_Attributes is
1861          Attribute_Id : Variable_Id;
1862          Attribute    : Variable;
1863          List         : String_List_Id;
1864
1865       begin
1866          --  Process non associated array attribute at project level
1867
1868          Attribute_Id := Project.Decl.Attributes;
1869          while Attribute_Id /= No_Variable loop
1870             Attribute := Shared.Variable_Elements.Table (Attribute_Id);
1871
1872             if not Attribute.Value.Default then
1873                if Attribute.Name = Name_Target then
1874
1875                   --  Attribute Target: the target specified
1876
1877                   Project.Config.Target := Attribute.Value.Value;
1878
1879                elsif Attribute.Name = Name_Library_Builder then
1880
1881                   --  Attribute Library_Builder: the application to invoke
1882                   --  to build libraries.
1883
1884                   Project.Config.Library_Builder :=
1885                     Path_Name_Type (Attribute.Value.Value);
1886
1887                elsif Attribute.Name = Name_Archive_Builder then
1888
1889                   --  Attribute Archive_Builder: the archive builder
1890                   --  (usually "ar") and its minimum options (usually "cr").
1891
1892                   List := Attribute.Value.Values;
1893
1894                   if List = Nil_String then
1895                      Error_Msg
1896                        (Data.Flags,
1897                         "archive builder cannot be null",
1898                         Attribute.Value.Location, Project);
1899                   end if;
1900
1901                   Put (Into_List => Project.Config.Archive_Builder,
1902                        From_List => List,
1903                        In_Tree   => Data.Tree);
1904
1905                elsif Attribute.Name = Name_Archive_Builder_Append_Option then
1906
1907                   --  Attribute Archive_Builder: the archive builder
1908                   --  (usually "ar") and its minimum options (usually "cr").
1909
1910                   List := Attribute.Value.Values;
1911
1912                   if List /= Nil_String then
1913                      Put
1914                        (Into_List =>
1915                           Project.Config.Archive_Builder_Append_Option,
1916                         From_List => List,
1917                         In_Tree   => Data.Tree);
1918                   end if;
1919
1920                elsif Attribute.Name = Name_Archive_Indexer then
1921
1922                   --  Attribute Archive_Indexer: the optional archive
1923                   --  indexer (usually "ranlib") with its minimum options
1924                   --  (usually none).
1925
1926                   List := Attribute.Value.Values;
1927
1928                   if List = Nil_String then
1929                      Error_Msg
1930                        (Data.Flags,
1931                         "archive indexer cannot be null",
1932                         Attribute.Value.Location, Project);
1933                   end if;
1934
1935                   Put (Into_List => Project.Config.Archive_Indexer,
1936                        From_List => List,
1937                        In_Tree   => Data.Tree);
1938
1939                elsif Attribute.Name = Name_Library_Partial_Linker then
1940
1941                   --  Attribute Library_Partial_Linker: the optional linker
1942                   --  driver with its minimum options, to partially link
1943                   --  archives.
1944
1945                   List := Attribute.Value.Values;
1946
1947                   if List = Nil_String then
1948                      Error_Msg
1949                        (Data.Flags,
1950                         "partial linker cannot be null",
1951                         Attribute.Value.Location, Project);
1952                   end if;
1953
1954                   Put (Into_List => Project.Config.Lib_Partial_Linker,
1955                        From_List => List,
1956                        In_Tree   => Data.Tree);
1957
1958                elsif Attribute.Name = Name_Library_GCC then
1959                   Project.Config.Shared_Lib_Driver :=
1960                     File_Name_Type (Attribute.Value.Value);
1961                   Error_Msg
1962                     (Data.Flags,
1963                      "?Library_'G'C'C is an obsolescent attribute, " &
1964                      "use Linker''Driver instead",
1965                      Attribute.Value.Location, Project);
1966
1967                elsif Attribute.Name = Name_Archive_Suffix then
1968                   Project.Config.Archive_Suffix :=
1969                     File_Name_Type (Attribute.Value.Value);
1970
1971                elsif Attribute.Name = Name_Linker_Executable_Option then
1972
1973                   --  Attribute Linker_Executable_Option: optional options
1974                   --  to specify an executable name. Defaults to "-o".
1975
1976                   List := Attribute.Value.Values;
1977
1978                   if List = Nil_String then
1979                      Error_Msg
1980                        (Data.Flags,
1981                         "linker executable option cannot be null",
1982                         Attribute.Value.Location, Project);
1983                   end if;
1984
1985                   Put (Into_List => Project.Config.Linker_Executable_Option,
1986                        From_List => List,
1987                        In_Tree   => Data.Tree);
1988
1989                elsif Attribute.Name = Name_Linker_Lib_Dir_Option then
1990
1991                   --  Attribute Linker_Lib_Dir_Option: optional options
1992                   --  to specify a library search directory. Defaults to
1993                   --  "-L".
1994
1995                   Get_Name_String (Attribute.Value.Value);
1996
1997                   if Name_Len = 0 then
1998                      Error_Msg
1999                        (Data.Flags,
2000                         "linker library directory option cannot be empty",
2001                         Attribute.Value.Location, Project);
2002                   end if;
2003
2004                   Project.Config.Linker_Lib_Dir_Option :=
2005                     Attribute.Value.Value;
2006
2007                elsif Attribute.Name = Name_Linker_Lib_Name_Option then
2008
2009                   --  Attribute Linker_Lib_Name_Option: optional options
2010                   --  to specify the name of a library to be linked in.
2011                   --  Defaults to "-l".
2012
2013                   Get_Name_String (Attribute.Value.Value);
2014
2015                   if Name_Len = 0 then
2016                      Error_Msg
2017                        (Data.Flags,
2018                         "linker library name option cannot be empty",
2019                         Attribute.Value.Location, Project);
2020                   end if;
2021
2022                   Project.Config.Linker_Lib_Name_Option :=
2023                     Attribute.Value.Value;
2024
2025                elsif Attribute.Name = Name_Run_Path_Option then
2026
2027                   --  Attribute Run_Path_Option: optional options to
2028                   --  specify a path for libraries.
2029
2030                   List := Attribute.Value.Values;
2031
2032                   if List /= Nil_String then
2033                      Put (Into_List => Project.Config.Run_Path_Option,
2034                           From_List => List,
2035                           In_Tree   => Data.Tree);
2036                   end if;
2037
2038                elsif Attribute.Name = Name_Run_Path_Origin then
2039                   Get_Name_String (Attribute.Value.Value);
2040
2041                   if Name_Len = 0 then
2042                      Error_Msg
2043                        (Data.Flags,
2044                         "run path origin cannot be empty",
2045                         Attribute.Value.Location, Project);
2046                   end if;
2047
2048                   Project.Config.Run_Path_Origin := Attribute.Value.Value;
2049
2050                elsif Attribute.Name = Name_Library_Install_Name_Option then
2051                   Project.Config.Library_Install_Name_Option :=
2052                     Attribute.Value.Value;
2053
2054                elsif Attribute.Name = Name_Separate_Run_Path_Options then
2055                   declare
2056                      pragma Unsuppress (All_Checks);
2057                   begin
2058                      Project.Config.Separate_Run_Path_Options :=
2059                        Boolean'Value (Get_Name_String (Attribute.Value.Value));
2060                   exception
2061                      when Constraint_Error =>
2062                         Error_Msg
2063                           (Data.Flags,
2064                            "invalid value """ &
2065                            Get_Name_String (Attribute.Value.Value) &
2066                            """ for Separate_Run_Path_Options",
2067                            Attribute.Value.Location, Project);
2068                   end;
2069
2070                elsif Attribute.Name = Name_Library_Support then
2071                   declare
2072                      pragma Unsuppress (All_Checks);
2073                   begin
2074                      Project.Config.Lib_Support :=
2075                        Library_Support'Value (Get_Name_String
2076                                               (Attribute.Value.Value));
2077                   exception
2078                      when Constraint_Error =>
2079                         Error_Msg
2080                           (Data.Flags,
2081                            "invalid value """ &
2082                            Get_Name_String (Attribute.Value.Value) &
2083                            """ for Library_Support",
2084                            Attribute.Value.Location, Project);
2085                   end;
2086
2087                elsif
2088                  Attribute.Name = Name_Library_Encapsulated_Supported
2089                then
2090                   declare
2091                      pragma Unsuppress (All_Checks);
2092                   begin
2093                      Project.Config.Lib_Encapsulated_Supported :=
2094                        Boolean'Value (Get_Name_String (Attribute.Value.Value));
2095                   exception
2096                      when Constraint_Error =>
2097                         Error_Msg
2098                           (Data.Flags,
2099                            "invalid value """
2100                              & Get_Name_String (Attribute.Value.Value)
2101                              & """ for Library_Encapsulated_Supported",
2102                            Attribute.Value.Location, Project);
2103                   end;
2104
2105                elsif Attribute.Name = Name_Shared_Library_Prefix then
2106                   Project.Config.Shared_Lib_Prefix :=
2107                     File_Name_Type (Attribute.Value.Value);
2108
2109                elsif Attribute.Name = Name_Shared_Library_Suffix then
2110                   Project.Config.Shared_Lib_Suffix :=
2111                     File_Name_Type (Attribute.Value.Value);
2112
2113                elsif Attribute.Name = Name_Symbolic_Link_Supported then
2114                   declare
2115                      pragma Unsuppress (All_Checks);
2116                   begin
2117                      Project.Config.Symbolic_Link_Supported :=
2118                        Boolean'Value (Get_Name_String
2119                                       (Attribute.Value.Value));
2120                   exception
2121                      when Constraint_Error =>
2122                         Error_Msg
2123                           (Data.Flags,
2124                            "invalid value """
2125                              & Get_Name_String (Attribute.Value.Value)
2126                              & """ for Symbolic_Link_Supported",
2127                            Attribute.Value.Location, Project);
2128                   end;
2129
2130                elsif
2131                  Attribute.Name = Name_Library_Major_Minor_Id_Supported
2132                then
2133                   declare
2134                      pragma Unsuppress (All_Checks);
2135                   begin
2136                      Project.Config.Lib_Maj_Min_Id_Supported :=
2137                        Boolean'Value (Get_Name_String
2138                                       (Attribute.Value.Value));
2139                   exception
2140                      when Constraint_Error =>
2141                         Error_Msg
2142                           (Data.Flags,
2143                            "invalid value """ &
2144                            Get_Name_String (Attribute.Value.Value) &
2145                            """ for Library_Major_Minor_Id_Supported",
2146                            Attribute.Value.Location, Project);
2147                   end;
2148
2149                elsif Attribute.Name = Name_Library_Auto_Init_Supported then
2150                   declare
2151                      pragma Unsuppress (All_Checks);
2152                   begin
2153                      Project.Config.Auto_Init_Supported :=
2154                        Boolean'Value (Get_Name_String (Attribute.Value.Value));
2155                   exception
2156                      when Constraint_Error =>
2157                         Error_Msg
2158                           (Data.Flags,
2159                            "invalid value """
2160                              & Get_Name_String (Attribute.Value.Value)
2161                              & """ for Library_Auto_Init_Supported",
2162                            Attribute.Value.Location, Project);
2163                   end;
2164
2165                elsif Attribute.Name = Name_Shared_Library_Minimum_Switches then
2166                   List := Attribute.Value.Values;
2167
2168                   if List /= Nil_String then
2169                      Put (Into_List => Project.Config.Shared_Lib_Min_Options,
2170                           From_List => List,
2171                           In_Tree   => Data.Tree);
2172                   end if;
2173
2174                elsif Attribute.Name = Name_Library_Version_Switches then
2175                   List := Attribute.Value.Values;
2176
2177                   if List /= Nil_String then
2178                      Put (Into_List => Project.Config.Lib_Version_Options,
2179                           From_List => List,
2180                           In_Tree   => Data.Tree);
2181                   end if;
2182                end if;
2183             end if;
2184
2185             Attribute_Id := Attribute.Next;
2186          end loop;
2187       end Process_Project_Level_Simple_Attributes;
2188
2189       --------------------------------------------
2190       -- Process_Project_Level_Array_Attributes --
2191       --------------------------------------------
2192
2193       procedure Process_Project_Level_Array_Attributes is
2194          Current_Array_Id : Array_Id;
2195          Current_Array    : Array_Data;
2196          Element_Id       : Array_Element_Id;
2197          Element          : Array_Element;
2198          List             : String_List_Id;
2199
2200       begin
2201          --  Process the associative array attributes at project level
2202
2203          Current_Array_Id := Project.Decl.Arrays;
2204          while Current_Array_Id /= No_Array loop
2205             Current_Array := Shared.Arrays.Table (Current_Array_Id);
2206
2207             Element_Id := Current_Array.Value;
2208             while Element_Id /= No_Array_Element loop
2209                Element := Shared.Array_Elements.Table (Element_Id);
2210
2211                --  Get the name of the language
2212
2213                Lang_Index :=
2214                  Get_Language_From_Name
2215                    (Project, Get_Name_String (Element.Index));
2216
2217                if Lang_Index /= No_Language_Index then
2218                   case Current_Array.Name is
2219                      when Name_Inherit_Source_Path =>
2220                         List := Element.Value.Values;
2221
2222                         if List /= Nil_String then
2223                            Put
2224                              (Into_List  =>
2225                                 Lang_Index.Config.Include_Compatible_Languages,
2226                               From_List  => List,
2227                               In_Tree    => Data.Tree,
2228                               Lower_Case => True);
2229                         end if;
2230
2231                      when Name_Toolchain_Description =>
2232
2233                         --  Attribute Toolchain_Description (<language>)
2234
2235                         Lang_Index.Config.Toolchain_Description :=
2236                           Element.Value.Value;
2237
2238                      when Name_Toolchain_Version =>
2239
2240                         --  Attribute Toolchain_Version (<language>)
2241
2242                         Lang_Index.Config.Toolchain_Version :=
2243                           Element.Value.Value;
2244
2245                         --  For Ada, set proper checksum computation mode
2246
2247                         if Lang_Index.Name = Name_Ada then
2248                            declare
2249                               Vers : constant String :=
2250                                        Get_Name_String (Element.Value.Value);
2251                               pragma Assert (Vers'First = 1);
2252
2253                            begin
2254                               --  Version 6.3 or earlier
2255
2256                               if Vers'Length >= 8
2257                                 and then Vers (1 .. 5) = "GNAT "
2258                                 and then Vers (7) = '.'
2259                                 and then
2260                                   (Vers (6) < '6'
2261                                     or else
2262                                       (Vers (6) = '6' and then Vers (8) < '4'))
2263                               then
2264                                  Checksum_GNAT_6_3 := True;
2265
2266                                  --  Version 5.03 or earlier
2267
2268                                  if Vers (6) < '5'
2269                                    or else (Vers (6) = '5'
2270                                              and then Vers (Vers'Last) < '4')
2271                                  then
2272                                     Checksum_GNAT_5_03 := True;
2273
2274                                     --  Version 5.02 or earlier
2275
2276                                     if Vers (6) /= '5'
2277                                       or else Vers (Vers'Last) < '3'
2278                                     then
2279                                        Checksum_Accumulate_Token_Checksum :=
2280                                          False;
2281                                     end if;
2282                                  end if;
2283                               end if;
2284                            end;
2285                         end if;
2286
2287                      when Name_Runtime_Library_Dir =>
2288
2289                         --  Attribute Runtime_Library_Dir (<language>)
2290
2291                         Lang_Index.Config.Runtime_Library_Dir :=
2292                           Element.Value.Value;
2293
2294                      when Name_Runtime_Source_Dir =>
2295
2296                         --  Attribute Runtime_Source_Dir (<language>)
2297
2298                         Lang_Index.Config.Runtime_Source_Dir :=
2299                           Element.Value.Value;
2300
2301                      when Name_Object_Generated =>
2302                         declare
2303                            pragma Unsuppress (All_Checks);
2304                            Value : Boolean;
2305
2306                         begin
2307                            Value :=
2308                              Boolean'Value
2309                                (Get_Name_String (Element.Value.Value));
2310
2311                            Lang_Index.Config.Object_Generated := Value;
2312
2313                            --  If no object is generated, no object may be
2314                            --  linked.
2315
2316                            if not Value then
2317                               Lang_Index.Config.Objects_Linked := False;
2318                            end if;
2319
2320                         exception
2321                            when Constraint_Error =>
2322                               Error_Msg
2323                                 (Data.Flags,
2324                                  "invalid value """
2325                                  & Get_Name_String (Element.Value.Value)
2326                                  & """ for Object_Generated",
2327                                  Element.Value.Location, Project);
2328                         end;
2329
2330                      when Name_Objects_Linked =>
2331                         declare
2332                            pragma Unsuppress (All_Checks);
2333                            Value : Boolean;
2334
2335                         begin
2336                            Value :=
2337                              Boolean'Value
2338                                (Get_Name_String (Element.Value.Value));
2339
2340                            --  No change if Object_Generated is False, as this
2341                            --  forces Objects_Linked to be False too.
2342
2343                            if Lang_Index.Config.Object_Generated then
2344                               Lang_Index.Config.Objects_Linked := Value;
2345                            end if;
2346
2347                         exception
2348                            when Constraint_Error =>
2349                               Error_Msg
2350                                 (Data.Flags,
2351                                  "invalid value """
2352                                  & Get_Name_String (Element.Value.Value)
2353                                  & """ for Objects_Linked",
2354                                  Element.Value.Location, Project);
2355                         end;
2356                      when others =>
2357                         null;
2358                   end case;
2359                end if;
2360
2361                Element_Id := Element.Next;
2362             end loop;
2363
2364             Current_Array_Id := Current_Array.Next;
2365          end loop;
2366       end Process_Project_Level_Array_Attributes;
2367
2368    --  Start of processing for Check_Configuration
2369
2370    begin
2371       Process_Project_Level_Simple_Attributes;
2372       Process_Project_Level_Array_Attributes;
2373       Process_Packages;
2374
2375       --  For unit based languages, set Casing, Dot_Replacement and
2376       --  Separate_Suffix in Naming_Data.
2377
2378       Lang_Index := Project.Languages;
2379       while Lang_Index /= No_Language_Index loop
2380          if Lang_Index.Config.Kind = Unit_Based then
2381             Lang_Index.Config.Naming_Data.Casing := Casing;
2382             Lang_Index.Config.Naming_Data.Dot_Replacement := Dot_Replacement;
2383
2384             if Separate_Suffix /= No_File then
2385                Lang_Index.Config.Naming_Data.Separate_Suffix :=
2386                  Separate_Suffix;
2387             end if;
2388
2389             exit;
2390          end if;
2391
2392          Lang_Index := Lang_Index.Next;
2393       end loop;
2394
2395       --  Give empty names to various prefixes/suffixes, if they have not
2396       --  been specified in the configuration.
2397
2398       if Project.Config.Archive_Suffix = No_File then
2399          Project.Config.Archive_Suffix := Empty_File;
2400       end if;
2401
2402       if Project.Config.Shared_Lib_Prefix = No_File then
2403          Project.Config.Shared_Lib_Prefix := Empty_File;
2404       end if;
2405
2406       if Project.Config.Shared_Lib_Suffix = No_File then
2407          Project.Config.Shared_Lib_Suffix := Empty_File;
2408       end if;
2409
2410       Lang_Index := Project.Languages;
2411       while Lang_Index /= No_Language_Index loop
2412
2413          --  For all languages, Compiler_Driver needs to be specified. This is
2414          --  only needed if we do intend to compile (not in GPS for instance).
2415
2416          if Data.Flags.Compiler_Driver_Mandatory
2417            and then Lang_Index.Config.Compiler_Driver = No_File
2418          then
2419             Error_Msg_Name_1 := Lang_Index.Display_Name;
2420             Error_Msg
2421               (Data.Flags,
2422                "?no compiler specified for language %%" &
2423                  ", ignoring all its sources",
2424                No_Location, Project);
2425
2426             if Lang_Index = Project.Languages then
2427                Project.Languages := Lang_Index.Next;
2428             else
2429                Prev_Index.Next := Lang_Index.Next;
2430             end if;
2431
2432          elsif Lang_Index.Config.Kind = Unit_Based then
2433             Prev_Index := Lang_Index;
2434
2435             --  For unit based languages, Dot_Replacement, Spec_Suffix and
2436             --  Body_Suffix need to be specified.
2437
2438             if Lang_Index.Config.Naming_Data.Dot_Replacement = No_File then
2439                Error_Msg
2440                  (Data.Flags,
2441                   "Dot_Replacement not specified for " &
2442                   Get_Name_String (Lang_Index.Name),
2443                   No_Location, Project);
2444             end if;
2445
2446             if Lang_Index.Config.Naming_Data.Spec_Suffix = No_File then
2447                Error_Msg
2448                  (Data.Flags,
2449                   "Spec_Suffix not specified for " &
2450                   Get_Name_String (Lang_Index.Name),
2451                   No_Location, Project);
2452             end if;
2453
2454             if Lang_Index.Config.Naming_Data.Body_Suffix = No_File then
2455                Error_Msg
2456                  (Data.Flags,
2457                   "Body_Suffix not specified for " &
2458                   Get_Name_String (Lang_Index.Name),
2459                   No_Location, Project);
2460             end if;
2461
2462          else
2463             Prev_Index := Lang_Index;
2464
2465             --  For file based languages, either Spec_Suffix or Body_Suffix
2466             --  need to be specified.
2467
2468             if Data.Flags.Require_Sources_Other_Lang
2469               and then Lang_Index.Config.Naming_Data.Spec_Suffix = No_File
2470               and then Lang_Index.Config.Naming_Data.Body_Suffix = No_File
2471             then
2472                Error_Msg_Name_1 := Lang_Index.Display_Name;
2473                Error_Msg
2474                  (Data.Flags,
2475                   "no suffixes specified for %%",
2476                   No_Location, Project);
2477             end if;
2478          end if;
2479
2480          Lang_Index := Lang_Index.Next;
2481       end loop;
2482    end Check_Configuration;
2483
2484    -------------------------------
2485    -- Check_If_Externally_Built --
2486    -------------------------------
2487
2488    procedure Check_If_Externally_Built
2489      (Project : Project_Id;
2490       Data    : in out Tree_Processing_Data)
2491    is
2492       Shared   : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
2493       Externally_Built : constant Variable_Value :=
2494                            Util.Value_Of
2495                             (Name_Externally_Built,
2496                              Project.Decl.Attributes, Shared);
2497
2498    begin
2499       if not Externally_Built.Default then
2500          Get_Name_String (Externally_Built.Value);
2501          To_Lower (Name_Buffer (1 .. Name_Len));
2502
2503          if Name_Buffer (1 .. Name_Len) = "true" then
2504             Project.Externally_Built := True;
2505
2506          elsif Name_Buffer (1 .. Name_Len) /= "false" then
2507             Error_Msg (Data.Flags,
2508                        "Externally_Built may only be true or false",
2509                        Externally_Built.Location, Project);
2510          end if;
2511       end if;
2512
2513       --  A virtual project extending an externally built project is itself
2514       --  externally built.
2515
2516       if Project.Virtual and then Project.Extends /= No_Project then
2517          Project.Externally_Built := Project.Extends.Externally_Built;
2518       end if;
2519
2520       if Project.Externally_Built then
2521          Debug_Output ("project is externally built");
2522       else
2523          Debug_Output ("project is not externally built");
2524       end if;
2525    end Check_If_Externally_Built;
2526
2527    ----------------------
2528    -- Check_Interfaces --
2529    ----------------------
2530
2531    procedure Check_Interfaces
2532      (Project : Project_Id;
2533       Data    : in out Tree_Processing_Data)
2534    is
2535       Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
2536
2537       Interfaces : constant Prj.Variable_Value :=
2538                      Prj.Util.Value_Of
2539                        (Snames.Name_Interfaces,
2540                         Project.Decl.Attributes,
2541                         Shared);
2542
2543       Library_Interface : constant Prj.Variable_Value :=
2544                             Prj.Util.Value_Of
2545                               (Snames.Name_Library_Interface,
2546                                Project.Decl.Attributes,
2547                                Shared);
2548
2549       List       : String_List_Id;
2550       Element    : String_Element;
2551       Name       : File_Name_Type;
2552       Iter       : Source_Iterator;
2553       Source     : Source_Id;
2554       Project_2  : Project_Id;
2555       Other      : Source_Id;
2556       Unit_Found : Boolean;
2557
2558       Interface_ALIs : String_List_Id := Nil_String;
2559
2560    begin
2561       if not Interfaces.Default then
2562
2563          --  Set In_Interfaces to False for all sources. It will be set to True
2564          --  later for the sources in the Interfaces list.
2565
2566          Project_2 := Project;
2567          while Project_2 /= No_Project loop
2568             Iter := For_Each_Source (Data.Tree, Project_2);
2569             loop
2570                Source := Prj.Element (Iter);
2571                exit when Source = No_Source;
2572                Source.In_Interfaces := False;
2573                Next (Iter);
2574             end loop;
2575
2576             Project_2 := Project_2.Extends;
2577          end loop;
2578
2579          List := Interfaces.Values;
2580          while List /= Nil_String loop
2581             Element := Shared.String_Elements.Table (List);
2582             Name := Canonical_Case_File_Name (Element.Value);
2583
2584             Project_2 := Project;
2585             Big_Loop : while Project_2 /= No_Project loop
2586                if Project.Qualifier = Aggregate_Library then
2587
2588                   --  For an aggregate library we want to consider sources of
2589                   --  all aggregated projects.
2590
2591                   Iter := For_Each_Source (Data.Tree);
2592
2593                else
2594                   Iter := For_Each_Source (Data.Tree, Project_2);
2595                end if;
2596
2597                loop
2598                   Source := Prj.Element (Iter);
2599                   exit when Source = No_Source;
2600
2601                   if Source.File = Name then
2602                      if not Source.Locally_Removed then
2603                         Source.In_Interfaces := True;
2604                         Source.Declared_In_Interfaces := True;
2605
2606                         Other := Other_Part (Source);
2607
2608                         if Other /= No_Source then
2609                            Other.In_Interfaces := True;
2610                            Other.Declared_In_Interfaces := True;
2611                         end if;
2612
2613                         if Source.Language.Config.Kind = Unit_Based then
2614                            if Source.Kind = Spec
2615                              and then Other_Part (Source) /= No_Source
2616                            then
2617                               Source := Other_Part (Source);
2618                            end if;
2619
2620                            String_Element_Table.Increment_Last
2621                              (Shared.String_Elements);
2622
2623                            Shared.String_Elements.Table
2624                              (String_Element_Table.Last
2625                                 (Shared.String_Elements)) :=
2626                              (Value         => Name_Id (Source.Dep_Name),
2627                               Index         => 0,
2628                               Display_Value => Name_Id (Source.Dep_Name),
2629                               Location      => No_Location,
2630                               Flag          => False,
2631                               Next          => Interface_ALIs);
2632
2633                            Interface_ALIs :=
2634                              String_Element_Table.Last
2635                                (Shared.String_Elements);
2636                         end if;
2637
2638                         Debug_Output
2639                           ("interface: ", Name_Id (Source.Path.Name));
2640                      end if;
2641
2642                      exit Big_Loop;
2643                   end if;
2644
2645                   Next (Iter);
2646                end loop;
2647
2648                Project_2 := Project_2.Extends;
2649             end loop Big_Loop;
2650
2651             if Source = No_Source then
2652                Error_Msg_File_1 := File_Name_Type (Element.Value);
2653                Error_Msg_Name_1 := Project.Name;
2654
2655                Error_Msg
2656                  (Data.Flags,
2657                   "{ cannot be an interface of project %% "
2658                   & "as it is not one of its sources",
2659                   Element.Location, Project);
2660             end if;
2661
2662             List := Element.Next;
2663          end loop;
2664
2665          Project.Interfaces_Defined := True;
2666          Project.Lib_Interface_ALIs := Interface_ALIs;
2667
2668       elsif Project.Library and then not Library_Interface.Default then
2669
2670          --  Set In_Interfaces to False for all sources. It will be set to True
2671          --  later for the sources in the Library_Interface list.
2672
2673          Project_2 := Project;
2674          while Project_2 /= No_Project loop
2675             Iter := For_Each_Source (Data.Tree, Project_2);
2676             loop
2677                Source := Prj.Element (Iter);
2678                exit when Source = No_Source;
2679                Source.In_Interfaces := False;
2680                Next (Iter);
2681             end loop;
2682
2683             Project_2 := Project_2.Extends;
2684          end loop;
2685
2686          List := Library_Interface.Values;
2687          while List /= Nil_String loop
2688             Element := Shared.String_Elements.Table (List);
2689             Get_Name_String (Element.Value);
2690             To_Lower (Name_Buffer (1 .. Name_Len));
2691             Name := Name_Find;
2692             Unit_Found := False;
2693
2694             Project_2 := Project;
2695             Big_Loop_2 : while Project_2 /= No_Project loop
2696                if Project.Qualifier = Aggregate_Library then
2697
2698                   --  For an aggregate library we want to consider sources of
2699                   --  all aggregated projects.
2700
2701                   Iter := For_Each_Source (Data.Tree);
2702
2703                else
2704                   Iter := For_Each_Source (Data.Tree, Project_2);
2705                end if;
2706
2707                loop
2708                   Source := Prj.Element (Iter);
2709                   exit when Source = No_Source;
2710
2711                   if Source.Unit /= No_Unit_Index
2712                     and then Source.Unit.Name = Name_Id (Name)
2713                   then
2714                      if not Source.Locally_Removed then
2715                         Source.In_Interfaces := True;
2716                         Source.Declared_In_Interfaces := True;
2717                         Project.Interfaces_Defined := True;
2718
2719                         Other := Other_Part (Source);
2720
2721                         if Other /= No_Source then
2722                            Other.In_Interfaces := True;
2723                            Other.Declared_In_Interfaces := True;
2724                         end if;
2725
2726                         Debug_Output
2727                           ("interface: ", Name_Id (Source.Path.Name));
2728
2729                         if Source.Kind = Spec
2730                           and then Other_Part (Source) /= No_Source
2731                         then
2732                            Source := Other_Part (Source);
2733                         end if;
2734
2735                         String_Element_Table.Increment_Last
2736                           (Shared.String_Elements);
2737
2738                         Shared.String_Elements.Table
2739                           (String_Element_Table.Last
2740                              (Shared.String_Elements)) :=
2741                           (Value         => Name_Id (Source.Dep_Name),
2742                            Index         => 0,
2743                            Display_Value => Name_Id (Source.Dep_Name),
2744                            Location      => No_Location,
2745                            Flag          => False,
2746                            Next          => Interface_ALIs);
2747
2748                         Interface_ALIs :=
2749                           String_Element_Table.Last (Shared.String_Elements);
2750                      end if;
2751
2752                      Unit_Found := True;
2753                      exit Big_Loop_2;
2754                   end if;
2755
2756                   Next (Iter);
2757                end loop;
2758
2759                Project_2 := Project_2.Extends;
2760             end loop Big_Loop_2;
2761
2762             if not Unit_Found then
2763                Error_Msg_Name_1 := Name_Id (Name);
2764
2765                Error_Msg
2766                  (Data.Flags,
2767                   "%% is not a unit of this project",
2768                   Element.Location, Project);
2769             end if;
2770
2771             List := Element.Next;
2772          end loop;
2773
2774          Project.Lib_Interface_ALIs := Interface_ALIs;
2775
2776       elsif Project.Extends /= No_Project
2777         and then Project.Extends.Interfaces_Defined
2778       then
2779          Project.Interfaces_Defined := True;
2780
2781          Iter := For_Each_Source (Data.Tree, Project);
2782          loop
2783             Source := Prj.Element (Iter);
2784             exit when Source = No_Source;
2785
2786             if not Source.Declared_In_Interfaces then
2787                Source.In_Interfaces := False;
2788             end if;
2789
2790             Next (Iter);
2791          end loop;
2792
2793          Project.Lib_Interface_ALIs := Project.Extends.Lib_Interface_ALIs;
2794       end if;
2795    end Check_Interfaces;
2796
2797    ------------------------------
2798    -- Check_Library_Attributes --
2799    ------------------------------
2800
2801    --  This procedure is awfully long (over 700 lines) should be broken up???
2802
2803    procedure Check_Library_Attributes
2804      (Project : Project_Id;
2805       Data    : in out Tree_Processing_Data)
2806    is
2807       Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
2808
2809       Attributes     : constant Prj.Variable_Id := Project.Decl.Attributes;
2810
2811       Lib_Dir        : constant Prj.Variable_Value :=
2812                          Prj.Util.Value_Of
2813                            (Snames.Name_Library_Dir, Attributes, Shared);
2814
2815       Lib_Name       : constant Prj.Variable_Value :=
2816                          Prj.Util.Value_Of
2817                            (Snames.Name_Library_Name, Attributes, Shared);
2818
2819       Lib_Standalone : constant Prj.Variable_Value :=
2820                          Prj.Util.Value_Of
2821                            (Snames.Name_Library_Standalone,
2822                             Attributes, Shared);
2823
2824       Lib_Version    : constant Prj.Variable_Value :=
2825                          Prj.Util.Value_Of
2826                            (Snames.Name_Library_Version, Attributes, Shared);
2827
2828       Lib_ALI_Dir    : constant Prj.Variable_Value :=
2829                          Prj.Util.Value_Of
2830                            (Snames.Name_Library_Ali_Dir, Attributes, Shared);
2831
2832       Lib_GCC        : constant Prj.Variable_Value :=
2833                          Prj.Util.Value_Of
2834                            (Snames.Name_Library_GCC, Attributes, Shared);
2835
2836       The_Lib_Kind   : constant Prj.Variable_Value :=
2837                          Prj.Util.Value_Of
2838                            (Snames.Name_Library_Kind, Attributes, Shared);
2839
2840       Imported_Project_List : Project_List;
2841       Continuation          : String_Access := No_Continuation_String'Access;
2842       Support_For_Libraries : Library_Support;
2843
2844       Library_Directory_Present : Boolean;
2845
2846       procedure Check_Library (Proj : Project_Id; Extends : Boolean);
2847       --  Check if an imported or extended project if also a library project
2848
2849       -------------------
2850       -- Check_Library --
2851       -------------------
2852
2853       procedure Check_Library (Proj : Project_Id; Extends : Boolean) is
2854          Src_Id : Source_Id;
2855          Iter   : Source_Iterator;
2856
2857       begin
2858          if Proj /= No_Project then
2859             if not Proj.Library then
2860
2861                --  The only not library projects that are OK are those that
2862                --  have no sources. However, header files from non-Ada
2863                --  languages are OK, as there is nothing to compile.
2864
2865                Iter := For_Each_Source (Data.Tree, Proj);
2866                loop
2867                   Src_Id := Prj.Element (Iter);
2868                   exit when Src_Id = No_Source
2869                     or else Src_Id.Language.Config.Kind /= File_Based
2870                     or else Src_Id.Kind /= Spec;
2871                   Next (Iter);
2872                end loop;
2873
2874                if Src_Id /= No_Source then
2875                   Error_Msg_Name_1 := Project.Name;
2876                   Error_Msg_Name_2 := Proj.Name;
2877
2878                   if Extends then
2879                      if Project.Library_Kind /= Static then
2880                         Error_Msg
2881                           (Data.Flags,
2882                            Continuation.all &
2883                            "shared library project %% cannot extend " &
2884                            "project %% that is not a library project",
2885                            Project.Location, Project);
2886                         Continuation := Continuation_String'Access;
2887                      end if;
2888
2889                   elsif not Unchecked_Shared_Lib_Imports
2890                     and then Project.Library_Kind /= Static
2891                   then
2892                      Error_Msg
2893                        (Data.Flags,
2894                         Continuation.all &
2895                         "shared library project %% cannot import project %% " &
2896                         "that is not a shared library project",
2897                         Project.Location, Project);
2898                      Continuation := Continuation_String'Access;
2899                   end if;
2900                end if;
2901
2902             elsif Project.Library_Kind /= Static
2903               and then not Lib_Standalone.Default
2904               and then Get_Name_String (Lib_Standalone.Value) = "encapsulated"
2905               and then Proj.Library_Kind /= Static
2906             then
2907                --  An encapsulated library must depend only on static libraries
2908
2909                Error_Msg_Name_1 := Project.Name;
2910                Error_Msg_Name_2 := Proj.Name;
2911
2912                Error_Msg
2913                  (Data.Flags,
2914                   Continuation.all &
2915                     "encapsulated library project %% cannot import shared " &
2916                     "library project %%",
2917                   Project.Location, Project);
2918                Continuation := Continuation_String'Access;
2919
2920             elsif Project.Library_Kind /= Static
2921               and then Proj.Library_Kind = Static
2922               and then
2923                 (Lib_Standalone.Default
2924                   or else
2925                     Get_Name_String (Lib_Standalone.Value) /= "encapsulated")
2926             then
2927                Error_Msg_Name_1 := Project.Name;
2928                Error_Msg_Name_2 := Proj.Name;
2929
2930                if Extends then
2931                   Error_Msg
2932                     (Data.Flags,
2933                      Continuation.all &
2934                      "shared library project %% cannot extend static " &
2935                      "library project %%",
2936                      Project.Location, Project);
2937                   Continuation := Continuation_String'Access;
2938
2939                elsif not Unchecked_Shared_Lib_Imports then
2940                   Error_Msg
2941                     (Data.Flags,
2942                      Continuation.all &
2943                      "shared library project %% cannot import static " &
2944                      "library project %%",
2945                      Project.Location, Project);
2946                   Continuation := Continuation_String'Access;
2947                end if;
2948
2949             end if;
2950          end if;
2951       end Check_Library;
2952
2953       Dir_Exists : Boolean;
2954
2955    --  Start of processing for Check_Library_Attributes
2956
2957    begin
2958       Library_Directory_Present := Lib_Dir.Value /= Empty_String;
2959
2960       --  Special case of extending project
2961
2962       if Project.Extends /= No_Project then
2963
2964          --  If the project extended is a library project, we inherit the
2965          --  library name, if it is not redefined; we check that the library
2966          --  directory is specified.
2967
2968          if Project.Extends.Library then
2969             if Project.Qualifier = Standard then
2970                Error_Msg
2971                  (Data.Flags,
2972                   "a standard project cannot extend a library project",
2973                   Project.Location, Project);
2974
2975             else
2976                if Lib_Name.Default then
2977                   Project.Library_Name := Project.Extends.Library_Name;
2978                end if;
2979
2980                if Lib_Dir.Default then
2981                   if not Project.Virtual then
2982                      Error_Msg
2983                        (Data.Flags,
2984                         "a project extending a library project must " &
2985                         "specify an attribute Library_Dir",
2986                         Project.Location, Project);
2987
2988                   else
2989                      --  For a virtual project extending a library project,
2990                      --  inherit library directory and library kind.
2991
2992                      Project.Library_Dir := Project.Extends.Library_Dir;
2993                      Library_Directory_Present := True;
2994                      Project.Library_Kind := Project.Extends.Library_Kind;
2995                   end if;
2996                end if;
2997             end if;
2998          end if;
2999       end if;
3000
3001       pragma Assert (Lib_Name.Kind = Single);
3002
3003       if Lib_Name.Value = Empty_String then
3004          if Current_Verbosity = High
3005            and then Project.Library_Name = No_Name
3006          then
3007             Debug_Indent;
3008             Write_Line ("no library name");
3009          end if;
3010
3011       else
3012          --  There is no restriction on the syntax of library names
3013
3014          Project.Library_Name := Lib_Name.Value;
3015       end if;
3016
3017       if Project.Library_Name /= No_Name then
3018          if Current_Verbosity = High then
3019             Write_Attr
3020               ("Library name: ", Get_Name_String (Project.Library_Name));
3021          end if;
3022
3023          pragma Assert (Lib_Dir.Kind = Single);
3024
3025          if not Library_Directory_Present then
3026             Debug_Output ("no library directory");
3027
3028          else
3029             --  Find path name (unless inherited), check that it is a directory
3030
3031             if Project.Library_Dir = No_Path_Information then
3032                Locate_Directory
3033                  (Project,
3034                   File_Name_Type (Lib_Dir.Value),
3035                   Path             => Project.Library_Dir,
3036                   Dir_Exists       => Dir_Exists,
3037                   Data             => Data,
3038                   Create           => "library",
3039                   Must_Exist       => False,
3040                   Location         => Lib_Dir.Location,
3041                   Externally_Built => Project.Externally_Built);
3042
3043             else
3044                Dir_Exists :=
3045                  Is_Directory
3046                    (Get_Name_String (Project.Library_Dir.Display_Name));
3047             end if;
3048
3049             if not Dir_Exists then
3050
3051                --  Get the absolute name of the library directory that
3052                --  does not exist, to report an error.
3053
3054                Err_Vars.Error_Msg_File_1 :=
3055                  File_Name_Type (Project.Library_Dir.Display_Name);
3056                Error_Msg
3057                  (Data.Flags,
3058                   "library directory { does not exist",
3059                   Lib_Dir.Location, Project);
3060
3061             --  Checks for object/source directories
3062
3063             elsif not Project.Externally_Built
3064
3065               --  An aggregate library does not have sources or objects, so
3066               --  these tests are not required in this case.
3067
3068               and then Project.Qualifier /= Aggregate_Library
3069             then
3070                --  Library directory cannot be the same as Object directory
3071
3072                if Project.Library_Dir.Name = Project.Object_Directory.Name then
3073                   Error_Msg
3074                     (Data.Flags,
3075                      "library directory cannot be the same " &
3076                      "as object directory",
3077                      Lib_Dir.Location, Project);
3078                   Project.Library_Dir := No_Path_Information;
3079
3080                else
3081                   declare
3082                      OK       : Boolean := True;
3083                      Dirs_Id  : String_List_Id;
3084                      Dir_Elem : String_Element;
3085                      Pid      : Project_List;
3086
3087                   begin
3088                      --  The library directory cannot be the same as a source
3089                      --  directory of the current project.
3090
3091                      Dirs_Id := Project.Source_Dirs;
3092                      while Dirs_Id /= Nil_String loop
3093                         Dir_Elem := Shared.String_Elements.Table (Dirs_Id);
3094                         Dirs_Id  := Dir_Elem.Next;
3095
3096                         if Project.Library_Dir.Name =
3097                           Path_Name_Type (Dir_Elem.Value)
3098                         then
3099                            Err_Vars.Error_Msg_File_1 :=
3100                              File_Name_Type (Dir_Elem.Value);
3101                            Error_Msg
3102                              (Data.Flags,
3103                               "library directory cannot be the same " &
3104                               "as source directory {",
3105                               Lib_Dir.Location, Project);
3106                            OK := False;
3107                            exit;
3108                         end if;
3109                      end loop;
3110
3111                      if OK then
3112
3113                         --  The library directory cannot be the same as a
3114                         --  source directory of another project either.
3115
3116                         Pid := Data.Tree.Projects;
3117                         Project_Loop : loop
3118                            exit Project_Loop when Pid = null;
3119
3120                            if Pid.Project /= Project then
3121                               Dirs_Id := Pid.Project.Source_Dirs;
3122
3123                               Dir_Loop : while Dirs_Id /= Nil_String loop
3124                                  Dir_Elem :=
3125                                    Shared.String_Elements.Table (Dirs_Id);
3126                                  Dirs_Id  := Dir_Elem.Next;
3127
3128                                  if Project.Library_Dir.Name =
3129                                    Path_Name_Type (Dir_Elem.Value)
3130                                  then
3131                                     Err_Vars.Error_Msg_File_1 :=
3132                                       File_Name_Type (Dir_Elem.Value);
3133                                     Err_Vars.Error_Msg_Name_1 :=
3134                                       Pid.Project.Name;
3135
3136                                     Error_Msg
3137                                       (Data.Flags,
3138                                        "library directory cannot be the same" &
3139                                        " as source directory { of project %%",
3140                                        Lib_Dir.Location, Project);
3141                                     OK := False;
3142                                     exit Project_Loop;
3143                                  end if;
3144                               end loop Dir_Loop;
3145                            end if;
3146
3147                            Pid := Pid.Next;
3148                         end loop Project_Loop;
3149                      end if;
3150
3151                      if not OK then
3152                         Project.Library_Dir := No_Path_Information;
3153
3154                      elsif Current_Verbosity = High then
3155
3156                         --  Display the Library directory in high verbosity
3157
3158                         Write_Attr
3159                           ("Library directory",
3160                            Get_Name_String (Project.Library_Dir.Display_Name));
3161                      end if;
3162                   end;
3163                end if;
3164             end if;
3165          end if;
3166
3167       end if;
3168
3169       Project.Library :=
3170         Project.Library_Dir /= No_Path_Information
3171         and then Project.Library_Name /= No_Name;
3172
3173       if Project.Extends = No_Project then
3174          case Project.Qualifier is
3175             when Standard =>
3176                if Project.Library then
3177                   Error_Msg
3178                     (Data.Flags,
3179                      "a standard project cannot be a library project",
3180                      Lib_Name.Location, Project);
3181                end if;
3182
3183             when Library | Aggregate_Library =>
3184                if not Project.Library then
3185                   if Project.Library_Name = No_Name then
3186                      Error_Msg
3187                        (Data.Flags,
3188                         "attribute Library_Name not declared",
3189                         Project.Location, Project);
3190
3191                      if not Library_Directory_Present then
3192                         Error_Msg
3193                           (Data.Flags,
3194                            "\attribute Library_Dir not declared",
3195                            Project.Location, Project);
3196                      end if;
3197
3198                   elsif Project.Library_Dir = No_Path_Information then
3199                      Error_Msg
3200                        (Data.Flags,
3201                         "attribute Library_Dir not declared",
3202                         Project.Location, Project);
3203                   end if;
3204                end if;
3205
3206             when others =>
3207                null;
3208          end case;
3209       end if;
3210
3211       if Project.Library then
3212          Support_For_Libraries := Project.Config.Lib_Support;
3213
3214          if Support_For_Libraries = Prj.None then
3215             Error_Msg
3216               (Data.Flags,
3217                "?libraries are not supported on this platform",
3218                Lib_Name.Location, Project);
3219             Project.Library := False;
3220
3221          else
3222             if Lib_ALI_Dir.Value = Empty_String then
3223                Debug_Output ("no library ALI directory specified");
3224                Project.Library_ALI_Dir := Project.Library_Dir;
3225
3226             else
3227                --  Find path name, check that it is a directory
3228
3229                Locate_Directory
3230                  (Project,
3231                   File_Name_Type (Lib_ALI_Dir.Value),
3232                   Path             => Project.Library_ALI_Dir,
3233                   Create           => "library ALI",
3234                   Dir_Exists       => Dir_Exists,
3235                   Data             => Data,
3236                   Must_Exist       => False,
3237                   Location         => Lib_ALI_Dir.Location,
3238                   Externally_Built => Project.Externally_Built);
3239
3240                if not Dir_Exists then
3241
3242                   --  Get the absolute name of the library ALI directory that
3243                   --  does not exist, to report an error.
3244
3245                   Err_Vars.Error_Msg_File_1 :=
3246                     File_Name_Type (Project.Library_ALI_Dir.Display_Name);
3247                   Error_Msg
3248                     (Data.Flags,
3249                      "library 'A'L'I directory { does not exist",
3250                      Lib_ALI_Dir.Location, Project);
3251                end if;
3252
3253                if not Project.Externally_Built
3254                  and then Project.Library_ALI_Dir /= Project.Library_Dir
3255                then
3256                   --  The library ALI directory cannot be the same as the
3257                   --  Object directory.
3258
3259                   if Project.Library_ALI_Dir = Project.Object_Directory then
3260                      Error_Msg
3261                        (Data.Flags,
3262                         "library 'A'L'I directory cannot be the same " &
3263                         "as object directory",
3264                         Lib_ALI_Dir.Location, Project);
3265                      Project.Library_ALI_Dir := No_Path_Information;
3266
3267                   else
3268                      declare
3269                         OK       : Boolean := True;
3270                         Dirs_Id  : String_List_Id;
3271                         Dir_Elem : String_Element;
3272                         Pid      : Project_List;
3273
3274                      begin
3275                         --  The library ALI directory cannot be the same as
3276                         --  a source directory of the current project.
3277
3278                         Dirs_Id := Project.Source_Dirs;
3279                         while Dirs_Id /= Nil_String loop
3280                            Dir_Elem := Shared.String_Elements.Table (Dirs_Id);
3281                            Dirs_Id  := Dir_Elem.Next;
3282
3283                            if Project.Library_ALI_Dir.Name =
3284                              Path_Name_Type (Dir_Elem.Value)
3285                            then
3286                               Err_Vars.Error_Msg_File_1 :=
3287                                 File_Name_Type (Dir_Elem.Value);
3288                               Error_Msg
3289                                 (Data.Flags,
3290                                  "library 'A'L'I directory cannot be " &
3291                                  "the same as source directory {",
3292                                  Lib_ALI_Dir.Location, Project);
3293                               OK := False;
3294                               exit;
3295                            end if;
3296                         end loop;
3297
3298                         if OK then
3299
3300                            --  The library ALI directory cannot be the same as
3301                            --  a source directory of another project either.
3302
3303                            Pid := Data.Tree.Projects;
3304                            ALI_Project_Loop : loop
3305                               exit ALI_Project_Loop when Pid = null;
3306
3307                               if Pid.Project /= Project then
3308                                  Dirs_Id := Pid.Project.Source_Dirs;
3309
3310                                  ALI_Dir_Loop :
3311                                  while Dirs_Id /= Nil_String loop
3312                                     Dir_Elem :=
3313                                       Shared.String_Elements.Table (Dirs_Id);
3314                                     Dirs_Id  := Dir_Elem.Next;
3315
3316                                     if Project.Library_ALI_Dir.Name =
3317                                         Path_Name_Type (Dir_Elem.Value)
3318                                     then
3319                                        Err_Vars.Error_Msg_File_1 :=
3320                                          File_Name_Type (Dir_Elem.Value);
3321                                        Err_Vars.Error_Msg_Name_1 :=
3322                                          Pid.Project.Name;
3323
3324                                        Error_Msg
3325                                          (Data.Flags,
3326                                           "library 'A'L'I directory cannot " &
3327                                           "be the same as source directory " &
3328                                           "{ of project %%",
3329                                           Lib_ALI_Dir.Location, Project);
3330                                        OK := False;
3331                                        exit ALI_Project_Loop;
3332                                     end if;
3333                                  end loop ALI_Dir_Loop;
3334                               end if;
3335                               Pid := Pid.Next;
3336                            end loop ALI_Project_Loop;
3337                         end if;
3338
3339                         if not OK then
3340                            Project.Library_ALI_Dir := No_Path_Information;
3341
3342                         elsif Current_Verbosity = High then
3343
3344                            --  Display Library ALI directory in high verbosity
3345
3346                            Write_Attr
3347                              ("Library ALI dir",
3348                               Get_Name_String
3349                                 (Project.Library_ALI_Dir.Display_Name));
3350                         end if;
3351                      end;
3352                   end if;
3353                end if;
3354             end if;
3355
3356             pragma Assert (Lib_Version.Kind = Single);
3357
3358             if Lib_Version.Value = Empty_String then
3359                Debug_Output ("no library version specified");
3360
3361             else
3362                Project.Lib_Internal_Name := Lib_Version.Value;
3363             end if;
3364
3365             pragma Assert (The_Lib_Kind.Kind = Single);
3366
3367             if The_Lib_Kind.Value = Empty_String then
3368                Debug_Output ("no library kind specified");
3369
3370             else
3371                Get_Name_String (The_Lib_Kind.Value);
3372
3373                declare
3374                   Kind_Name : constant String :=
3375                                 To_Lower (Name_Buffer (1 .. Name_Len));
3376
3377                   OK : Boolean := True;
3378
3379                begin
3380                   if Kind_Name = "static" then
3381                      Project.Library_Kind := Static;
3382
3383                   elsif Kind_Name = "dynamic" then
3384                      Project.Library_Kind := Dynamic;
3385
3386                   elsif Kind_Name = "relocatable" then
3387                      Project.Library_Kind := Relocatable;
3388
3389                   else
3390                      Error_Msg
3391                        (Data.Flags,
3392                         "illegal value for Library_Kind",
3393                         The_Lib_Kind.Location, Project);
3394                      OK := False;
3395                   end if;
3396
3397                   if Current_Verbosity = High and then OK then
3398                      Write_Attr ("Library kind", Kind_Name);
3399                   end if;
3400
3401                   if Project.Library_Kind /= Static then
3402                      if Support_For_Libraries = Prj.Static_Only then
3403                         Error_Msg
3404                           (Data.Flags,
3405                            "only static libraries are supported " &
3406                            "on this platform",
3407                            The_Lib_Kind.Location, Project);
3408                         Project.Library := False;
3409
3410                      else
3411                         --  Check if (obsolescent) attribute Library_GCC or
3412                         --  Linker'Driver is declared.
3413
3414                         if Lib_GCC.Value /= Empty_String then
3415                            Error_Msg
3416                              (Data.Flags,
3417                               "?Library_'G'C'C is an obsolescent attribute, " &
3418                               "use Linker''Driver instead",
3419                               Lib_GCC.Location, Project);
3420                            Project.Config.Shared_Lib_Driver :=
3421                              File_Name_Type (Lib_GCC.Value);
3422
3423                         else
3424                            declare
3425                               Linker : constant Package_Id :=
3426                                          Value_Of
3427                                            (Name_Linker,
3428                                             Project.Decl.Packages,
3429                                             Shared);
3430                               Driver : constant Variable_Value :=
3431                                          Value_Of
3432                                            (Name                 => No_Name,
3433                                             Attribute_Or_Array_Name =>
3434                                               Name_Driver,
3435                                             In_Package           => Linker,
3436                                             Shared               => Shared);
3437
3438                            begin
3439                               if Driver /= Nil_Variable_Value
3440                                  and then Driver.Value /= Empty_String
3441                               then
3442                                  Project.Config.Shared_Lib_Driver :=
3443                                    File_Name_Type (Driver.Value);
3444                               end if;
3445                            end;
3446                         end if;
3447                      end if;
3448                   end if;
3449                end;
3450             end if;
3451
3452             if Project.Library
3453               and then Project.Qualifier /= Aggregate_Library
3454             then
3455                Debug_Output ("this is a library project file");
3456
3457                Check_Library (Project.Extends, Extends => True);
3458
3459                Imported_Project_List := Project.Imported_Projects;
3460                while Imported_Project_List /= null loop
3461                   Check_Library
3462                     (Imported_Project_List.Project,
3463                      Extends => False);
3464                   Imported_Project_List := Imported_Project_List.Next;
3465                end loop;
3466             end if;
3467          end if;
3468       end if;
3469
3470       --  Check if Linker'Switches or Linker'Default_Switches are declared.
3471       --  Warn if they are declared, as it is a common error to think that
3472       --  library are "linked" with Linker switches.
3473
3474       if Project.Library then
3475          declare
3476             Linker_Package_Id : constant Package_Id :=
3477                                   Util.Value_Of
3478                                     (Name_Linker,
3479                                      Project.Decl.Packages, Shared);
3480             Linker_Package    : Package_Element;
3481             Switches          : Array_Element_Id := No_Array_Element;
3482
3483          begin
3484             if Linker_Package_Id /= No_Package then
3485                Linker_Package := Shared.Packages.Table (Linker_Package_Id);
3486
3487                Switches :=
3488                  Value_Of
3489                    (Name      => Name_Switches,
3490                     In_Arrays => Linker_Package.Decl.Arrays,
3491                     Shared    => Shared);
3492
3493                if Switches = No_Array_Element then
3494                   Switches :=
3495                     Value_Of
3496                       (Name      => Name_Default_Switches,
3497                        In_Arrays => Linker_Package.Decl.Arrays,
3498                        Shared    => Shared);
3499                end if;
3500
3501                if Switches /= No_Array_Element then
3502                   Error_Msg
3503                     (Data.Flags,
3504                      "?Linker switches not taken into account in library " &
3505                      "projects",
3506                      No_Location, Project);
3507                end if;
3508             end if;
3509          end;
3510       end if;
3511
3512       if Project.Extends /= No_Project and then Project.Extends.Library then
3513
3514          --  Remove the library name from Lib_Data_Table
3515
3516          for J in 1 .. Lib_Data_Table.Last loop
3517             if Lib_Data_Table.Table (J).Proj = Project.Extends then
3518                Lib_Data_Table.Table (J) :=
3519                  Lib_Data_Table.Table (Lib_Data_Table.Last);
3520                Lib_Data_Table.Set_Last (Lib_Data_Table.Last - 1);
3521                exit;
3522             end if;
3523          end loop;
3524       end if;
3525
3526       if Project.Library and then not Lib_Name.Default then
3527
3528          --  Check if the same library name is used in an other library project
3529
3530          for J in 1 .. Lib_Data_Table.Last loop
3531             if Lib_Data_Table.Table (J).Name = Project.Library_Name then
3532                Error_Msg_Name_1 := Lib_Data_Table.Table (J).Proj.Name;
3533                Error_Msg
3534                  (Data.Flags,
3535                   "Library name cannot be the same as in project %%",
3536                   Lib_Name.Location, Project);
3537                Project.Library := False;
3538                exit;
3539             end if;
3540          end loop;
3541       end if;
3542
3543       if Project.Library and not Data.In_Aggregate_Lib then
3544
3545          --  Record the library name
3546
3547          Lib_Data_Table.Append
3548            ((Name => Project.Library_Name, Proj => Project));
3549       end if;
3550    end Check_Library_Attributes;
3551
3552    --------------------------
3553    -- Check_Package_Naming --
3554    --------------------------
3555
3556    procedure Check_Package_Naming
3557      (Project : Project_Id;
3558       Data    : in out Tree_Processing_Data)
3559    is
3560       Shared    : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
3561       Naming_Id : constant Package_Id :=
3562                     Util.Value_Of
3563                       (Name_Naming, Project.Decl.Packages, Shared);
3564       Naming    : Package_Element;
3565
3566       Ada_Body_Suffix_Loc : Source_Ptr := No_Location;
3567
3568       procedure Check_Naming;
3569       --  Check the validity of the Naming package (suffixes valid, ...)
3570
3571       procedure Check_Common
3572         (Dot_Replacement : in out File_Name_Type;
3573          Casing          : in out Casing_Type;
3574          Casing_Defined  : out Boolean;
3575          Separate_Suffix : in out File_Name_Type;
3576          Sep_Suffix_Loc  : out Source_Ptr);
3577       --  Check attributes common
3578
3579       procedure Process_Exceptions_File_Based
3580         (Lang_Id : Language_Ptr;
3581          Kind    : Source_Kind);
3582       procedure Process_Exceptions_Unit_Based
3583         (Lang_Id : Language_Ptr;
3584          Kind    : Source_Kind);
3585       --  Process the naming exceptions for the two types of languages
3586
3587       procedure Initialize_Naming_Data;
3588       --  Initialize internal naming data for the various languages
3589
3590       ------------------
3591       -- Check_Common --
3592       ------------------
3593
3594       procedure Check_Common
3595         (Dot_Replacement : in out File_Name_Type;
3596          Casing          : in out Casing_Type;
3597          Casing_Defined  : out Boolean;
3598          Separate_Suffix : in out File_Name_Type;
3599          Sep_Suffix_Loc  : out Source_Ptr)
3600       is
3601          Dot_Repl      : constant Variable_Value :=
3602                            Util.Value_Of
3603                              (Name_Dot_Replacement,
3604                               Naming.Decl.Attributes,
3605                               Shared);
3606          Casing_String : constant Variable_Value :=
3607                            Util.Value_Of
3608                              (Name_Casing,
3609                               Naming.Decl.Attributes,
3610                               Shared);
3611          Sep_Suffix    : constant Variable_Value :=
3612                            Util.Value_Of
3613                              (Name_Separate_Suffix,
3614                               Naming.Decl.Attributes,
3615                               Shared);
3616          Dot_Repl_Loc  : Source_Ptr;
3617
3618       begin
3619          Sep_Suffix_Loc := No_Location;
3620
3621          if not Dot_Repl.Default then
3622             pragma Assert
3623               (Dot_Repl.Kind = Single, "Dot_Replacement is not a string");
3624
3625             if Length_Of_Name (Dot_Repl.Value) = 0 then
3626                Error_Msg
3627                  (Data.Flags, "Dot_Replacement cannot be empty",
3628                   Dot_Repl.Location, Project);
3629             end if;
3630
3631             Dot_Replacement := Canonical_Case_File_Name (Dot_Repl.Value);
3632             Dot_Repl_Loc    := Dot_Repl.Location;
3633
3634             declare
3635                Repl : constant String := Get_Name_String (Dot_Replacement);
3636
3637             begin
3638                --  Dot_Replacement cannot
3639                --   - be empty
3640                --   - start or end with an alphanumeric
3641                --   - be a single '_'
3642                --   - start with an '_' followed by an alphanumeric
3643                --   - contain a '.' except if it is "."
3644
3645                if Repl'Length = 0
3646                  or else Is_Alphanumeric (Repl (Repl'First))
3647                  or else Is_Alphanumeric (Repl (Repl'Last))
3648                  or else (Repl (Repl'First) = '_'
3649                            and then
3650                              (Repl'Length = 1
3651                                or else
3652                                  Is_Alphanumeric (Repl (Repl'First + 1))))
3653                  or else (Repl'Length > 1
3654                            and then
3655                              Index (Source => Repl, Pattern => ".") /= 0)
3656                then
3657                   Error_Msg
3658                     (Data.Flags,
3659                      '"' & Repl &
3660                      """ is illegal for Dot_Replacement.",
3661                      Dot_Repl_Loc, Project);
3662                end if;
3663             end;
3664          end if;
3665
3666          if Dot_Replacement /= No_File then
3667             Write_Attr
3668               ("Dot_Replacement", Get_Name_String (Dot_Replacement));
3669          end if;
3670
3671          Casing_Defined := False;
3672
3673          if not Casing_String.Default then
3674             pragma Assert
3675               (Casing_String.Kind = Single, "Casing is not a string");
3676
3677             declare
3678                Casing_Image : constant String :=
3679                                 Get_Name_String (Casing_String.Value);
3680
3681             begin
3682                if Casing_Image'Length = 0 then
3683                   Error_Msg
3684                     (Data.Flags,
3685                      "Casing cannot be an empty string",
3686                      Casing_String.Location, Project);
3687                end if;
3688
3689                Casing := Value (Casing_Image);
3690                Casing_Defined := True;
3691
3692             exception
3693                when Constraint_Error =>
3694                   Name_Len := Casing_Image'Length;
3695                   Name_Buffer (1 .. Name_Len) := Casing_Image;
3696                   Err_Vars.Error_Msg_Name_1 := Name_Find;
3697                   Error_Msg
3698                     (Data.Flags,
3699                      "%% is not a correct Casing",
3700                      Casing_String.Location, Project);
3701             end;
3702          end if;
3703
3704          Write_Attr ("Casing", Image (Casing));
3705
3706          if not Sep_Suffix.Default then
3707             if Length_Of_Name (Sep_Suffix.Value) = 0 then
3708                Error_Msg
3709                  (Data.Flags,
3710                   "Separate_Suffix cannot be empty",
3711                   Sep_Suffix.Location, Project);
3712
3713             else
3714                Separate_Suffix := Canonical_Case_File_Name (Sep_Suffix.Value);
3715                Sep_Suffix_Loc  := Sep_Suffix.Location;
3716
3717                Check_Illegal_Suffix
3718                  (Project, Separate_Suffix,
3719                   Dot_Replacement, "Separate_Suffix", Sep_Suffix.Location,
3720                   Data);
3721             end if;
3722          end if;
3723
3724          if Separate_Suffix /= No_File then
3725             Write_Attr
3726               ("Separate_Suffix", Get_Name_String (Separate_Suffix));
3727          end if;
3728       end Check_Common;
3729
3730       -----------------------------------
3731       -- Process_Exceptions_File_Based --
3732       -----------------------------------
3733
3734       procedure Process_Exceptions_File_Based
3735         (Lang_Id : Language_Ptr;
3736          Kind    : Source_Kind)
3737       is
3738          Lang           : constant Name_Id := Lang_Id.Name;
3739          Exceptions     : Array_Element_Id;
3740          Exception_List : Variable_Value;
3741          Element_Id     : String_List_Id;
3742          Element        : String_Element;
3743          File_Name      : File_Name_Type;
3744          Source         : Source_Id;
3745
3746       begin
3747          case Kind is
3748             when Impl | Sep =>
3749                Exceptions :=
3750                  Value_Of
3751                    (Name_Implementation_Exceptions,
3752                     In_Arrays => Naming.Decl.Arrays,
3753                     Shared    => Shared);
3754
3755             when Spec =>
3756                Exceptions :=
3757                  Value_Of
3758                    (Name_Specification_Exceptions,
3759                     In_Arrays => Naming.Decl.Arrays,
3760                     Shared    => Shared);
3761          end case;
3762
3763          Exception_List :=
3764            Value_Of
3765              (Index    => Lang,
3766               In_Array => Exceptions,
3767               Shared   => Shared);
3768
3769          if Exception_List /= Nil_Variable_Value then
3770             Element_Id := Exception_List.Values;
3771             while Element_Id /= Nil_String loop
3772                Element   := Shared.String_Elements.Table (Element_Id);
3773                File_Name := Canonical_Case_File_Name (Element.Value);
3774
3775                Source :=
3776                  Source_Files_Htable.Get
3777                    (Data.Tree.Source_Files_HT, File_Name);
3778                while Source /= No_Source
3779                  and then Source.Project /= Project
3780                loop
3781                   Source := Source.Next_With_File_Name;
3782                end loop;
3783
3784                if Source = No_Source then
3785                   Add_Source
3786                     (Id               => Source,
3787                      Data             => Data,
3788                      Project          => Project,
3789                      Source_Dir_Rank  => 0,
3790                      Lang_Id          => Lang_Id,
3791                      Kind             => Kind,
3792                      File_Name        => File_Name,
3793                      Display_File     => File_Name_Type (Element.Value),
3794                      Naming_Exception => Yes,
3795                      Location         => Element.Location);
3796
3797                else
3798                   --  Check if the file name is already recorded for another
3799                   --  language or another kind.
3800
3801                   if Source.Language /= Lang_Id then
3802                      Error_Msg
3803                        (Data.Flags,
3804                         "the same file cannot be a source of two languages",
3805                         Element.Location, Project);
3806
3807                   elsif Source.Kind /= Kind then
3808                      Error_Msg
3809                        (Data.Flags,
3810                         "the same file cannot be a source and a template",
3811                         Element.Location, Project);
3812                   end if;
3813
3814                   --  If the file is already recorded for the same
3815                   --  language and the same kind, it means that the file
3816                   --  name appears several times in the *_Exceptions
3817                   --  attribute; so there is nothing to do.
3818                end if;
3819
3820                Element_Id := Element.Next;
3821             end loop;
3822          end if;
3823       end Process_Exceptions_File_Based;
3824
3825       -----------------------------------
3826       -- Process_Exceptions_Unit_Based --
3827       -----------------------------------
3828
3829       procedure Process_Exceptions_Unit_Based
3830         (Lang_Id : Language_Ptr;
3831          Kind    : Source_Kind)
3832       is
3833          Exceptions : Array_Element_Id;
3834          Element    : Array_Element;
3835          Unit       : Name_Id;
3836          Index      : Int;
3837          File_Name  : File_Name_Type;
3838          Source     : Source_Id;
3839
3840          Naming_Exception : Naming_Exception_Type;
3841
3842       begin
3843          case Kind is
3844             when Impl | Sep =>
3845                Exceptions :=
3846                  Value_Of
3847                    (Name_Body,
3848                     In_Arrays => Naming.Decl.Arrays,
3849                     Shared    => Shared);
3850
3851                if Exceptions = No_Array_Element then
3852                   Exceptions :=
3853                     Value_Of
3854                       (Name_Implementation,
3855                        In_Arrays => Naming.Decl.Arrays,
3856                        Shared    => Shared);
3857                end if;
3858
3859             when Spec =>
3860                Exceptions :=
3861                  Value_Of
3862                    (Name_Spec,
3863                     In_Arrays => Naming.Decl.Arrays,
3864                     Shared    => Shared);
3865
3866                if Exceptions = No_Array_Element then
3867                   Exceptions :=
3868                     Value_Of
3869                       (Name_Specification,
3870                        In_Arrays => Naming.Decl.Arrays,
3871                        Shared    => Shared);
3872                end if;
3873          end case;
3874
3875          while Exceptions /= No_Array_Element loop
3876             Element   := Shared.Array_Elements.Table (Exceptions);
3877
3878             if Element.Restricted then
3879                Naming_Exception := Inherited;
3880             else
3881                Naming_Exception := Yes;
3882             end if;
3883
3884             File_Name := Canonical_Case_File_Name (Element.Value.Value);
3885
3886             Get_Name_String (Element.Index);
3887             To_Lower (Name_Buffer (1 .. Name_Len));
3888             Index := Element.Value.Index;
3889
3890             --  Check if it is a valid unit name
3891
3892             Get_Name_String (Element.Index);
3893             Check_Unit_Name (Name_Buffer (1 .. Name_Len), Unit);
3894
3895             if Unit = No_Name then
3896                Err_Vars.Error_Msg_Name_1 := Element.Index;
3897                Error_Msg
3898                  (Data.Flags,
3899                   "%% is not a valid unit name.",
3900                   Element.Value.Location, Project);
3901             end if;
3902
3903             if Unit /= No_Name then
3904                Add_Source
3905                  (Id               => Source,
3906                   Data             => Data,
3907                   Project          => Project,
3908                   Source_Dir_Rank  => 0,
3909                   Lang_Id          => Lang_Id,
3910                   Kind             => Kind,
3911                   File_Name        => File_Name,
3912                   Display_File     => File_Name_Type (Element.Value.Value),
3913                   Unit             => Unit,
3914                   Index            => Index,
3915                   Location         => Element.Value.Location,
3916                   Naming_Exception => Naming_Exception);
3917             end if;
3918
3919             Exceptions := Element.Next;
3920          end loop;
3921       end Process_Exceptions_Unit_Based;
3922
3923       ------------------
3924       -- Check_Naming --
3925       ------------------
3926
3927       procedure Check_Naming is
3928          Dot_Replacement : File_Name_Type :=
3929                              File_Name_Type
3930                                (First_Name_Id + Character'Pos ('-'));
3931          Separate_Suffix : File_Name_Type := No_File;
3932          Casing          : Casing_Type    := All_Lower_Case;
3933          Casing_Defined  : Boolean;
3934          Lang_Id         : Language_Ptr;
3935          Sep_Suffix_Loc  : Source_Ptr;
3936          Suffix          : Variable_Value;
3937          Lang            : Name_Id;
3938
3939       begin
3940          Check_Common
3941            (Dot_Replacement => Dot_Replacement,
3942             Casing          => Casing,
3943             Casing_Defined  => Casing_Defined,
3944             Separate_Suffix => Separate_Suffix,
3945             Sep_Suffix_Loc  => Sep_Suffix_Loc);
3946
3947          --  For all unit based languages, if any, set the specified value
3948          --  of Dot_Replacement, Casing and/or Separate_Suffix. Do not
3949          --  systematically overwrite, since the defaults come from the
3950          --  configuration file.
3951
3952          if Dot_Replacement /= No_File
3953            or else Casing_Defined
3954            or else Separate_Suffix /= No_File
3955          then
3956             Lang_Id := Project.Languages;
3957             while Lang_Id /= No_Language_Index loop
3958                if Lang_Id.Config.Kind = Unit_Based then
3959                   if Dot_Replacement /= No_File then
3960                      Lang_Id.Config.Naming_Data.Dot_Replacement :=
3961                          Dot_Replacement;
3962                   end if;
3963
3964                   if Casing_Defined then
3965                      Lang_Id.Config.Naming_Data.Casing := Casing;
3966                   end if;
3967                end if;
3968
3969                Lang_Id := Lang_Id.Next;
3970             end loop;
3971          end if;
3972
3973          --  Next, get the spec and body suffixes
3974
3975          Lang_Id := Project.Languages;
3976          while Lang_Id /= No_Language_Index loop
3977             Lang := Lang_Id.Name;
3978
3979             --  Spec_Suffix
3980
3981             Suffix := Value_Of
3982               (Name                    => Lang,
3983                Attribute_Or_Array_Name => Name_Spec_Suffix,
3984                In_Package              => Naming_Id,
3985                Shared                  => Shared);
3986
3987             if Suffix = Nil_Variable_Value then
3988                Suffix := Value_Of
3989                  (Name                    => Lang,
3990                   Attribute_Or_Array_Name => Name_Specification_Suffix,
3991                   In_Package              => Naming_Id,
3992                   Shared                  => Shared);
3993             end if;
3994
3995             if Suffix /= Nil_Variable_Value then
3996                Lang_Id.Config.Naming_Data.Spec_Suffix :=
3997                    File_Name_Type (Suffix.Value);
3998
3999                Check_Illegal_Suffix
4000                  (Project,
4001                   Lang_Id.Config.Naming_Data.Spec_Suffix,
4002                   Lang_Id.Config.Naming_Data.Dot_Replacement,
4003                   "Spec_Suffix", Suffix.Location, Data);
4004
4005                Write_Attr
4006                  ("Spec_Suffix",
4007                   Get_Name_String (Lang_Id.Config.Naming_Data.Spec_Suffix));
4008             end if;
4009
4010             --  Body_Suffix
4011
4012             Suffix :=
4013               Value_Of
4014                 (Name                    => Lang,
4015                  Attribute_Or_Array_Name => Name_Body_Suffix,
4016                  In_Package              => Naming_Id,
4017                  Shared                  => Shared);
4018
4019             if Suffix = Nil_Variable_Value then
4020                Suffix :=
4021                  Value_Of
4022                    (Name                    => Lang,
4023                     Attribute_Or_Array_Name => Name_Implementation_Suffix,
4024                     In_Package              => Naming_Id,
4025                     Shared                  => Shared);
4026             end if;
4027
4028             if Suffix /= Nil_Variable_Value then
4029                Lang_Id.Config.Naming_Data.Body_Suffix :=
4030                  File_Name_Type (Suffix.Value);
4031
4032                --  The default value of separate suffix should be the same as
4033                --  the body suffix, so we need to compute that first.
4034
4035                if Separate_Suffix = No_File then
4036                   Lang_Id.Config.Naming_Data.Separate_Suffix :=
4037                     Lang_Id.Config.Naming_Data.Body_Suffix;
4038                   Write_Attr
4039                     ("Sep_Suffix",
4040                      Get_Name_String
4041                        (Lang_Id.Config.Naming_Data.Separate_Suffix));
4042                else
4043                   Lang_Id.Config.Naming_Data.Separate_Suffix :=
4044                     Separate_Suffix;
4045                end if;
4046
4047                Check_Illegal_Suffix
4048                  (Project,
4049                   Lang_Id.Config.Naming_Data.Body_Suffix,
4050                   Lang_Id.Config.Naming_Data.Dot_Replacement,
4051                   "Body_Suffix", Suffix.Location, Data);
4052
4053                Write_Attr
4054                  ("Body_Suffix",
4055                   Get_Name_String (Lang_Id.Config.Naming_Data.Body_Suffix));
4056
4057             elsif Separate_Suffix /= No_File then
4058                Lang_Id.Config.Naming_Data.Separate_Suffix := Separate_Suffix;
4059             end if;
4060
4061             --  Spec_Suffix cannot be equal to Body_Suffix or Separate_Suffix,
4062             --  since that would cause a clear ambiguity. Note that we do allow
4063             --  a Spec_Suffix to have the same termination as one of these,
4064             --  which causes a potential ambiguity, but we resolve that by
4065             --  matching the longest possible suffix.
4066
4067             if Lang_Id.Config.Naming_Data.Spec_Suffix /= No_File
4068               and then Lang_Id.Config.Naming_Data.Spec_Suffix =
4069                        Lang_Id.Config.Naming_Data.Body_Suffix
4070             then
4071                Error_Msg
4072                  (Data.Flags,
4073                   "Body_Suffix ("""
4074                   & Get_Name_String (Lang_Id.Config.Naming_Data.Body_Suffix)
4075                   & """) cannot be the same as Spec_Suffix.",
4076                   Ada_Body_Suffix_Loc, Project);
4077             end if;
4078
4079             if Lang_Id.Config.Naming_Data.Body_Suffix /=
4080                Lang_Id.Config.Naming_Data.Separate_Suffix
4081               and then Lang_Id.Config.Naming_Data.Spec_Suffix =
4082                        Lang_Id.Config.Naming_Data.Separate_Suffix
4083             then
4084                Error_Msg
4085                  (Data.Flags,
4086                   "Separate_Suffix ("""
4087                   & Get_Name_String
4088                     (Lang_Id.Config.Naming_Data.Separate_Suffix)
4089                   & """) cannot be the same as Spec_Suffix.",
4090                   Sep_Suffix_Loc, Project);
4091             end if;
4092
4093             Lang_Id := Lang_Id.Next;
4094          end loop;
4095
4096          --  Get the naming exceptions for all languages
4097
4098          for Kind in Spec_Or_Body loop
4099             Lang_Id := Project.Languages;
4100             while Lang_Id /= No_Language_Index loop
4101                case Lang_Id.Config.Kind is
4102                   when File_Based =>
4103                      Process_Exceptions_File_Based (Lang_Id, Kind);
4104
4105                   when Unit_Based =>
4106                      Process_Exceptions_Unit_Based (Lang_Id, Kind);
4107                end case;
4108
4109                Lang_Id := Lang_Id.Next;
4110             end loop;
4111          end loop;
4112       end Check_Naming;
4113
4114       ----------------------------
4115       -- Initialize_Naming_Data --
4116       ----------------------------
4117
4118       procedure Initialize_Naming_Data is
4119          Specs : Array_Element_Id :=
4120                    Util.Value_Of
4121                      (Name_Spec_Suffix,
4122                       Naming.Decl.Arrays,
4123                       Shared);
4124
4125          Impls : Array_Element_Id :=
4126                    Util.Value_Of
4127                      (Name_Body_Suffix,
4128                       Naming.Decl.Arrays,
4129                       Shared);
4130
4131          Lang      : Language_Ptr;
4132          Lang_Name : Name_Id;
4133          Value     : Variable_Value;
4134          Extended  : Project_Id;
4135
4136       begin
4137          --  At this stage, the project already contains the default extensions
4138          --  for the various languages. We now merge those suffixes read in the
4139          --  user project, and they override the default.
4140
4141          while Specs /= No_Array_Element loop
4142             Lang_Name := Shared.Array_Elements.Table (Specs).Index;
4143             Lang :=
4144               Get_Language_From_Name
4145                 (Project, Name => Get_Name_String (Lang_Name));
4146
4147             --  An extending project inherits its parent projects' languages
4148             --  so if needed we should create entries for those languages
4149
4150             if Lang = null  then
4151                Extended := Project.Extends;
4152                while Extended /= null loop
4153                   Lang := Get_Language_From_Name
4154                     (Extended, Name => Get_Name_String (Lang_Name));
4155                   exit when Lang /= null;
4156
4157                   Extended := Extended.Extends;
4158                end loop;
4159
4160                if Lang /= null then
4161                   Lang := new Language_Data'(Lang.all);
4162                   Lang.First_Source := null;
4163                   Lang.Next := Project.Languages;
4164                   Project.Languages := Lang;
4165                end if;
4166             end if;
4167
4168             --  If language was not found in project or the projects it extends
4169
4170             if Lang = null then
4171                Debug_Output
4172                  ("ignoring spec naming data (lang. not in project): ",
4173                   Lang_Name);
4174
4175             else
4176                Value := Shared.Array_Elements.Table (Specs).Value;
4177
4178                if Value.Kind = Single then
4179                   Lang.Config.Naming_Data.Spec_Suffix :=
4180                     Canonical_Case_File_Name (Value.Value);
4181                end if;
4182             end if;
4183
4184             Specs := Shared.Array_Elements.Table (Specs).Next;
4185          end loop;
4186
4187          while Impls /= No_Array_Element loop
4188             Lang_Name := Shared.Array_Elements.Table (Impls).Index;
4189             Lang :=
4190               Get_Language_From_Name
4191                 (Project, Name => Get_Name_String (Lang_Name));
4192
4193             if Lang = null then
4194                Debug_Output
4195                  ("ignoring impl naming data (lang. not in project): ",
4196                   Lang_Name);
4197             else
4198                Value := Shared.Array_Elements.Table (Impls).Value;
4199
4200                if Lang.Name = Name_Ada then
4201                   Ada_Body_Suffix_Loc := Value.Location;
4202                end if;
4203
4204                if Value.Kind = Single then
4205                   Lang.Config.Naming_Data.Body_Suffix :=
4206                     Canonical_Case_File_Name (Value.Value);
4207                end if;
4208             end if;
4209
4210             Impls := Shared.Array_Elements.Table (Impls).Next;
4211          end loop;
4212       end Initialize_Naming_Data;
4213
4214    --  Start of processing for Check_Naming_Schemes
4215
4216    begin
4217       --  No Naming package or parsing a configuration file? nothing to do
4218
4219       if Naming_Id /= No_Package
4220         and then Project.Qualifier /= Configuration
4221       then
4222          Naming := Shared.Packages.Table (Naming_Id);
4223          Debug_Increase_Indent ("checking package Naming for ", Project.Name);
4224          Initialize_Naming_Data;
4225          Check_Naming;
4226          Debug_Decrease_Indent ("done checking package naming");
4227       end if;
4228    end Check_Package_Naming;
4229
4230    ---------------------------------
4231    -- Check_Programming_Languages --
4232    ---------------------------------
4233
4234    procedure Check_Programming_Languages
4235      (Project : Project_Id;
4236       Data    : in out Tree_Processing_Data)
4237    is
4238       Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
4239
4240       Languages   : Variable_Value := Nil_Variable_Value;
4241       Def_Lang    : Variable_Value := Nil_Variable_Value;
4242       Def_Lang_Id : Name_Id;
4243
4244       procedure Add_Language (Name, Display_Name : Name_Id);
4245       --  Add a new language to the list of languages for the project.
4246       --  Nothing is done if the language has already been defined
4247
4248       ------------------
4249       -- Add_Language --
4250       ------------------
4251
4252       procedure Add_Language (Name, Display_Name : Name_Id) is
4253          Lang : Language_Ptr;
4254
4255       begin
4256          Lang := Project.Languages;
4257          while Lang /= No_Language_Index loop
4258             if Name = Lang.Name then
4259                return;
4260             end if;
4261
4262             Lang := Lang.Next;
4263          end loop;
4264
4265          Lang              := new Language_Data'(No_Language_Data);
4266          Lang.Next         := Project.Languages;
4267          Project.Languages := Lang;
4268          Lang.Name         := Name;
4269          Lang.Display_Name := Display_Name;
4270       end Add_Language;
4271
4272    --  Start of processing for Check_Programming_Languages
4273
4274    begin
4275       Project.Languages := null;
4276       Languages :=
4277         Prj.Util.Value_Of (Name_Languages, Project.Decl.Attributes, Shared);
4278       Def_Lang :=
4279         Prj.Util.Value_Of
4280           (Name_Default_Language, Project.Decl.Attributes, Shared);
4281
4282       if Project.Source_Dirs /= Nil_String then
4283
4284          --  Check if languages are specified in this project
4285
4286          if Languages.Default then
4287
4288             --  Fail if there is no default language defined
4289
4290             if Def_Lang.Default then
4291                Error_Msg
4292                  (Data.Flags,
4293                   "no languages defined for this project",
4294                   Project.Location, Project);
4295                Def_Lang_Id := No_Name;
4296
4297             else
4298                Get_Name_String (Def_Lang.Value);
4299                To_Lower (Name_Buffer (1 .. Name_Len));
4300                Def_Lang_Id := Name_Find;
4301             end if;
4302
4303             if Def_Lang_Id /= No_Name then
4304                Get_Name_String (Def_Lang_Id);
4305                Name_Buffer (1) := GNAT.Case_Util.To_Upper (Name_Buffer (1));
4306                Add_Language
4307                  (Name         => Def_Lang_Id,
4308                   Display_Name => Name_Find);
4309             end if;
4310
4311          else
4312             declare
4313                Current : String_List_Id := Languages.Values;
4314                Element : String_Element;
4315
4316             begin
4317                --  If there are no languages declared, there are no sources
4318
4319                if Current = Nil_String then
4320                   Project.Source_Dirs := Nil_String;
4321
4322                   if Project.Qualifier = Standard then
4323                      Error_Msg
4324                        (Data.Flags,
4325                         "a standard project must have at least one language",
4326                         Languages.Location, Project);
4327                   end if;
4328
4329                else
4330                   --  Look through all the languages specified in attribute
4331                   --  Languages.
4332
4333                   while Current /= Nil_String loop
4334                      Element := Shared.String_Elements.Table (Current);
4335                      Get_Name_String (Element.Value);
4336                      To_Lower (Name_Buffer (1 .. Name_Len));
4337
4338                      Add_Language
4339                        (Name         => Name_Find,
4340                         Display_Name => Element.Value);
4341
4342                      Current := Element.Next;
4343                   end loop;
4344                end if;
4345             end;
4346          end if;
4347       end if;
4348    end Check_Programming_Languages;
4349
4350    -------------------------------
4351    -- Check_Stand_Alone_Library --
4352    -------------------------------
4353
4354    procedure Check_Stand_Alone_Library
4355      (Project : Project_Id;
4356       Data    : in out Tree_Processing_Data)
4357    is
4358       Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
4359
4360       Lib_Name            : constant Prj.Variable_Value :=
4361                               Prj.Util.Value_Of
4362                                (Snames.Name_Library_Name,
4363                                 Project.Decl.Attributes,
4364                                 Shared);
4365
4366       Lib_Standalone      : constant Prj.Variable_Value :=
4367                               Prj.Util.Value_Of
4368                                 (Snames.Name_Library_Standalone,
4369                                  Project.Decl.Attributes,
4370                                  Shared);
4371
4372       Lib_Auto_Init       : constant Prj.Variable_Value :=
4373                               Prj.Util.Value_Of
4374                                 (Snames.Name_Library_Auto_Init,
4375                                  Project.Decl.Attributes,
4376                                  Shared);
4377
4378       Lib_Src_Dir         : constant Prj.Variable_Value :=
4379                               Prj.Util.Value_Of
4380                                 (Snames.Name_Library_Src_Dir,
4381                                  Project.Decl.Attributes,
4382                                  Shared);
4383
4384       Lib_Symbol_File     : constant Prj.Variable_Value :=
4385                               Prj.Util.Value_Of
4386                                 (Snames.Name_Library_Symbol_File,
4387                                  Project.Decl.Attributes,
4388                                  Shared);
4389
4390       Lib_Symbol_Policy   : constant Prj.Variable_Value :=
4391                               Prj.Util.Value_Of
4392                                 (Snames.Name_Library_Symbol_Policy,
4393                                  Project.Decl.Attributes,
4394                                  Shared);
4395
4396       Lib_Ref_Symbol_File : constant Prj.Variable_Value :=
4397                               Prj.Util.Value_Of
4398                                 (Snames.Name_Library_Reference_Symbol_File,
4399                                  Project.Decl.Attributes,
4400                                  Shared);
4401
4402       Auto_Init_Supported : Boolean;
4403       OK                  : Boolean := True;
4404
4405    begin
4406       Auto_Init_Supported := Project.Config.Auto_Init_Supported;
4407
4408       --  It is a stand-alone library project file if there is at least one
4409       --  unit in the declared or inherited interface.
4410
4411       if Project.Lib_Interface_ALIs = Nil_String then
4412          if not Lib_Standalone.Default
4413            and then Get_Name_String (Lib_Standalone.Value) /= "no"
4414          then
4415             Error_Msg
4416               (Data.Flags,
4417                "Library_Standalone valid only if Library_Interface is set",
4418                Lib_Standalone.Location, Project);
4419          end if;
4420
4421       else
4422          if Project.Standalone_Library = No then
4423             Project.Standalone_Library := Standard;
4424          end if;
4425
4426          --  The name of a stand-alone library needs to have the syntax of an
4427          --  Ada identifier.
4428
4429          declare
4430             Name : constant String := Get_Name_String (Project.Library_Name);
4431             OK   : Boolean         := Is_Letter (Name (Name'First));
4432
4433             Underline : Boolean := False;
4434
4435          begin
4436             for J in Name'First + 1 .. Name'Last loop
4437                exit when not OK;
4438
4439                if Is_Alphanumeric (Name (J)) then
4440                   Underline := False;
4441
4442                elsif Name (J) = '_' then
4443                   if Underline then
4444                      OK := False;
4445                   else
4446                      Underline := True;
4447                   end if;
4448
4449                else
4450                   OK := False;
4451                end if;
4452             end loop;
4453
4454             OK := OK and not Underline;
4455
4456             if not OK then
4457                Error_Msg
4458                  (Data.Flags,
4459                   "Incorrect library name for a Stand-Alone Library",
4460                   Lib_Name.Location, Project);
4461                return;
4462             end if;
4463          end;
4464
4465          if Lib_Standalone.Default then
4466             Project.Standalone_Library := Standard;
4467
4468          else
4469             Get_Name_String (Lib_Standalone.Value);
4470             To_Lower (Name_Buffer (1 .. Name_Len));
4471
4472             if Name_Buffer (1 .. Name_Len) = "standard" then
4473                Project.Standalone_Library := Standard;
4474
4475             elsif Name_Buffer (1 .. Name_Len) = "encapsulated" then
4476                Project.Standalone_Library := Encapsulated;
4477
4478             elsif Name_Buffer (1 .. Name_Len) = "no" then
4479                Project.Standalone_Library := No;
4480                Error_Msg
4481                  (Data.Flags,
4482                   "wrong value for Library_Standalone "
4483                   & "when Library_Interface defined",
4484                   Lib_Standalone.Location, Project);
4485
4486             else
4487                Error_Msg
4488                  (Data.Flags,
4489                   "invalid value for attribute Library_Standalone",
4490                   Lib_Standalone.Location, Project);
4491             end if;
4492          end if;
4493
4494          --  Check value of attribute Library_Auto_Init and set Lib_Auto_Init
4495          --  accordingly.
4496
4497          if Lib_Auto_Init.Default then
4498
4499             --  If no attribute Library_Auto_Init is declared, then set auto
4500             --  init only if it is supported.
4501
4502             Project.Lib_Auto_Init := Auto_Init_Supported;
4503
4504          else
4505             Get_Name_String (Lib_Auto_Init.Value);
4506             To_Lower (Name_Buffer (1 .. Name_Len));
4507
4508             if Name_Buffer (1 .. Name_Len) = "false" then
4509                Project.Lib_Auto_Init := False;
4510
4511             elsif Name_Buffer (1 .. Name_Len) = "true" then
4512                if Auto_Init_Supported then
4513                   Project.Lib_Auto_Init := True;
4514
4515                else
4516                   --  Library_Auto_Init cannot be "true" if auto init is not
4517                   --  supported.
4518
4519                   Error_Msg
4520                     (Data.Flags,
4521                      "library auto init not supported " &
4522                      "on this platform",
4523                      Lib_Auto_Init.Location, Project);
4524                end if;
4525
4526             else
4527                Error_Msg
4528                  (Data.Flags,
4529                   "invalid value for attribute Library_Auto_Init",
4530                   Lib_Auto_Init.Location, Project);
4531             end if;
4532          end if;
4533
4534          --  If attribute Library_Src_Dir is defined and not the empty string,
4535          --  check if the directory exist and is not the object directory or
4536          --  one of the source directories. This is the directory where copies
4537          --  of the interface sources will be copied. Note that this directory
4538          --  may be the library directory.
4539
4540          if Lib_Src_Dir.Value /= Empty_String then
4541             declare
4542                Dir_Id     : constant File_Name_Type :=
4543                               File_Name_Type (Lib_Src_Dir.Value);
4544                Dir_Exists : Boolean;
4545
4546             begin
4547                Locate_Directory
4548                  (Project,
4549                   Dir_Id,
4550                   Path             => Project.Library_Src_Dir,
4551                   Dir_Exists       => Dir_Exists,
4552                   Data             => Data,
4553                   Must_Exist       => False,
4554                   Create           => "library source copy",
4555                   Location         => Lib_Src_Dir.Location,
4556                   Externally_Built => Project.Externally_Built);
4557
4558                --  If directory does not exist, report an error
4559
4560                if not Dir_Exists then
4561
4562                   --  Get the absolute name of the library directory that does
4563                   --  not exist, to report an error.
4564
4565                   Err_Vars.Error_Msg_File_1 :=
4566                     File_Name_Type (Project.Library_Src_Dir.Display_Name);
4567                   Error_Msg
4568                     (Data.Flags,
4569                      "Directory { does not exist",
4570                      Lib_Src_Dir.Location, Project);
4571
4572                   --  Report error if it is the same as the object directory
4573
4574                elsif Project.Library_Src_Dir = Project.Object_Directory then
4575                   Error_Msg
4576                     (Data.Flags,
4577                      "directory to copy interfaces cannot be " &
4578                      "the object directory",
4579                      Lib_Src_Dir.Location, Project);
4580                   Project.Library_Src_Dir := No_Path_Information;
4581
4582                else
4583                   declare
4584                      Src_Dirs : String_List_Id;
4585                      Src_Dir  : String_Element;
4586                      Pid      : Project_List;
4587
4588                   begin
4589                      --  Interface copy directory cannot be one of the source
4590                      --  directory of the current project.
4591
4592                      Src_Dirs := Project.Source_Dirs;
4593                      while Src_Dirs /= Nil_String loop
4594                         Src_Dir := Shared.String_Elements.Table (Src_Dirs);
4595
4596                         --  Report error if it is one of the source directories
4597
4598                         if Project.Library_Src_Dir.Name =
4599                              Path_Name_Type (Src_Dir.Value)
4600                         then
4601                            Error_Msg
4602                              (Data.Flags,
4603                               "directory to copy interfaces cannot " &
4604                               "be one of the source directories",
4605                               Lib_Src_Dir.Location, Project);
4606                            Project.Library_Src_Dir := No_Path_Information;
4607                            exit;
4608                         end if;
4609
4610                         Src_Dirs := Src_Dir.Next;
4611                      end loop;
4612
4613                      if Project.Library_Src_Dir /= No_Path_Information then
4614
4615                         --  It cannot be a source directory of any other
4616                         --  project either.
4617
4618                         Pid := Data.Tree.Projects;
4619                         Project_Loop : loop
4620                            exit Project_Loop when Pid = null;
4621
4622                            Src_Dirs := Pid.Project.Source_Dirs;
4623                            Dir_Loop : while Src_Dirs /= Nil_String loop
4624                               Src_Dir :=
4625                                 Shared.String_Elements.Table (Src_Dirs);
4626
4627                               --  Report error if it is one of the source
4628                               --  directories.
4629
4630                               if Project.Library_Src_Dir.Name =
4631                                 Path_Name_Type (Src_Dir.Value)
4632                               then
4633                                  Error_Msg_File_1 :=
4634                                    File_Name_Type (Src_Dir.Value);
4635                                  Error_Msg_Name_1 := Pid.Project.Name;
4636                                  Error_Msg
4637                                    (Data.Flags,
4638                                     "directory to copy interfaces cannot " &
4639                                     "be the same as source directory { of " &
4640                                     "project %%",
4641                                     Lib_Src_Dir.Location, Project);
4642                                  Project.Library_Src_Dir :=
4643                                    No_Path_Information;
4644                                  exit Project_Loop;
4645                               end if;
4646
4647                               Src_Dirs := Src_Dir.Next;
4648                            end loop Dir_Loop;
4649
4650                            Pid := Pid.Next;
4651                         end loop Project_Loop;
4652                      end if;
4653                   end;
4654
4655                   --  In high verbosity, if there is a valid Library_Src_Dir,
4656                   --  display its path name.
4657
4658                   if Project.Library_Src_Dir /= No_Path_Information
4659                     and then Current_Verbosity = High
4660                   then
4661                      Write_Attr
4662                        ("Directory to copy interfaces",
4663                         Get_Name_String (Project.Library_Src_Dir.Name));
4664                   end if;
4665                end if;
4666             end;
4667          end if;
4668
4669          --  Check the symbol related attributes
4670
4671          --  First, the symbol policy
4672
4673          if not Lib_Symbol_Policy.Default then
4674             declare
4675                Value : constant String :=
4676                          To_Lower
4677                            (Get_Name_String (Lib_Symbol_Policy.Value));
4678
4679             begin
4680                --  Symbol policy must have one of a limited number of values
4681
4682                if Value = "autonomous" or else Value = "default" then
4683                   Project.Symbol_Data.Symbol_Policy := Autonomous;
4684
4685                elsif Value = "compliant" then
4686                   Project.Symbol_Data.Symbol_Policy := Compliant;
4687
4688                elsif Value = "controlled" then
4689                   Project.Symbol_Data.Symbol_Policy := Controlled;
4690
4691                elsif Value = "restricted" then
4692                   Project.Symbol_Data.Symbol_Policy := Restricted;
4693
4694                elsif Value = "direct" then
4695                   Project.Symbol_Data.Symbol_Policy := Direct;
4696
4697                else
4698                   Error_Msg
4699                     (Data.Flags,
4700                      "illegal value for Library_Symbol_Policy",
4701                      Lib_Symbol_Policy.Location, Project);
4702                end if;
4703             end;
4704          end if;
4705
4706          --  If attribute Library_Symbol_File is not specified, symbol policy
4707          --  cannot be Restricted.
4708
4709          if Lib_Symbol_File.Default then
4710             if Project.Symbol_Data.Symbol_Policy = Restricted then
4711                Error_Msg
4712                  (Data.Flags,
4713                   "Library_Symbol_File needs to be defined when " &
4714                   "symbol policy is Restricted",
4715                   Lib_Symbol_Policy.Location, Project);
4716             end if;
4717
4718          else
4719             --  Library_Symbol_File is defined
4720
4721             Project.Symbol_Data.Symbol_File :=
4722               Path_Name_Type (Lib_Symbol_File.Value);
4723
4724             Get_Name_String (Lib_Symbol_File.Value);
4725
4726             if Name_Len = 0 then
4727                Error_Msg
4728                  (Data.Flags,
4729                   "symbol file name cannot be an empty string",
4730                   Lib_Symbol_File.Location, Project);
4731
4732             else
4733                OK := not Is_Absolute_Path (Name_Buffer (1 .. Name_Len));
4734
4735                if OK then
4736                   for J in 1 .. Name_Len loop
4737                      if Name_Buffer (J) = '/'
4738                        or else Name_Buffer (J) = Directory_Separator
4739                      then
4740                         OK := False;
4741                         exit;
4742                      end if;
4743                   end loop;
4744                end if;
4745
4746                if not OK then
4747                   Error_Msg_File_1 := File_Name_Type (Lib_Symbol_File.Value);
4748                   Error_Msg
4749                     (Data.Flags,
4750                      "symbol file name { is illegal. " &
4751                      "Name cannot include directory info.",
4752                      Lib_Symbol_File.Location, Project);
4753                end if;
4754             end if;
4755          end if;
4756
4757          --  If attribute Library_Reference_Symbol_File is not defined,
4758          --  symbol policy cannot be Compliant or Controlled.
4759
4760          if Lib_Ref_Symbol_File.Default then
4761             if Project.Symbol_Data.Symbol_Policy = Compliant
4762               or else Project.Symbol_Data.Symbol_Policy = Controlled
4763             then
4764                Error_Msg
4765                  (Data.Flags,
4766                   "a reference symbol file needs to be defined",
4767                   Lib_Symbol_Policy.Location, Project);
4768             end if;
4769
4770          else
4771             --  Library_Reference_Symbol_File is defined, check file exists
4772
4773             Project.Symbol_Data.Reference :=
4774               Path_Name_Type (Lib_Ref_Symbol_File.Value);
4775
4776             Get_Name_String (Lib_Ref_Symbol_File.Value);
4777
4778             if Name_Len = 0 then
4779                Error_Msg
4780                  (Data.Flags,
4781                   "reference symbol file name cannot be an empty string",
4782                   Lib_Symbol_File.Location, Project);
4783
4784             else
4785                if not Is_Absolute_Path (Name_Buffer (1 .. Name_Len)) then
4786                   Name_Len := 0;
4787                   Add_Str_To_Name_Buffer
4788                     (Get_Name_String (Project.Directory.Name));
4789                   Add_Str_To_Name_Buffer
4790                     (Get_Name_String (Lib_Ref_Symbol_File.Value));
4791                   Project.Symbol_Data.Reference := Name_Find;
4792                end if;
4793
4794                if not Is_Regular_File
4795                         (Get_Name_String (Project.Symbol_Data.Reference))
4796                then
4797                   Error_Msg_File_1 :=
4798                     File_Name_Type (Lib_Ref_Symbol_File.Value);
4799
4800                   --  For controlled and direct symbol policies, it is an error
4801                   --  if the reference symbol file does not exist. For other
4802                   --  symbol policies, this is just a warning
4803
4804                   Error_Msg_Warn :=
4805                     Project.Symbol_Data.Symbol_Policy /= Controlled
4806                     and then Project.Symbol_Data.Symbol_Policy /= Direct;
4807
4808                   Error_Msg
4809                     (Data.Flags,
4810                      "<library reference symbol file { does not exist",
4811                      Lib_Ref_Symbol_File.Location, Project);
4812
4813                   --  In addition in the non-controlled case, if symbol policy
4814                   --  is Compliant, it is changed to Autonomous, because there
4815                   --  is no reference to check against, and we don't want to
4816                   --  fail in this case.
4817
4818                   if Project.Symbol_Data.Symbol_Policy /= Controlled then
4819                      if Project.Symbol_Data.Symbol_Policy = Compliant then
4820                         Project.Symbol_Data.Symbol_Policy := Autonomous;
4821                      end if;
4822                   end if;
4823                end if;
4824
4825                --  If both the reference symbol file and the symbol file are
4826                --  defined, then check that they are not the same file.
4827
4828                if Project.Symbol_Data.Symbol_File /= No_Path then
4829                   Get_Name_String (Project.Symbol_Data.Symbol_File);
4830
4831                   if Name_Len > 0 then
4832                      declare
4833                         --  We do not need to pass a Directory to
4834                         --  Normalize_Pathname, since the path_information
4835                         --  already contains absolute information.
4836
4837                         Symb_Path : constant String :=
4838                                       Normalize_Pathname
4839                                         (Get_Name_String
4840                                            (Project.Object_Directory.Name) &
4841                                          Name_Buffer (1 .. Name_Len),
4842                                          Directory     => "/",
4843                                          Resolve_Links =>
4844                                            Opt.Follow_Links_For_Files);
4845                         Ref_Path  : constant String :=
4846                                       Normalize_Pathname
4847                                         (Get_Name_String
4848                                            (Project.Symbol_Data.Reference),
4849                                          Directory     => "/",
4850                                          Resolve_Links =>
4851                                            Opt.Follow_Links_For_Files);
4852                      begin
4853                         if Symb_Path = Ref_Path then
4854                            Error_Msg
4855                              (Data.Flags,
4856                               "library reference symbol file and library" &
4857                               " symbol file cannot be the same file",
4858                               Lib_Ref_Symbol_File.Location, Project);
4859                         end if;
4860                      end;
4861                   end if;
4862                end if;
4863             end if;
4864          end if;
4865       end if;
4866    end Check_Stand_Alone_Library;
4867
4868    ---------------------
4869    -- Check_Unit_Name --
4870    ---------------------
4871
4872    procedure Check_Unit_Name (Name : String; Unit : out Name_Id) is
4873       The_Name        : String := Name;
4874       Real_Name       : Name_Id;
4875       Need_Letter     : Boolean := True;
4876       Last_Underscore : Boolean := False;
4877       OK              : Boolean := The_Name'Length > 0;
4878       First           : Positive;
4879
4880       function Is_Reserved (Name : Name_Id) return Boolean;
4881       function Is_Reserved (S    : String)  return Boolean;
4882       --  Check that the given name is not an Ada 95 reserved word. The reason
4883       --  for the Ada 95 here is that we do not want to exclude the case of an
4884       --  Ada 95 unit called Interface (for example). In Ada 2005, such a unit
4885       --  name would be rejected anyway by the compiler. That means there is no
4886       --  requirement that the project file parser reject this.
4887
4888       -----------------
4889       -- Is_Reserved --
4890       -----------------
4891
4892       function Is_Reserved (S : String) return Boolean is
4893       begin
4894          Name_Len := 0;
4895          Add_Str_To_Name_Buffer (S);
4896          return Is_Reserved (Name_Find);
4897       end Is_Reserved;
4898
4899       -----------------
4900       -- Is_Reserved --
4901       -----------------
4902
4903       function Is_Reserved (Name : Name_Id) return Boolean is
4904       begin
4905          if Get_Name_Table_Byte (Name) /= 0
4906            and then Name /= Name_Project
4907            and then Name /= Name_Extends
4908            and then Name /= Name_External
4909            and then Name not in Ada_2005_Reserved_Words
4910          then
4911             Unit := No_Name;
4912             Debug_Output ("Ada reserved word: ", Name);
4913             return True;
4914
4915          else
4916             return False;
4917          end if;
4918       end Is_Reserved;
4919
4920    --  Start of processing for Check_Unit_Name
4921
4922    begin
4923       To_Lower (The_Name);
4924
4925       Name_Len := The_Name'Length;
4926       Name_Buffer (1 .. Name_Len) := The_Name;
4927
4928       --  Special cases of children of packages A, G, I and S on VMS
4929
4930       if OpenVMS_On_Target
4931         and then Name_Len > 3
4932         and then Name_Buffer (2 .. 3) = "__"
4933         and then
4934           (Name_Buffer (1) = 'a' or else
4935            Name_Buffer (1) = 'g' or else
4936            Name_Buffer (1) = 'i' or else
4937            Name_Buffer (1) = 's')
4938       then
4939          Name_Buffer (2) := '.';
4940          Name_Buffer (3 .. Name_Len - 1) := Name_Buffer (4 .. Name_Len);
4941          Name_Len := Name_Len - 1;
4942       end if;
4943
4944       Real_Name := Name_Find;
4945
4946       if Is_Reserved (Real_Name) then
4947          return;
4948       end if;
4949
4950       First := The_Name'First;
4951
4952       for Index in The_Name'Range loop
4953          if Need_Letter then
4954
4955             --  We need a letter (at the beginning, and following a dot),
4956             --  but we don't have one.
4957
4958             if Is_Letter (The_Name (Index)) then
4959                Need_Letter := False;
4960
4961             else
4962                OK := False;
4963
4964                if Current_Verbosity = High then
4965                   Debug_Indent;
4966                   Write_Int  (Types.Int (Index));
4967                   Write_Str  (": '");
4968                   Write_Char (The_Name (Index));
4969                   Write_Line ("' is not a letter.");
4970                end if;
4971
4972                exit;
4973             end if;
4974
4975          elsif Last_Underscore
4976            and then (The_Name (Index) = '_' or else The_Name (Index) = '.')
4977          then
4978             --  Two underscores are illegal, and a dot cannot follow
4979             --  an underscore.
4980
4981             OK := False;
4982
4983             if Current_Verbosity = High then
4984                Debug_Indent;
4985                Write_Int  (Types.Int (Index));
4986                Write_Str  (": '");
4987                Write_Char (The_Name (Index));
4988                Write_Line ("' is illegal here.");
4989             end if;
4990
4991             exit;
4992
4993          elsif The_Name (Index) = '.' then
4994
4995             --  First, check if the name before the dot is not a reserved word
4996
4997             if Is_Reserved (The_Name (First .. Index - 1)) then
4998                return;
4999             end if;
5000
5001             First := Index + 1;
5002
5003             --  We need a letter after a dot
5004
5005             Need_Letter := True;
5006
5007          elsif The_Name (Index) = '_' then
5008             Last_Underscore := True;
5009
5010          else
5011             --  We need an letter or a digit
5012
5013             Last_Underscore := False;
5014
5015             if not Is_Alphanumeric (The_Name (Index)) then
5016                OK := False;
5017
5018                if Current_Verbosity = High then
5019                   Debug_Indent;
5020                   Write_Int  (Types.Int (Index));
5021                   Write_Str  (": '");
5022                   Write_Char (The_Name (Index));
5023                   Write_Line ("' is not alphanumeric.");
5024                end if;
5025
5026                exit;
5027             end if;
5028          end if;
5029       end loop;
5030
5031       --  Cannot end with an underscore or a dot
5032
5033       OK := OK and then not Need_Letter and then not Last_Underscore;
5034
5035       if OK then
5036          if First /= Name'First
5037            and then Is_Reserved (The_Name (First .. The_Name'Last))
5038          then
5039             return;
5040          end if;
5041
5042          Unit := Real_Name;
5043
5044       else
5045          --  Signal a problem with No_Name
5046
5047          Unit := No_Name;
5048       end if;
5049    end Check_Unit_Name;
5050
5051    ----------------------------
5052    -- Compute_Directory_Last --
5053    ----------------------------
5054
5055    function Compute_Directory_Last (Dir : String) return Natural is
5056    begin
5057       if Dir'Length > 1
5058         and then (Dir (Dir'Last - 1) = Directory_Separator
5059                     or else
5060                   Dir (Dir'Last - 1) = '/')
5061       then
5062          return Dir'Last - 1;
5063       else
5064          return Dir'Last;
5065       end if;
5066    end Compute_Directory_Last;
5067
5068    ---------------------
5069    -- Get_Directories --
5070    ---------------------
5071
5072    procedure Get_Directories
5073      (Project : Project_Id;
5074       Data    : in out Tree_Processing_Data)
5075    is
5076       Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
5077
5078       Object_Dir  : constant Variable_Value :=
5079                       Util.Value_Of
5080                         (Name_Object_Dir, Project.Decl.Attributes, Shared);
5081
5082       Exec_Dir : constant Variable_Value :=
5083                    Util.Value_Of
5084                      (Name_Exec_Dir, Project.Decl.Attributes, Shared);
5085
5086       Source_Dirs : constant Variable_Value :=
5087                       Util.Value_Of
5088                         (Name_Source_Dirs, Project.Decl.Attributes, Shared);
5089
5090       Ignore_Source_Sub_Dirs : constant Variable_Value :=
5091                                  Util.Value_Of
5092                                    (Name_Ignore_Source_Sub_Dirs,
5093                                     Project.Decl.Attributes,
5094                                     Shared);
5095
5096       Excluded_Source_Dirs : constant Variable_Value :=
5097                               Util.Value_Of
5098                                 (Name_Excluded_Source_Dirs,
5099                                  Project.Decl.Attributes,
5100                                  Shared);
5101
5102       Source_Files : constant Variable_Value :=
5103                       Util.Value_Of
5104                         (Name_Source_Files,
5105                          Project.Decl.Attributes, Shared);
5106
5107       Last_Source_Dir   : String_List_Id    := Nil_String;
5108       Last_Src_Dir_Rank : Number_List_Index := No_Number_List;
5109
5110       Languages : constant Variable_Value :=
5111                       Prj.Util.Value_Of
5112                         (Name_Languages, Project.Decl.Attributes, Shared);
5113
5114       Remove_Source_Dirs : Boolean := False;
5115
5116       procedure Add_To_Or_Remove_From_Source_Dirs
5117         (Path : Path_Information;
5118          Rank : Natural);
5119       --  When Removed = False, the directory Path_Id to the list of
5120       --  source_dirs if not already in the list. When Removed = True,
5121       --  removed directory Path_Id if in the list.
5122
5123       procedure Find_Source_Dirs is new Expand_Subdirectory_Pattern
5124         (Add_To_Or_Remove_From_Source_Dirs);
5125
5126       ---------------------------------------
5127       -- Add_To_Or_Remove_From_Source_Dirs --
5128       ---------------------------------------
5129
5130       procedure Add_To_Or_Remove_From_Source_Dirs
5131         (Path : Path_Information;
5132          Rank : Natural)
5133       is
5134          List      : String_List_Id;
5135          Prev      : String_List_Id;
5136          Rank_List : Number_List_Index;
5137          Prev_Rank : Number_List_Index;
5138          Element   : String_Element;
5139
5140       begin
5141          Prev      := Nil_String;
5142          Prev_Rank := No_Number_List;
5143          List      := Project.Source_Dirs;
5144          Rank_List := Project.Source_Dir_Ranks;
5145          while List /= Nil_String loop
5146             Element := Shared.String_Elements.Table (List);
5147             exit when Element.Value = Name_Id (Path.Name);
5148             Prev := List;
5149             List := Element.Next;
5150             Prev_Rank := Rank_List;
5151             Rank_List := Shared.Number_Lists.Table (Prev_Rank).Next;
5152          end loop;
5153
5154          --  The directory is in the list if List is not Nil_String
5155
5156          if not Remove_Source_Dirs and then List = Nil_String then
5157             Debug_Output ("adding source dir=", Name_Id (Path.Display_Name));
5158
5159             String_Element_Table.Increment_Last (Shared.String_Elements);
5160             Element :=
5161               (Value         => Name_Id (Path.Name),
5162                Index         => 0,
5163                Display_Value => Name_Id (Path.Display_Name),
5164                Location      => No_Location,
5165                Flag          => False,
5166                Next          => Nil_String);
5167
5168             Number_List_Table.Increment_Last (Shared.Number_Lists);
5169
5170             if Last_Source_Dir = Nil_String then
5171
5172                --  This is the first source directory
5173
5174                Project.Source_Dirs :=
5175                  String_Element_Table.Last (Shared.String_Elements);
5176                Project.Source_Dir_Ranks :=
5177                  Number_List_Table.Last (Shared.Number_Lists);
5178
5179             else
5180                --  We already have source directories, link the previous
5181                --  last to the new one.
5182
5183                Shared.String_Elements.Table (Last_Source_Dir).Next :=
5184                  String_Element_Table.Last (Shared.String_Elements);
5185                Shared.Number_Lists.Table (Last_Src_Dir_Rank).Next :=
5186                  Number_List_Table.Last (Shared.Number_Lists);
5187             end if;
5188
5189             --  And register this source directory as the new last
5190
5191             Last_Source_Dir :=
5192               String_Element_Table.Last (Shared.String_Elements);
5193             Shared.String_Elements.Table (Last_Source_Dir) := Element;
5194             Last_Src_Dir_Rank := Number_List_Table.Last (Shared.Number_Lists);
5195             Shared.Number_Lists.Table (Last_Src_Dir_Rank) :=
5196               (Number => Rank, Next => No_Number_List);
5197
5198          elsif Remove_Source_Dirs and then List /= Nil_String then
5199
5200             --  Remove source dir if present
5201
5202             if Prev = Nil_String then
5203                Project.Source_Dirs := Shared.String_Elements.Table (List).Next;
5204                Project.Source_Dir_Ranks :=
5205                  Shared.Number_Lists.Table (Rank_List).Next;
5206
5207             else
5208                Shared.String_Elements.Table (Prev).Next :=
5209                  Shared.String_Elements.Table (List).Next;
5210                Shared.Number_Lists.Table (Prev_Rank).Next :=
5211                  Shared.Number_Lists.Table (Rank_List).Next;
5212             end if;
5213          end if;
5214       end Add_To_Or_Remove_From_Source_Dirs;
5215
5216       --  Local declarations
5217
5218       Dir_Exists : Boolean;
5219
5220       No_Sources : constant Boolean :=
5221                      ((not Source_Files.Default
5222                         and then Source_Files.Values = Nil_String)
5223                       or else
5224                         (not Source_Dirs.Default
5225                           and then Source_Dirs.Values = Nil_String)
5226                       or else
5227                         (not Languages.Default
5228                           and then Languages.Values = Nil_String))
5229                      and then Project.Extends = No_Project;
5230
5231    --  Start of processing for Get_Directories
5232
5233    begin
5234       Debug_Output ("starting to look for directories");
5235
5236       --  Set the object directory to its default which may be nil, if there
5237       --  is no sources in the project.
5238
5239       if No_Sources then
5240          Project.Object_Directory := No_Path_Information;
5241       else
5242          Project.Object_Directory := Project.Directory;
5243       end if;
5244
5245       --  Check the object directory
5246
5247       if Object_Dir.Value /= Empty_String then
5248          Get_Name_String (Object_Dir.Value);
5249
5250          if Name_Len = 0 then
5251             Error_Msg
5252               (Data.Flags,
5253                "Object_Dir cannot be empty",
5254                Object_Dir.Location, Project);
5255
5256          elsif Setup_Projects
5257            and then No_Sources
5258            and then Project.Extends = No_Project
5259          then
5260             --  Do not create an object directory for a non extending project
5261             --  with no sources.
5262
5263             Locate_Directory
5264               (Project,
5265                File_Name_Type (Object_Dir.Value),
5266                Path             => Project.Object_Directory,
5267                Dir_Exists       => Dir_Exists,
5268                Data             => Data,
5269                Location         => Object_Dir.Location,
5270                Must_Exist       => False,
5271                Externally_Built => Project.Externally_Built);
5272
5273          else
5274             --  We check that the specified object directory does exist.
5275             --  However, even when it doesn't exist, we set it to a default
5276             --  value. This is for the benefit of tools that recover from
5277             --  errors; for example, these tools could create the non existent
5278             --  directory. We always return an absolute directory name though.
5279
5280             Locate_Directory
5281               (Project,
5282                File_Name_Type (Object_Dir.Value),
5283                Path             => Project.Object_Directory,
5284                Create           => "object",
5285                Dir_Exists       => Dir_Exists,
5286                Data             => Data,
5287                Location         => Object_Dir.Location,
5288                Must_Exist       => False,
5289                Externally_Built => Project.Externally_Built);
5290
5291             if not Dir_Exists and then not Project.Externally_Built then
5292
5293                --  The object directory does not exist, report an error if the
5294                --  project is not externally built.
5295
5296                Err_Vars.Error_Msg_File_1 :=
5297                  File_Name_Type (Object_Dir.Value);
5298                Error_Or_Warning
5299                  (Data.Flags, Data.Flags.Require_Obj_Dirs,
5300                   "object directory { not found", Project.Location, Project);
5301             end if;
5302          end if;
5303
5304       elsif not No_Sources and then Subdirs /= null then
5305          Name_Len := 1;
5306          Name_Buffer (1) := '.';
5307          Locate_Directory
5308            (Project,
5309             Name_Find,
5310             Path             => Project.Object_Directory,
5311             Create           => "object",
5312             Dir_Exists       => Dir_Exists,
5313             Data             => Data,
5314             Location         => Object_Dir.Location,
5315             Externally_Built => Project.Externally_Built);
5316       end if;
5317
5318       if Current_Verbosity = High then
5319          if Project.Object_Directory = No_Path_Information then
5320             Debug_Output ("no object directory");
5321          else
5322             Write_Attr
5323               ("Object directory",
5324                Get_Name_String (Project.Object_Directory.Display_Name));
5325          end if;
5326       end if;
5327
5328       --  Check the exec directory
5329
5330       --  We set the object directory to its default
5331
5332       Project.Exec_Directory := Project.Object_Directory;
5333
5334       if Exec_Dir.Value /= Empty_String then
5335          Get_Name_String (Exec_Dir.Value);
5336
5337          if Name_Len = 0 then
5338             Error_Msg
5339               (Data.Flags,
5340                "Exec_Dir cannot be empty",
5341                Exec_Dir.Location, Project);
5342
5343          elsif Setup_Projects
5344            and then No_Sources
5345            and then Project.Extends = No_Project
5346          then
5347             --  Do not create an exec directory for a non extending project
5348             --  with no sources.
5349
5350             Locate_Directory
5351               (Project,
5352                File_Name_Type (Exec_Dir.Value),
5353                Path             => Project.Exec_Directory,
5354                Dir_Exists       => Dir_Exists,
5355                Data             => Data,
5356                Location         => Exec_Dir.Location,
5357                Externally_Built => Project.Externally_Built);
5358
5359          else
5360             --  We check that the specified exec directory does exist
5361
5362             Locate_Directory
5363               (Project,
5364                File_Name_Type (Exec_Dir.Value),
5365                Path             => Project.Exec_Directory,
5366                Dir_Exists       => Dir_Exists,
5367                Data             => Data,
5368                Create           => "exec",
5369                Location         => Exec_Dir.Location,
5370                Externally_Built => Project.Externally_Built);
5371
5372             if not Dir_Exists then
5373                Err_Vars.Error_Msg_File_1 := File_Name_Type (Exec_Dir.Value);
5374                Error_Or_Warning
5375                  (Data.Flags, Data.Flags.Missing_Source_Files,
5376                   "exec directory { not found", Project.Location, Project);
5377             end if;
5378          end if;
5379       end if;
5380
5381       if Current_Verbosity = High then
5382          if Project.Exec_Directory = No_Path_Information then
5383             Debug_Output ("no exec directory");
5384          else
5385             Debug_Output
5386               ("exec directory: ",
5387                Name_Id (Project.Exec_Directory.Display_Name));
5388          end if;
5389       end if;
5390
5391       --  Look for the source directories
5392
5393       Debug_Output ("starting to look for source directories");
5394
5395       pragma Assert (Source_Dirs.Kind = List, "Source_Dirs is not a list");
5396
5397       if not Source_Files.Default
5398         and then Source_Files.Values = Nil_String
5399       then
5400          Project.Source_Dirs := Nil_String;
5401
5402          if Project.Qualifier = Standard then
5403             Error_Msg
5404               (Data.Flags,
5405                "a standard project cannot have no sources",
5406                Source_Files.Location, Project);
5407          end if;
5408
5409       elsif Source_Dirs.Default then
5410
5411          --  No Source_Dirs specified: the single source directory is the one
5412          --  containing the project file.
5413
5414          Remove_Source_Dirs := False;
5415          Add_To_Or_Remove_From_Source_Dirs
5416            (Path => (Name         => Project.Directory.Name,
5417                      Display_Name => Project.Directory.Display_Name),
5418             Rank => 1);
5419
5420       else
5421          Remove_Source_Dirs := False;
5422          Find_Source_Dirs
5423            (Project       => Project,
5424             Data          => Data,
5425             Patterns      => Source_Dirs.Values,
5426             Ignore        => Ignore_Source_Sub_Dirs.Values,
5427             Search_For    => Search_Directories,
5428             Resolve_Links => Opt.Follow_Links_For_Dirs);
5429
5430          if Project.Source_Dirs = Nil_String
5431            and then Project.Qualifier = Standard
5432          then
5433             Error_Msg
5434               (Data.Flags,
5435                "a standard project cannot have no source directories",
5436                Source_Dirs.Location, Project);
5437          end if;
5438       end if;
5439
5440       if not Excluded_Source_Dirs.Default
5441         and then Excluded_Source_Dirs.Values /= Nil_String
5442       then
5443          Remove_Source_Dirs := True;
5444          Find_Source_Dirs
5445            (Project       => Project,
5446             Data          => Data,
5447             Patterns      => Excluded_Source_Dirs.Values,
5448             Ignore        => Nil_String,
5449             Search_For    => Search_Directories,
5450             Resolve_Links => Opt.Follow_Links_For_Dirs);
5451       end if;
5452
5453       Debug_Output ("putting source directories in canonical cases");
5454
5455       declare
5456          Current : String_List_Id := Project.Source_Dirs;
5457          Element : String_Element;
5458
5459       begin
5460          while Current /= Nil_String loop
5461             Element := Shared.String_Elements.Table (Current);
5462             if Element.Value /= No_Name then
5463                Element.Value :=
5464                  Name_Id (Canonical_Case_File_Name (Element.Value));
5465                Shared.String_Elements.Table (Current) := Element;
5466             end if;
5467
5468             Current := Element.Next;
5469          end loop;
5470       end;
5471    end Get_Directories;
5472
5473    ---------------
5474    -- Get_Mains --
5475    ---------------
5476
5477    procedure Get_Mains
5478      (Project : Project_Id;
5479       Data    : in out Tree_Processing_Data)
5480    is
5481       Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
5482
5483       Mains : constant Variable_Value :=
5484                Prj.Util.Value_Of
5485                  (Name_Main, Project.Decl.Attributes, Shared);
5486       List  : String_List_Id;
5487       Elem  : String_Element;
5488
5489    begin
5490       Project.Mains := Mains.Values;
5491
5492       --  If no Mains were specified, and if we are an extending project,
5493       --  inherit the Mains from the project we are extending.
5494
5495       if Mains.Default then
5496          if not Project.Library and then Project.Extends /= No_Project then
5497             Project.Mains := Project.Extends.Mains;
5498          end if;
5499
5500       --  In a library project file, Main cannot be specified
5501
5502       elsif Project.Library then
5503          Error_Msg
5504            (Data.Flags,
5505             "a library project file cannot have Main specified",
5506             Mains.Location, Project);
5507
5508       else
5509          List := Mains.Values;
5510          while List /= Nil_String loop
5511             Elem := Shared.String_Elements.Table (List);
5512
5513             if Length_Of_Name (Elem.Value) = 0 then
5514                Error_Msg
5515                  (Data.Flags,
5516                   "?a main cannot have an empty name",
5517                   Elem.Location, Project);
5518                exit;
5519             end if;
5520
5521             List := Elem.Next;
5522          end loop;
5523       end if;
5524    end Get_Mains;
5525
5526    ---------------------------
5527    -- Get_Sources_From_File --
5528    ---------------------------
5529
5530    procedure Get_Sources_From_File
5531      (Path     : String;
5532       Location : Source_Ptr;
5533       Project  : in out Project_Processing_Data;
5534       Data     : in out Tree_Processing_Data)
5535    is
5536       File        : Prj.Util.Text_File;
5537       Line        : String (1 .. 250);
5538       Last        : Natural;
5539       Source_Name : File_Name_Type;
5540       Name_Loc    : Name_Location;
5541
5542    begin
5543       if Current_Verbosity = High then
5544          Debug_Output ("opening """ & Path & '"');
5545       end if;
5546
5547       --  Open the file
5548
5549       Prj.Util.Open (File, Path);
5550
5551       if not Prj.Util.Is_Valid (File) then
5552          Error_Msg
5553            (Data.Flags, "file does not exist", Location, Project.Project);
5554
5555       else
5556          --  Read the lines one by one
5557
5558          while not Prj.Util.End_Of_File (File) loop
5559             Prj.Util.Get_Line (File, Line, Last);
5560
5561             --  A non empty, non comment line should contain a file name
5562
5563             if Last /= 0
5564               and then (Last = 1 or else Line (1 .. 2) /= "--")
5565             then
5566                Name_Len := Last;
5567                Name_Buffer (1 .. Name_Len) := Line (1 .. Last);
5568                Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
5569                Source_Name := Name_Find;
5570
5571                --  Check that there is no directory information
5572
5573                for J in 1 .. Last loop
5574                   if Line (J) = '/' or else Line (J) = Directory_Separator then
5575                      Error_Msg_File_1 := Source_Name;
5576                      Error_Msg
5577                        (Data.Flags,
5578                         "file name cannot include directory information ({)",
5579                         Location, Project.Project);
5580                      exit;
5581                   end if;
5582                end loop;
5583
5584                Name_Loc := Source_Names_Htable.Get
5585                  (Project.Source_Names, Source_Name);
5586
5587                if Name_Loc = No_Name_Location then
5588                   Name_Loc :=
5589                     (Name     => Source_Name,
5590                      Location => Location,
5591                      Source   => No_Source,
5592                      Listed   => True,
5593                      Found    => False);
5594
5595                else
5596                   Name_Loc.Listed := True;
5597                end if;
5598
5599                Source_Names_Htable.Set
5600                  (Project.Source_Names, Source_Name, Name_Loc);
5601             end if;
5602          end loop;
5603
5604          Prj.Util.Close (File);
5605
5606       end if;
5607    end Get_Sources_From_File;
5608
5609    ------------------
5610    -- No_Space_Img --
5611    ------------------
5612
5613    function No_Space_Img (N : Natural) return String is
5614       Image : constant String := N'Img;
5615    begin
5616       return Image (2 .. Image'Last);
5617    end No_Space_Img;
5618
5619    -----------------------
5620    -- Compute_Unit_Name --
5621    -----------------------
5622
5623    procedure Compute_Unit_Name
5624      (File_Name : File_Name_Type;
5625       Naming    : Lang_Naming_Data;
5626       Kind      : out Source_Kind;
5627       Unit      : out Name_Id;
5628       Project   : Project_Processing_Data)
5629    is
5630       Filename : constant String  := Get_Name_String (File_Name);
5631       Last     : Integer          := Filename'Last;
5632       Sep_Len  : Integer;
5633       Body_Len : Integer;
5634       Spec_Len : Integer;
5635
5636       Unit_Except : Unit_Exception;
5637       Masked      : Boolean  := False;
5638
5639    begin
5640       Unit := No_Name;
5641       Kind := Spec;
5642
5643       if Naming.Separate_Suffix = No_File
5644         or else Naming.Body_Suffix = No_File
5645         or else Naming.Spec_Suffix = No_File
5646       then
5647          return;
5648       end if;
5649
5650       if Naming.Dot_Replacement = No_File then
5651          Debug_Output ("no dot_replacement specified");
5652          return;
5653       end if;
5654
5655       Sep_Len  := Integer (Length_Of_Name (Naming.Separate_Suffix));
5656       Spec_Len := Integer (Length_Of_Name (Naming.Spec_Suffix));
5657       Body_Len := Integer (Length_Of_Name (Naming.Body_Suffix));
5658
5659       --  Choose the longest suffix that matches. If there are several matches,
5660       --  give priority to specs, then bodies, then separates.
5661
5662       if Naming.Separate_Suffix /= Naming.Body_Suffix
5663         and then Suffix_Matches (Filename, Naming.Separate_Suffix)
5664       then
5665          Last := Filename'Last - Sep_Len;
5666          Kind := Sep;
5667       end if;
5668
5669       if Filename'Last - Body_Len <= Last
5670         and then Suffix_Matches (Filename, Naming.Body_Suffix)
5671       then
5672          Last := Natural'Min (Last, Filename'Last - Body_Len);
5673          Kind := Impl;
5674       end if;
5675
5676       if Filename'Last - Spec_Len <= Last
5677         and then Suffix_Matches (Filename, Naming.Spec_Suffix)
5678       then
5679          Last := Natural'Min (Last, Filename'Last - Spec_Len);
5680          Kind := Spec;
5681       end if;
5682
5683       if Last = Filename'Last then
5684          Debug_Output ("no matching suffix");
5685          return;
5686       end if;
5687
5688       --  Check that the casing matches
5689
5690       if File_Names_Case_Sensitive then
5691          case Naming.Casing is
5692             when All_Lower_Case =>
5693                for J in Filename'First .. Last loop
5694                   if Is_Letter (Filename (J))
5695                     and then not Is_Lower (Filename (J))
5696                   then
5697                      Debug_Output ("invalid casing");
5698                      return;
5699                   end if;
5700                end loop;
5701
5702             when All_Upper_Case =>
5703                for J in Filename'First .. Last loop
5704                   if Is_Letter (Filename (J))
5705                     and then not Is_Upper (Filename (J))
5706                   then
5707                      Debug_Output ("invalid casing");
5708                      return;
5709                   end if;
5710                end loop;
5711
5712             when Mixed_Case | Unknown =>
5713                null;
5714          end case;
5715       end if;
5716
5717       --  If Dot_Replacement is not a single dot, then there should not
5718       --  be any dot in the name.
5719
5720       declare
5721          Dot_Repl : constant String :=
5722                       Get_Name_String (Naming.Dot_Replacement);
5723
5724       begin
5725          if Dot_Repl /= "." then
5726             for Index in Filename'First .. Last loop
5727                if Filename (Index) = '.' then
5728                   Debug_Output ("invalid name, contains dot");
5729                   return;
5730                end if;
5731             end loop;
5732
5733             Replace_Into_Name_Buffer
5734               (Filename (Filename'First .. Last), Dot_Repl, '.');
5735
5736          else
5737             Name_Len := Last - Filename'First + 1;
5738             Name_Buffer (1 .. Name_Len) := Filename (Filename'First .. Last);
5739             Fixed.Translate
5740               (Source  => Name_Buffer (1 .. Name_Len),
5741                Mapping => Lower_Case_Map);
5742          end if;
5743       end;
5744
5745       --  In the standard GNAT naming scheme, check for special cases: children
5746       --  or separates of A, G, I or S, and run time sources.
5747
5748       if Is_Standard_GNAT_Naming (Naming)
5749         and then Name_Len >= 3
5750       then
5751          declare
5752             S1 : constant Character := Name_Buffer (1);
5753             S2 : constant Character := Name_Buffer (2);
5754             S3 : constant Character := Name_Buffer (3);
5755
5756          begin
5757             if        S1 = 'a'
5758               or else S1 = 'g'
5759               or else S1 = 'i'
5760               or else S1 = 's'
5761             then
5762                --  Children or separates of packages A, G, I or S. These names
5763                --  are x__ ... or x~... (where x is a, g, i, or s). Both
5764                --  versions (x__... and x~...) are allowed in all platforms,
5765                --  because it is not possible to know the platform before
5766                --  processing of the project files.
5767
5768                if S2 = '_' and then S3 = '_' then
5769                   Name_Buffer (2) := '.';
5770                   Name_Buffer (3 .. Name_Len - 1) :=
5771                     Name_Buffer (4 .. Name_Len);
5772                   Name_Len := Name_Len - 1;
5773
5774                elsif S2 = '~' then
5775                   Name_Buffer (2) := '.';
5776
5777                elsif S2 = '.' then
5778
5779                   --  If it is potentially a run time source
5780
5781                   null;
5782                end if;
5783             end if;
5784          end;
5785       end if;
5786
5787       --  Name_Buffer contains the name of the unit in lower-cases. Check
5788       --  that this is a valid unit name
5789
5790       Check_Unit_Name (Name_Buffer (1 .. Name_Len), Unit);
5791
5792       --  If there is a naming exception for the same unit, the file is not
5793       --  a source for the unit.
5794
5795       if Unit /= No_Name then
5796          Unit_Except :=
5797            Unit_Exceptions_Htable.Get (Project.Unit_Exceptions, Unit);
5798
5799          if Kind = Spec then
5800             Masked := Unit_Except.Spec /= No_File
5801                         and then
5802                       Unit_Except.Spec /= File_Name;
5803          else
5804             Masked := Unit_Except.Impl /= No_File
5805                         and then
5806                       Unit_Except.Impl /= File_Name;
5807          end if;
5808
5809          if Masked then
5810             if Current_Verbosity = High then
5811                Debug_Indent;
5812                Write_Str ("   """ & Filename & """ contains the ");
5813
5814                if Kind = Spec then
5815                   Write_Str ("spec of a unit found in """);
5816                   Write_Str (Get_Name_String (Unit_Except.Spec));
5817                else
5818                   Write_Str ("body of a unit found in """);
5819                   Write_Str (Get_Name_String (Unit_Except.Impl));
5820                end if;
5821
5822                Write_Line (""" (ignored)");
5823             end if;
5824
5825             Unit := No_Name;
5826          end if;
5827       end if;
5828
5829       if Unit /= No_Name
5830         and then Current_Verbosity = High
5831       then
5832          case Kind is
5833             when Spec => Debug_Output ("spec of", Unit);
5834             when Impl => Debug_Output ("body of", Unit);
5835             when Sep  => Debug_Output ("sep of", Unit);
5836          end case;
5837       end if;
5838    end Compute_Unit_Name;
5839
5840    --------------------------
5841    -- Check_Illegal_Suffix --
5842    --------------------------
5843
5844    procedure Check_Illegal_Suffix
5845      (Project         : Project_Id;
5846       Suffix          : File_Name_Type;
5847       Dot_Replacement : File_Name_Type;
5848       Attribute_Name  : String;
5849       Location        : Source_Ptr;
5850       Data            : in out Tree_Processing_Data)
5851    is
5852       Suffix_Str : constant String := Get_Name_String (Suffix);
5853
5854    begin
5855       if Suffix_Str'Length = 0 then
5856
5857          --  Always valid
5858
5859          return;
5860
5861       elsif Index (Suffix_Str, ".") = 0 then
5862          Err_Vars.Error_Msg_File_1 := Suffix;
5863          Error_Msg
5864            (Data.Flags,
5865             "{ is illegal for " & Attribute_Name & ": must have a dot",
5866             Location, Project);
5867          return;
5868       end if;
5869
5870       --  Case of dot replacement is a single dot, and first character of
5871       --  suffix is also a dot.
5872
5873       if Dot_Replacement /= No_File
5874         and then Get_Name_String (Dot_Replacement) = "."
5875         and then Suffix_Str (Suffix_Str'First) = '.'
5876       then
5877          for Index in Suffix_Str'First + 1 .. Suffix_Str'Last loop
5878
5879             --  If there are multiple dots in the name
5880
5881             if Suffix_Str (Index) = '.' then
5882
5883                --  It is illegal to have a letter following the initial dot
5884
5885                if Is_Letter (Suffix_Str (Suffix_Str'First + 1)) then
5886                   Err_Vars.Error_Msg_File_1 := Suffix;
5887                   Error_Msg
5888                     (Data.Flags,
5889                      "{ is illegal for " & Attribute_Name
5890                      & ": ambiguous prefix when Dot_Replacement is a dot",
5891                      Location, Project);
5892                end if;
5893                return;
5894             end if;
5895          end loop;
5896       end if;
5897    end Check_Illegal_Suffix;
5898
5899    ----------------------
5900    -- Locate_Directory --
5901    ----------------------
5902
5903    procedure Locate_Directory
5904      (Project          : Project_Id;
5905       Name             : File_Name_Type;
5906       Path             : out Path_Information;
5907       Dir_Exists       : out Boolean;
5908       Data             : in out Tree_Processing_Data;
5909       Create           : String := "";
5910       Location         : Source_Ptr := No_Location;
5911       Must_Exist       : Boolean := True;
5912       Externally_Built : Boolean := False)
5913    is
5914       Parent          : constant Path_Name_Type :=
5915                           Project.Directory.Display_Name;
5916       The_Parent      : constant String :=
5917                           Get_Name_String (Parent);
5918       The_Parent_Last : constant Natural :=
5919                           Compute_Directory_Last (The_Parent);
5920       Full_Name       : File_Name_Type;
5921       The_Name        : File_Name_Type;
5922
5923    begin
5924       Get_Name_String (Name);
5925
5926       --  Add Subdirs.all if it is a directory that may be created and
5927       --  Subdirs is not null;
5928
5929       if Create /= "" and then Subdirs /= null then
5930          if Name_Buffer (Name_Len) /= Directory_Separator then
5931             Add_Char_To_Name_Buffer (Directory_Separator);
5932          end if;
5933
5934          Add_Str_To_Name_Buffer (Subdirs.all);
5935       end if;
5936
5937       --  Convert '/' to directory separator (for Windows)
5938
5939       for J in 1 .. Name_Len loop
5940          if Name_Buffer (J) = '/' then
5941             Name_Buffer (J) := Directory_Separator;
5942          end if;
5943       end loop;
5944
5945       The_Name := Name_Find;
5946
5947       if Current_Verbosity = High then
5948          Debug_Indent;
5949          Write_Str ("Locate_Directory (""");
5950          Write_Str (Get_Name_String (The_Name));
5951          Write_Str (""", in """);
5952          Write_Str (The_Parent);
5953          Write_Line (""")");
5954       end if;
5955
5956       Path := No_Path_Information;
5957       Dir_Exists := False;
5958
5959       if Is_Absolute_Path (Get_Name_String (The_Name)) then
5960          Full_Name := The_Name;
5961
5962       else
5963          Name_Len := 0;
5964          Add_Str_To_Name_Buffer
5965            (The_Parent (The_Parent'First .. The_Parent_Last));
5966          Add_Str_To_Name_Buffer (Get_Name_String (The_Name));
5967          Full_Name := Name_Find;
5968       end if;
5969
5970       declare
5971          Full_Path_Name : String_Access :=
5972                             new String'(Get_Name_String (Full_Name));
5973
5974       begin
5975          if (Setup_Projects or else Subdirs /= null)
5976            and then Create'Length > 0
5977          then
5978             if not Is_Directory (Full_Path_Name.all) then
5979
5980                --  If project is externally built, do not create a subdir,
5981                --  use the specified directory, without the subdir.
5982
5983                if Externally_Built then
5984                   if Is_Absolute_Path (Get_Name_String (Name)) then
5985                      Get_Name_String (Name);
5986
5987                   else
5988                      Name_Len := 0;
5989                      Add_Str_To_Name_Buffer
5990                        (The_Parent (The_Parent'First .. The_Parent_Last));
5991                      Add_Str_To_Name_Buffer (Get_Name_String (Name));
5992                   end if;
5993
5994                   Full_Path_Name := new String'(Name_Buffer (1 .. Name_Len));
5995
5996                else
5997                   begin
5998                      Create_Path (Full_Path_Name.all);
5999
6000                      if not Quiet_Output then
6001                         Write_Str (Create);
6002                         Write_Str (" directory """);
6003                         Write_Str (Full_Path_Name.all);
6004                         Write_Str (""" created for project ");
6005                         Write_Line (Get_Name_String (Project.Name));
6006                      end if;
6007
6008                   exception
6009                      when Use_Error =>
6010                         Error_Msg
6011                           (Data.Flags,
6012                            "could not create " & Create &
6013                            " directory " & Full_Path_Name.all,
6014                            Location, Project);
6015                   end;
6016                end if;
6017             end if;
6018          end if;
6019
6020          Dir_Exists := Is_Directory (Full_Path_Name.all);
6021
6022          if not Must_Exist or else Dir_Exists then
6023             declare
6024                Normed : constant String :=
6025                           Normalize_Pathname
6026                             (Full_Path_Name.all,
6027                              Directory      =>
6028                               The_Parent (The_Parent'First .. The_Parent_Last),
6029                              Resolve_Links  => False,
6030                              Case_Sensitive => True);
6031
6032                Canonical_Path : constant String :=
6033                                   Normalize_Pathname
6034                                     (Normed,
6035                                      Directory      =>
6036                                        The_Parent
6037                                          (The_Parent'First .. The_Parent_Last),
6038                                      Resolve_Links  =>
6039                                         Opt.Follow_Links_For_Dirs,
6040                                      Case_Sensitive => False);
6041
6042             begin
6043                Name_Len := Normed'Length;
6044                Name_Buffer (1 .. Name_Len) := Normed;
6045
6046                --  Directories should always end with a directory separator
6047
6048                if Name_Buffer (Name_Len) /= Directory_Separator then
6049                   Add_Char_To_Name_Buffer (Directory_Separator);
6050                end if;
6051
6052                Path.Display_Name := Name_Find;
6053
6054                Name_Len := Canonical_Path'Length;
6055                Name_Buffer (1 .. Name_Len) := Canonical_Path;
6056
6057                if Name_Buffer (Name_Len) /= Directory_Separator then
6058                   Add_Char_To_Name_Buffer (Directory_Separator);
6059                end if;
6060
6061                Path.Name := Name_Find;
6062             end;
6063          end if;
6064
6065          Free (Full_Path_Name);
6066       end;
6067    end Locate_Directory;
6068
6069    ---------------------------
6070    -- Find_Excluded_Sources --
6071    ---------------------------
6072
6073    procedure Find_Excluded_Sources
6074      (Project : in out Project_Processing_Data;
6075       Data    : in out Tree_Processing_Data)
6076    is
6077       Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
6078
6079       Excluded_Source_List_File : constant Variable_Value :=
6080                                     Util.Value_Of
6081                                       (Name_Excluded_Source_List_File,
6082                                        Project.Project.Decl.Attributes,
6083                                        Shared);
6084       Excluded_Sources          : Variable_Value := Util.Value_Of
6085                                     (Name_Excluded_Source_Files,
6086                                      Project.Project.Decl.Attributes,
6087                                      Shared);
6088
6089       Current         : String_List_Id;
6090       Element         : String_Element;
6091       Location        : Source_Ptr;
6092       Name            : File_Name_Type;
6093       File            : Prj.Util.Text_File;
6094       Line            : String (1 .. 300);
6095       Last            : Natural;
6096       Locally_Removed : Boolean := False;
6097
6098    begin
6099       --  If Excluded_Source_Files is not declared, check Locally_Removed_Files
6100
6101       if Excluded_Sources.Default then
6102          Locally_Removed := True;
6103          Excluded_Sources :=
6104            Util.Value_Of
6105              (Name_Locally_Removed_Files,
6106               Project.Project.Decl.Attributes, Shared);
6107       end if;
6108
6109       --  If there are excluded sources, put them in the table
6110
6111       if not Excluded_Sources.Default then
6112          if not Excluded_Source_List_File.Default then
6113             if Locally_Removed then
6114                Error_Msg
6115                  (Data.Flags,
6116                   "?both attributes Locally_Removed_Files and " &
6117                   "Excluded_Source_List_File are present",
6118                   Excluded_Source_List_File.Location, Project.Project);
6119             else
6120                Error_Msg
6121                  (Data.Flags,
6122                   "?both attributes Excluded_Source_Files and " &
6123                   "Excluded_Source_List_File are present",
6124                   Excluded_Source_List_File.Location, Project.Project);
6125             end if;
6126          end if;
6127
6128          Current := Excluded_Sources.Values;
6129          while Current /= Nil_String loop
6130             Element := Shared.String_Elements.Table (Current);
6131             Name := Canonical_Case_File_Name (Element.Value);
6132
6133             --  If the element has no location, then use the location of
6134             --  Excluded_Sources to report possible errors.
6135
6136             if Element.Location = No_Location then
6137                Location := Excluded_Sources.Location;
6138             else
6139                Location := Element.Location;
6140             end if;
6141
6142             Excluded_Sources_Htable.Set
6143               (Project.Excluded, Name,
6144                (Name, No_File, 0, False, Location));
6145             Current := Element.Next;
6146          end loop;
6147
6148       elsif not Excluded_Source_List_File.Default then
6149          Location := Excluded_Source_List_File.Location;
6150
6151          declare
6152             Source_File_Name : constant File_Name_Type :=
6153                                  File_Name_Type
6154                                     (Excluded_Source_List_File.Value);
6155             Source_File_Line : Natural := 0;
6156
6157             Source_File_Path_Name : constant String :=
6158                                       Path_Name_Of
6159                                         (Source_File_Name,
6160                                          Project.Project.Directory.Name);
6161
6162          begin
6163             if Source_File_Path_Name'Length = 0 then
6164                Err_Vars.Error_Msg_File_1 :=
6165                  File_Name_Type (Excluded_Source_List_File.Value);
6166                Error_Msg
6167                  (Data.Flags,
6168                   "file with excluded sources { does not exist",
6169                   Excluded_Source_List_File.Location, Project.Project);
6170
6171             else
6172                --  Open the file
6173
6174                Prj.Util.Open (File, Source_File_Path_Name);
6175
6176                if not Prj.Util.Is_Valid (File) then
6177                   Error_Msg
6178                     (Data.Flags, "file does not exist",
6179                      Location, Project.Project);
6180                else
6181                   --  Read the lines one by one
6182
6183                   while not Prj.Util.End_Of_File (File) loop
6184                      Prj.Util.Get_Line (File, Line, Last);
6185                      Source_File_Line := Source_File_Line + 1;
6186
6187                      --  Non empty, non comment line should contain a file name
6188
6189                      if Last /= 0
6190                        and then (Last = 1 or else Line (1 .. 2) /= "--")
6191                      then
6192                         Name_Len := Last;
6193                         Name_Buffer (1 .. Name_Len) := Line (1 .. Last);
6194                         Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
6195                         Name := Name_Find;
6196
6197                         --  Check that there is no directory information
6198
6199                         for J in 1 .. Last loop
6200                            if Line (J) = '/'
6201                              or else Line (J) = Directory_Separator
6202                            then
6203                               Error_Msg_File_1 := Name;
6204                               Error_Msg
6205                                 (Data.Flags,
6206                                  "file name cannot include " &
6207                                  "directory information ({)",
6208                                  Location, Project.Project);
6209                               exit;
6210                            end if;
6211                         end loop;
6212
6213                         Excluded_Sources_Htable.Set
6214                           (Project.Excluded,
6215                            Name,
6216                            (Name, Source_File_Name, Source_File_Line,
6217                             False, Location));
6218                      end if;
6219                   end loop;
6220
6221                   Prj.Util.Close (File);
6222                end if;
6223             end if;
6224          end;
6225       end if;
6226    end Find_Excluded_Sources;
6227
6228    ------------------
6229    -- Find_Sources --
6230    ------------------
6231
6232    procedure Find_Sources
6233      (Project : in out Project_Processing_Data;
6234       Data    : in out Tree_Processing_Data)
6235    is
6236       Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
6237
6238       Sources : constant Variable_Value :=
6239                   Util.Value_Of
6240                     (Name_Source_Files,
6241                      Project.Project.Decl.Attributes,
6242                      Shared);
6243
6244       Source_List_File : constant Variable_Value :=
6245                            Util.Value_Of
6246                              (Name_Source_List_File,
6247                               Project.Project.Decl.Attributes,
6248                               Shared);
6249
6250       Name_Loc             : Name_Location;
6251       Has_Explicit_Sources : Boolean;
6252
6253    begin
6254       pragma Assert (Sources.Kind = List, "Source_Files is not a list");
6255       pragma Assert
6256         (Source_List_File.Kind = Single,
6257          "Source_List_File is not a single string");
6258
6259       Project.Source_List_File_Location := Source_List_File.Location;
6260
6261       --  If the user has specified a Source_Files attribute
6262
6263       if not Sources.Default then
6264          if not Source_List_File.Default then
6265             Error_Msg
6266               (Data.Flags,
6267                "?both attributes source_files and " &
6268                "source_list_file are present",
6269                Source_List_File.Location, Project.Project);
6270          end if;
6271
6272          --  Sources is a list of file names
6273
6274          declare
6275             Current  : String_List_Id := Sources.Values;
6276             Element  : String_Element;
6277             Location : Source_Ptr;
6278             Name     : File_Name_Type;
6279
6280          begin
6281             if Current = Nil_String then
6282                Project.Project.Languages := No_Language_Index;
6283
6284                --  This project contains no source. For projects that don't
6285                --  extend other projects, this also means that there is no
6286                --  need for an object directory, if not specified.
6287
6288                if Project.Project.Extends = No_Project
6289                  and then
6290                    Project.Project.Object_Directory = Project.Project.Directory
6291                  and then
6292                    not (Project.Project.Qualifier = Aggregate_Library)
6293                then
6294                   Project.Project.Object_Directory := No_Path_Information;
6295                end if;
6296             end if;
6297
6298             while Current /= Nil_String loop
6299                Element := Shared.String_Elements.Table (Current);
6300                Name := Canonical_Case_File_Name (Element.Value);
6301                Get_Name_String (Element.Value);
6302
6303                --  If the element has no location, then use the location of
6304                --  Sources to report possible errors.
6305
6306                if Element.Location = No_Location then
6307                   Location := Sources.Location;
6308                else
6309                   Location := Element.Location;
6310                end if;
6311
6312                --  Check that there is no directory information
6313
6314                for J in 1 .. Name_Len loop
6315                   if Name_Buffer (J) = '/'
6316                     or else Name_Buffer (J) = Directory_Separator
6317                   then
6318                      Error_Msg_File_1 := Name;
6319                      Error_Msg
6320                        (Data.Flags,
6321                         "file name cannot include directory " &
6322                         "information ({)",
6323                         Location, Project.Project);
6324                      exit;
6325                   end if;
6326                end loop;
6327
6328                --  Check whether the file is already there: the same file name
6329                --  may be in the list. If the source is missing, the error will
6330                --  be on the first mention of the source file name.
6331
6332                Name_Loc := Source_Names_Htable.Get
6333                  (Project.Source_Names, Name);
6334
6335                if Name_Loc = No_Name_Location then
6336                   Name_Loc :=
6337                     (Name     => Name,
6338                      Location => Location,
6339                      Source   => No_Source,
6340                      Listed   => True,
6341                      Found    => False);
6342
6343                else
6344                   Name_Loc.Listed := True;
6345                end if;
6346
6347                Source_Names_Htable.Set
6348                  (Project.Source_Names, Name, Name_Loc);
6349
6350                Current := Element.Next;
6351             end loop;
6352
6353             Has_Explicit_Sources := True;
6354          end;
6355
6356          --  If we have no Source_Files attribute, check the Source_List_File
6357          --  attribute.
6358
6359       elsif not Source_List_File.Default then
6360
6361          --  Source_List_File is the name of the file that contains the source
6362          --  file names.
6363
6364          declare
6365             Source_File_Path_Name : constant String :=
6366                                       Path_Name_Of
6367                                         (File_Name_Type
6368                                            (Source_List_File.Value),
6369                                          Project.Project.
6370                                            Directory.Display_Name);
6371
6372          begin
6373             Has_Explicit_Sources := True;
6374
6375             if Source_File_Path_Name'Length = 0 then
6376                Err_Vars.Error_Msg_File_1 :=
6377                  File_Name_Type (Source_List_File.Value);
6378                Error_Msg
6379                  (Data.Flags,
6380                   "file with sources { does not exist",
6381                   Source_List_File.Location, Project.Project);
6382
6383             else
6384                Get_Sources_From_File
6385                  (Source_File_Path_Name, Source_List_File.Location,
6386                   Project, Data);
6387             end if;
6388          end;
6389
6390       else
6391          --  Neither Source_Files nor Source_List_File has been specified. Find
6392          --  all the files that satisfy the naming scheme in all the source
6393          --  directories.
6394
6395          Has_Explicit_Sources := False;
6396       end if;
6397
6398       --  Remove any exception that is not in the specified list of sources
6399
6400       if Has_Explicit_Sources then
6401          declare
6402             Source : Source_Id;
6403             Iter   : Source_Iterator;
6404             NL     : Name_Location;
6405             Again  : Boolean;
6406          begin
6407             Iter_Loop :
6408             loop
6409                Again := False;
6410                Iter := For_Each_Source (Data.Tree, Project.Project);
6411
6412                Source_Loop :
6413                loop
6414                   Source := Prj.Element (Iter);
6415                   exit Source_Loop when Source = No_Source;
6416
6417                   if Source.Naming_Exception /= No then
6418                      NL := Source_Names_Htable.Get
6419                        (Project.Source_Names, Source.File);
6420
6421                      if NL /= No_Name_Location and then not NL.Listed then
6422                         --  Remove the exception
6423                         Source_Names_Htable.Set
6424                           (Project.Source_Names,
6425                            Source.File,
6426                            No_Name_Location);
6427                         Remove_Source (Data.Tree, Source, No_Source);
6428
6429                         if Source.Naming_Exception = Yes then
6430                            Error_Msg_Name_1 := Name_Id (Source.File);
6431                            Error_Msg
6432                              (Data.Flags,
6433                               "? unknown source file %%",
6434                               NL.Location,
6435                               Project.Project);
6436                         end if;
6437
6438                         Again := True;
6439                         exit Source_Loop;
6440                      end if;
6441                   end if;
6442
6443                   Next (Iter);
6444                end loop Source_Loop;
6445
6446                exit Iter_Loop when not Again;
6447             end loop Iter_Loop;
6448          end;
6449       end if;
6450
6451       Search_Directories
6452         (Project,
6453          Data            => Data,
6454          For_All_Sources => Sources.Default and then Source_List_File.Default);
6455
6456       --  Check if all exceptions have been found
6457
6458       declare
6459          Source : Source_Id;
6460          Iter   : Source_Iterator;
6461          Found  : Boolean := False;
6462
6463       begin
6464          Iter := For_Each_Source (Data.Tree, Project.Project);
6465          loop
6466             Source := Prj.Element (Iter);
6467             exit when Source = No_Source;
6468
6469             --  If the full source path is unknown for this source_id, there
6470             --  could be several reasons:
6471             --    * we simply did not find the file itself, this is an error
6472             --    * we have a multi-unit source file. Another Source_Id from
6473             --      the same file has received the full path, so we need to
6474             --      propagate it.
6475
6476             if Source.Path = No_Path_Information then
6477                if Source.Naming_Exception = Yes then
6478                   if Source.Unit /= No_Unit_Index then
6479                      Found := False;
6480
6481                      if Source.Index /= 0 then  --  Only multi-unit files
6482                         declare
6483                            S : Source_Id :=
6484                                  Source_Files_Htable.Get
6485                                    (Data.Tree.Source_Files_HT, Source.File);
6486
6487                         begin
6488                            while S /= null loop
6489                               if S.Path /= No_Path_Information then
6490                                  Source.Path := S.Path;
6491                                  Found := True;
6492
6493                                  if Current_Verbosity = High then
6494                                     Debug_Output
6495                                       ("setting full path for "
6496                                        & Get_Name_String (Source.File)
6497                                        & " at" & Source.Index'Img
6498                                        & " to "
6499                                        & Get_Name_String (Source.Path.Name));
6500                                  end if;
6501
6502                                  exit;
6503                               end if;
6504
6505                               S := S.Next_With_File_Name;
6506                            end loop;
6507                         end;
6508                      end if;
6509
6510                      if not Found then
6511                         Error_Msg_Name_1 := Name_Id (Source.Display_File);
6512                         Error_Msg_Name_2 := Source.Unit.Name;
6513                         Error_Or_Warning
6514                           (Data.Flags, Data.Flags.Missing_Source_Files,
6515                            "source file %% for unit %% not found",
6516                            No_Location, Project.Project);
6517                      end if;
6518                   end if;
6519
6520                   if Source.Path = No_Path_Information then
6521                      Remove_Source (Data.Tree, Source, No_Source);
6522                   end if;
6523
6524                elsif Source.Naming_Exception = Inherited then
6525                   Remove_Source (Data.Tree, Source, No_Source);
6526                end if;
6527             end if;
6528
6529             Next (Iter);
6530          end loop;
6531       end;
6532
6533       --  It is an error if a source file name in a source list or in a source
6534       --  list file is not found.
6535
6536       if Has_Explicit_Sources then
6537          declare
6538             NL          : Name_Location;
6539             First_Error : Boolean;
6540
6541          begin
6542             NL := Source_Names_Htable.Get_First (Project.Source_Names);
6543             First_Error := True;
6544             while NL /= No_Name_Location loop
6545                if not NL.Found then
6546                   Err_Vars.Error_Msg_File_1 := NL.Name;
6547                   if First_Error then
6548                      Error_Or_Warning
6549                        (Data.Flags, Data.Flags.Missing_Source_Files,
6550                         "source file { not found",
6551                         NL.Location, Project.Project);
6552                      First_Error := False;
6553                   else
6554                      Error_Or_Warning
6555                        (Data.Flags, Data.Flags.Missing_Source_Files,
6556                         "\source file { not found",
6557                         NL.Location, Project.Project);
6558                   end if;
6559                end if;
6560
6561                NL := Source_Names_Htable.Get_Next (Project.Source_Names);
6562             end loop;
6563          end;
6564       end if;
6565    end Find_Sources;
6566
6567    ----------------
6568    -- Initialize --
6569    ----------------
6570
6571    procedure Initialize
6572      (Data      : out Tree_Processing_Data;
6573       Tree      : Project_Tree_Ref;
6574       Node_Tree : Prj.Tree.Project_Node_Tree_Ref;
6575       Flags     : Prj.Processing_Flags)
6576    is
6577    begin
6578       Data.Tree      := Tree;
6579       Data.Node_Tree := Node_Tree;
6580       Data.Flags     := Flags;
6581    end Initialize;
6582
6583    ----------
6584    -- Free --
6585    ----------
6586
6587    procedure Free (Data : in out Tree_Processing_Data) is
6588       pragma Unreferenced (Data);
6589    begin
6590       null;
6591    end Free;
6592
6593    ----------------
6594    -- Initialize --
6595    ----------------
6596
6597    procedure Initialize
6598      (Data    : in out Project_Processing_Data;
6599       Project : Project_Id)
6600    is
6601    begin
6602       Data.Project := Project;
6603    end Initialize;
6604
6605    ----------
6606    -- Free --
6607    ----------
6608
6609    procedure Free (Data : in out Project_Processing_Data) is
6610    begin
6611       Source_Names_Htable.Reset      (Data.Source_Names);
6612       Unit_Exceptions_Htable.Reset   (Data.Unit_Exceptions);
6613       Excluded_Sources_Htable.Reset  (Data.Excluded);
6614    end Free;
6615
6616    -------------------------------
6617    -- Check_File_Naming_Schemes --
6618    -------------------------------
6619
6620    procedure Check_File_Naming_Schemes
6621      (Project               : Project_Processing_Data;
6622       File_Name             : File_Name_Type;
6623       Alternate_Languages   : out Language_List;
6624       Language              : out Language_Ptr;
6625       Display_Language_Name : out Name_Id;
6626       Unit                  : out Name_Id;
6627       Lang_Kind             : out Language_Kind;
6628       Kind                  : out Source_Kind)
6629    is
6630       Filename : constant String := Get_Name_String (File_Name);
6631       Config   : Language_Config;
6632       Tmp_Lang : Language_Ptr;
6633
6634       Header_File : Boolean := False;
6635       --  True if we found at least one language for which the file is a header
6636       --  In such a case, we search for all possible languages where this is
6637       --  also a header (C and C++ for instance), since the file might be used
6638       --  for several such languages.
6639
6640       procedure Check_File_Based_Lang;
6641       --  Does the naming scheme test for file-based languages. For those,
6642       --  there is no Unit. Just check if the file name has the implementation
6643       --  or, if it is specified, the template suffix of the language.
6644       --
6645       --  Returns True if the file belongs to the current language and we
6646       --  should stop searching for matching languages. Not that a given header
6647       --  file could belong to several languages (C and C++ for instance). Thus
6648       --  if we found a header we'll check whether it matches other languages.
6649
6650       ---------------------------
6651       -- Check_File_Based_Lang --
6652       ---------------------------
6653
6654       procedure Check_File_Based_Lang is
6655       begin
6656          if not Header_File
6657            and then Suffix_Matches (Filename, Config.Naming_Data.Body_Suffix)
6658          then
6659             Unit     := No_Name;
6660             Kind     := Impl;
6661             Language := Tmp_Lang;
6662
6663             Debug_Output
6664               ("implementation of language ", Display_Language_Name);
6665
6666          elsif Suffix_Matches (Filename, Config.Naming_Data.Spec_Suffix) then
6667             Debug_Output
6668               ("header of language ", Display_Language_Name);
6669
6670             if Header_File then
6671                Alternate_Languages := new Language_List_Element'
6672                  (Language => Language,
6673                   Next     => Alternate_Languages);
6674
6675             else
6676                Header_File := True;
6677                Kind        := Spec;
6678                Unit        := No_Name;
6679                Language    := Tmp_Lang;
6680             end if;
6681          end if;
6682       end Check_File_Based_Lang;
6683
6684    --  Start of processing for Check_File_Naming_Schemes
6685
6686    begin
6687       Language              := No_Language_Index;
6688       Alternate_Languages   := null;
6689       Display_Language_Name := No_Name;
6690       Unit                  := No_Name;
6691       Lang_Kind             := File_Based;
6692       Kind                  := Spec;
6693
6694       Tmp_Lang := Project.Project.Languages;
6695       while Tmp_Lang /= No_Language_Index loop
6696          if Current_Verbosity = High then
6697             Debug_Output
6698               ("testing language "
6699                & Get_Name_String (Tmp_Lang.Name)
6700                & " Header_File=" & Header_File'Img);
6701          end if;
6702
6703          Display_Language_Name := Tmp_Lang.Display_Name;
6704          Config := Tmp_Lang.Config;
6705          Lang_Kind := Config.Kind;
6706
6707          case Config.Kind is
6708             when File_Based =>
6709                Check_File_Based_Lang;
6710                exit when Kind = Impl;
6711
6712             when Unit_Based =>
6713
6714                --  We know it belongs to a least a file_based language, no
6715                --  need to check unit-based ones.
6716
6717                if not Header_File then
6718                   Compute_Unit_Name
6719                     (File_Name => File_Name,
6720                      Naming    => Config.Naming_Data,
6721                      Kind      => Kind,
6722                      Unit      => Unit,
6723                      Project   => Project);
6724
6725                   if Unit /= No_Name then
6726                      Language    := Tmp_Lang;
6727                      exit;
6728                   end if;
6729                end if;
6730          end case;
6731
6732          Tmp_Lang := Tmp_Lang.Next;
6733       end loop;
6734
6735       if Language = No_Language_Index then
6736          Debug_Output ("not a source of any language");
6737       end if;
6738    end Check_File_Naming_Schemes;
6739
6740    -------------------
6741    -- Override_Kind --
6742    -------------------
6743
6744    procedure Override_Kind (Source : Source_Id; Kind : Source_Kind) is
6745    begin
6746       --  If the file was previously already associated with a unit, change it
6747
6748       if Source.Unit /= null
6749         and then Source.Kind in Spec_Or_Body
6750         and then Source.Unit.File_Names (Source.Kind) /= null
6751       then
6752          --  If we had another file referencing the same unit (for instance it
6753          --  was in an extended project), that source file is in fact invisible
6754          --  from now on, and in particular doesn't belong to the same unit.
6755          --  If the source is an inherited naming exception, then it may not
6756          --  really exist: the source potentially replaced is left untouched.
6757
6758          if Source.Unit.File_Names (Source.Kind) /= Source then
6759             Source.Unit.File_Names (Source.Kind).Unit := No_Unit_Index;
6760          end if;
6761
6762          Source.Unit.File_Names (Source.Kind) := null;
6763       end if;
6764
6765       Source.Kind := Kind;
6766
6767       if Current_Verbosity = High
6768         and then Source.File /= No_File
6769       then
6770          Debug_Output ("override kind for "
6771                        & Get_Name_String (Source.File)
6772                        & " idx=" & Source.Index'Img
6773                        & " kind=" & Source.Kind'Img);
6774       end if;
6775
6776       if Source.Unit /= null then
6777          if Source.Kind = Spec then
6778             Source.Unit.File_Names (Spec) := Source;
6779          else
6780             Source.Unit.File_Names (Impl) := Source;
6781          end if;
6782       end if;
6783    end Override_Kind;
6784
6785    ----------------
6786    -- Check_File --
6787    ----------------
6788
6789    procedure Check_File
6790      (Project           : in out Project_Processing_Data;
6791       Data              : in out Tree_Processing_Data;
6792       Source_Dir_Rank   : Natural;
6793       Path              : Path_Name_Type;
6794       Display_Path      : Path_Name_Type;
6795       File_Name         : File_Name_Type;
6796       Display_File_Name : File_Name_Type;
6797       Locally_Removed   : Boolean;
6798       For_All_Sources   : Boolean)
6799    is
6800       Name_Loc              : Name_Location :=
6801                                 Source_Names_Htable.Get
6802                                   (Project.Source_Names, File_Name);
6803       Check_Name            : Boolean := False;
6804       Alternate_Languages   : Language_List;
6805       Language              : Language_Ptr;
6806       Source                : Source_Id;
6807       Src_Ind               : Source_File_Index;
6808       Unit                  : Name_Id;
6809       Display_Language_Name : Name_Id;
6810       Lang_Kind             : Language_Kind;
6811       Kind                  : Source_Kind := Spec;
6812
6813    begin
6814       if Current_Verbosity = High then
6815          Debug_Increase_Indent
6816            ("checking file (rank=" & Source_Dir_Rank'Img & ")",
6817             Name_Id (Display_Path));
6818       end if;
6819
6820       if Name_Loc = No_Name_Location then
6821          Check_Name := For_All_Sources;
6822
6823       else
6824          if Name_Loc.Found then
6825
6826             --  Check if it is OK to have the same file name in several
6827             --  source directories.
6828
6829             if Source_Dir_Rank = Name_Loc.Source.Source_Dir_Rank then
6830                Error_Msg_File_1 := File_Name;
6831                Error_Msg
6832                  (Data.Flags,
6833                   "{ is found in several source directories",
6834                   Name_Loc.Location, Project.Project);
6835             end if;
6836
6837          else
6838             Name_Loc.Found := True;
6839
6840             Source_Names_Htable.Set
6841               (Project.Source_Names, File_Name, Name_Loc);
6842
6843             if Name_Loc.Source = No_Source then
6844                Check_Name := True;
6845
6846             else
6847                --  Set the full path for the source_id (which might have been
6848                --  created when parsing the naming exceptions, and therefore
6849                --  might not have the full path).
6850                --  We only set this for this source_id, but not for other
6851                --  source_id in the same file (case of multi-unit source files)
6852                --  For the latter, they will be set in Find_Sources when we
6853                --  check that all source_id have known full paths.
6854                --  Doing this later saves one htable lookup per file in the
6855                --  common case where the user is not using multi-unit files.
6856
6857                Name_Loc.Source.Path := (Path, Display_Path);
6858
6859                Source_Paths_Htable.Set
6860                  (Data.Tree.Source_Paths_HT, Path, Name_Loc.Source);
6861
6862                --  Check if this is a subunit
6863
6864                if Name_Loc.Source.Unit /= No_Unit_Index
6865                  and then Name_Loc.Source.Kind = Impl
6866                then
6867                   Src_Ind := Sinput.P.Load_Project_File
6868                     (Get_Name_String (Display_Path));
6869
6870                   if Sinput.P.Source_File_Is_Subunit (Src_Ind) then
6871                      Override_Kind (Name_Loc.Source, Sep);
6872                   end if;
6873                end if;
6874
6875                --  If this is an inherited naming exception, make sure that
6876                --  the naming exception it replaces is no longer a source.
6877
6878                if Name_Loc.Source.Naming_Exception = Inherited then
6879                   declare
6880                      Proj  : Project_Id := Name_Loc.Source.Project.Extends;
6881                      Iter  : Source_Iterator;
6882                      Src   : Source_Id;
6883                   begin
6884                      while Proj /= No_Project loop
6885                         Iter := For_Each_Source (Data.Tree, Proj);
6886                         Src := Prj.Element (Iter);
6887                         while Src /= No_Source loop
6888                            if Src.File = Name_Loc.Source.File then
6889                               Src.Replaced_By := Name_Loc.Source;
6890                               exit;
6891                            end if;
6892
6893                            Next (Iter);
6894                            Src := Prj.Element (Iter);
6895                         end loop;
6896
6897                         Proj := Proj.Extends;
6898                      end loop;
6899                   end;
6900
6901                   if Name_Loc.Source.Unit /= No_Unit_Index then
6902                      if Name_Loc.Source.Kind = Spec then
6903                         Name_Loc.Source.Unit.File_Names (Spec) :=
6904                           Name_Loc.Source;
6905
6906                      elsif Name_Loc.Source.Kind = Impl then
6907                         Name_Loc.Source.Unit.File_Names (Impl) :=
6908                           Name_Loc.Source;
6909                      end if;
6910
6911                      Units_Htable.Set
6912                        (Data.Tree.Units_HT,
6913                         Name_Loc.Source.Unit.Name,
6914                         Name_Loc.Source.Unit);
6915                   end if;
6916                end if;
6917             end if;
6918          end if;
6919       end if;
6920
6921       if Check_Name then
6922          Check_File_Naming_Schemes
6923            (Project               => Project,
6924             File_Name             => File_Name,
6925             Alternate_Languages   => Alternate_Languages,
6926             Language              => Language,
6927             Display_Language_Name => Display_Language_Name,
6928             Unit                  => Unit,
6929             Lang_Kind             => Lang_Kind,
6930             Kind                  => Kind);
6931
6932          if Language = No_Language_Index then
6933
6934             --  A file name in a list must be a source of a language
6935
6936             if Data.Flags.Error_On_Unknown_Language
6937               and then Name_Loc.Found
6938             then
6939                Error_Msg_File_1 := File_Name;
6940                Error_Msg
6941                  (Data.Flags,
6942                   "language unknown for {",
6943                   Name_Loc.Location, Project.Project);
6944             end if;
6945
6946          else
6947             Add_Source
6948               (Id                  => Source,
6949                Project             => Project.Project,
6950                Source_Dir_Rank     => Source_Dir_Rank,
6951                Lang_Id             => Language,
6952                Kind                => Kind,
6953                Data                => Data,
6954                Alternate_Languages => Alternate_Languages,
6955                File_Name           => File_Name,
6956                Display_File        => Display_File_Name,
6957                Unit                => Unit,
6958                Locally_Removed     => Locally_Removed,
6959                Path                => (Path, Display_Path));
6960
6961             --  If it is a source specified in a list, update the entry in
6962             --  the Source_Names table.
6963
6964             if Name_Loc.Found and then Name_Loc.Source = No_Source then
6965                Name_Loc.Source := Source;
6966                Source_Names_Htable.Set
6967                  (Project.Source_Names, File_Name, Name_Loc);
6968             end if;
6969          end if;
6970       end if;
6971
6972       Debug_Decrease_Indent;
6973    end Check_File;
6974
6975    ---------------------------------
6976    -- Expand_Subdirectory_Pattern --
6977    ---------------------------------
6978
6979    procedure Expand_Subdirectory_Pattern
6980      (Project       : Project_Id;
6981       Data          : in out Tree_Processing_Data;
6982       Patterns      : String_List_Id;
6983       Ignore        : String_List_Id;
6984       Search_For    : Search_Type;
6985       Resolve_Links : Boolean)
6986    is
6987       Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
6988
6989       package Recursive_Dirs is new GNAT.Dynamic_HTables.Simple_HTable
6990         (Header_Num => Header_Num,
6991          Element    => Boolean,
6992          No_Element => False,
6993          Key        => Path_Name_Type,
6994          Hash       => Hash,
6995          Equal      => "=");
6996       --  Hash table stores recursive source directories, to avoid looking
6997       --  several times, and to avoid cycles that may be introduced by symbolic
6998       --  links.
6999
7000       File_Pattern : GNAT.Regexp.Regexp;
7001       --  Pattern to use when matching file names
7002
7003       Visited : Recursive_Dirs.Instance;
7004
7005       procedure Find_Pattern
7006         (Pattern_Id : Name_Id;
7007          Rank       : Natural;
7008          Location   : Source_Ptr);
7009       --  Find a specific pattern
7010
7011       function Recursive_Find_Dirs
7012         (Path : Path_Information;
7013          Rank : Natural) return Boolean;
7014       --  Search all the subdirectories (recursively) of Path.
7015       --  Return True if at least one file or directory was processed
7016
7017       function Subdirectory_Matches
7018         (Path : Path_Information;
7019          Rank : Natural) return Boolean;
7020       --  Called when a matching directory was found. If the user is in fact
7021       --  searching for files, we then search for those files matching the
7022       --  pattern within the directory.
7023       --  Return True if at least one file or directory was processed
7024
7025       --------------------------
7026       -- Subdirectory_Matches --
7027       --------------------------
7028
7029       function Subdirectory_Matches
7030         (Path : Path_Information;
7031          Rank : Natural) return Boolean
7032       is
7033          Dir   : Dir_Type;
7034          Name  : String (1 .. 250);
7035          Last  : Natural;
7036          Found : Path_Information;
7037          Success : Boolean := False;
7038
7039       begin
7040          case Search_For is
7041             when Search_Directories =>
7042                Callback (Path, Rank);
7043                return True;
7044
7045             when Search_Files =>
7046                Open (Dir, Get_Name_String (Path.Display_Name));
7047                loop
7048                   Read (Dir, Name, Last);
7049                   exit when Last = 0;
7050
7051                   if Name (Name'First .. Last) /= "."
7052                     and then Name (Name'First .. Last) /= ".."
7053                     and then Match (Name (Name'First .. Last), File_Pattern)
7054                   then
7055                      Get_Name_String (Path.Display_Name);
7056                      Add_Str_To_Name_Buffer (Name (Name'First .. Last));
7057
7058                      Found.Display_Name := Name_Find;
7059                      Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
7060                      Found.Name := Name_Find;
7061
7062                      Callback (Found, Rank);
7063                      Success := True;
7064                   end if;
7065                end loop;
7066
7067                Close (Dir);
7068
7069                return Success;
7070          end case;
7071       end Subdirectory_Matches;
7072
7073       -------------------------
7074       -- Recursive_Find_Dirs --
7075       -------------------------
7076
7077       function Recursive_Find_Dirs
7078         (Path : Path_Information;
7079          Rank : Natural) return Boolean
7080       is
7081          Path_Str : constant String := Get_Name_String (Path.Display_Name);
7082          Dir   : Dir_Type;
7083          Name  : String (1 .. 250);
7084          Last  : Natural;
7085          Success : Boolean := False;
7086
7087       begin
7088          Debug_Output ("looking for subdirs of ", Name_Id (Path.Display_Name));
7089
7090          if Recursive_Dirs.Get (Visited, Path.Name) then
7091             return Success;
7092          end if;
7093
7094          Recursive_Dirs.Set (Visited, Path.Name, True);
7095
7096          Success := Subdirectory_Matches (Path, Rank) or Success;
7097
7098          Open (Dir, Path_Str);
7099
7100          loop
7101             Read (Dir, Name, Last);
7102             exit when Last = 0;
7103
7104             if Name (1 .. Last) /= "."
7105                  and then
7106                Name (1 .. Last) /= ".."
7107             then
7108                declare
7109                   Path_Name : constant String :=
7110                     Normalize_Pathname
7111                       (Name           => Name (1 .. Last),
7112                        Directory      => Path_Str,
7113                        Resolve_Links  => Resolve_Links)
7114                     & Directory_Separator;
7115                   Path2     : Path_Information;
7116                   OK        : Boolean := True;
7117
7118                begin
7119                   if Is_Directory (Path_Name) then
7120                      if Ignore /= Nil_String then
7121                         declare
7122                            Dir_Name : String := Name (1 .. Last);
7123                            List     : String_List_Id := Ignore;
7124
7125                         begin
7126                            Canonical_Case_File_Name (Dir_Name);
7127
7128                            while List /= Nil_String loop
7129                               Get_Name_String
7130                                 (Shared.String_Elements.Table (List).Value);
7131                               Canonical_Case_File_Name
7132                                 (Name_Buffer (1 .. Name_Len));
7133                               OK := Name_Buffer (1 .. Name_Len) /= Dir_Name;
7134                               exit when not OK;
7135                               List := Shared.String_Elements.Table (List).Next;
7136                            end loop;
7137                         end;
7138                      end if;
7139
7140                      if OK then
7141                         Name_Len := 0;
7142                         Add_Str_To_Name_Buffer (Path_Name);
7143                         Path2.Display_Name := Name_Find;
7144
7145                         Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
7146                         Path2.Name := Name_Find;
7147
7148                         Success :=
7149                           Recursive_Find_Dirs (Path2, Rank) or Success;
7150                      end if;
7151                   end if;
7152                end;
7153             end if;
7154          end loop;
7155
7156          Close (Dir);
7157
7158          return Success;
7159
7160       exception
7161          when Directory_Error =>
7162             return Success;
7163       end Recursive_Find_Dirs;
7164
7165       ------------------
7166       -- Find_Pattern --
7167       ------------------
7168
7169       procedure Find_Pattern
7170         (Pattern_Id : Name_Id;
7171          Rank       : Natural;
7172          Location   : Source_Ptr)
7173       is
7174          Pattern     : constant String := Get_Name_String (Pattern_Id);
7175          Pattern_End : Natural := Pattern'Last;
7176          Recursive   : Boolean;
7177          Dir         : File_Name_Type;
7178          Path_Name   : Path_Information;
7179          Dir_Exists  : Boolean;
7180          Has_Error   : Boolean := False;
7181          Success     : Boolean;
7182
7183       begin
7184          Debug_Increase_Indent ("Find_Pattern", Pattern_Id);
7185
7186          --  If we are looking for files, find the pattern for the files
7187
7188          if Search_For = Search_Files then
7189             while Pattern_End >= Pattern'First
7190               and then Pattern (Pattern_End) /= '/'
7191               and then Pattern (Pattern_End) /= Directory_Separator
7192             loop
7193                Pattern_End := Pattern_End - 1;
7194             end loop;
7195
7196             if Pattern_End = Pattern'Last then
7197                Err_Vars.Error_Msg_File_1 := File_Name_Type (Pattern_Id);
7198                Error_Or_Warning
7199                  (Data.Flags, Data.Flags.Missing_Source_Files,
7200                   "Missing file name or pattern in {", Location, Project);
7201                return;
7202             end if;
7203
7204             if Current_Verbosity = High then
7205                Debug_Indent;
7206                Write_Str ("file_pattern=");
7207                Write_Str (Pattern (Pattern_End + 1 .. Pattern'Last));
7208                Write_Str (" dir_pattern=");
7209                Write_Line (Pattern (Pattern'First .. Pattern_End));
7210             end if;
7211
7212             File_Pattern := Compile
7213               (Pattern (Pattern_End + 1 .. Pattern'Last),
7214                Glob           => True,
7215                Case_Sensitive => File_Names_Case_Sensitive);
7216
7217             --  If we had just "*.gpr", this is equivalent to "./*.gpr"
7218
7219             if Pattern_End > Pattern'First then
7220                Pattern_End := Pattern_End - 1; --  Skip directory separator
7221             end if;
7222          end if;
7223
7224          Recursive :=
7225            Pattern_End - 1 >= Pattern'First
7226            and then Pattern (Pattern_End - 1 .. Pattern_End) = "**"
7227            and then (Pattern_End - 1 = Pattern'First
7228                      or else Pattern (Pattern_End - 2) = '/'
7229                      or else Pattern (Pattern_End - 2) = Directory_Separator);
7230
7231          if Recursive then
7232             Pattern_End := Pattern_End - 2;
7233             if Pattern_End > Pattern'First then
7234                Pattern_End := Pattern_End - 1; --  Skip '/'
7235             end if;
7236          end if;
7237
7238          Name_Len := Pattern_End - Pattern'First + 1;
7239          Name_Buffer (1 .. Name_Len) := Pattern (Pattern'First .. Pattern_End);
7240          Dir := Name_Find;
7241
7242          Locate_Directory
7243            (Project     => Project,
7244             Name        => Dir,
7245             Path        => Path_Name,
7246             Dir_Exists  => Dir_Exists,
7247             Data        => Data,
7248             Must_Exist  => False);
7249
7250          if not Dir_Exists then
7251             Err_Vars.Error_Msg_File_1 := Dir;
7252             Error_Or_Warning
7253               (Data.Flags, Data.Flags.Missing_Source_Files,
7254                "{ is not a valid directory", Location, Project);
7255             Has_Error := Data.Flags.Missing_Source_Files = Error;
7256          end if;
7257
7258          if not Has_Error then
7259
7260             --  Links have been resolved if necessary, and Path_Name
7261             --  always ends with a directory separator.
7262
7263             if Recursive then
7264                Success := Recursive_Find_Dirs (Path_Name, Rank);
7265             else
7266                Success := Subdirectory_Matches (Path_Name, Rank);
7267             end if;
7268
7269             if not Success then
7270                case Search_For is
7271                   when Search_Directories =>
7272                      null;  --  Error can't occur
7273
7274                   when Search_Files =>
7275                      Err_Vars.Error_Msg_File_1 := File_Name_Type (Pattern_Id);
7276                      Error_Or_Warning
7277                        (Data.Flags, Data.Flags.Missing_Source_Files,
7278                         "file { not found", Location, Project);
7279                end case;
7280             end if;
7281          end if;
7282
7283          Debug_Decrease_Indent ("done Find_Pattern");
7284       end Find_Pattern;
7285
7286       --  Local variables
7287
7288       Pattern_Id : String_List_Id := Patterns;
7289       Element    : String_Element;
7290       Rank       : Natural := 1;
7291
7292    --  Start of processing for Expand_Subdirectory_Pattern
7293
7294    begin
7295       while Pattern_Id /= Nil_String loop
7296          Element := Shared.String_Elements.Table (Pattern_Id);
7297          Find_Pattern (Element.Value, Rank, Element.Location);
7298          Rank := Rank + 1;
7299          Pattern_Id := Element.Next;
7300       end loop;
7301
7302       Recursive_Dirs.Reset (Visited);
7303    end Expand_Subdirectory_Pattern;
7304
7305    ------------------------
7306    -- Search_Directories --
7307    ------------------------
7308
7309    procedure Search_Directories
7310      (Project         : in out Project_Processing_Data;
7311       Data            : in out Tree_Processing_Data;
7312       For_All_Sources : Boolean)
7313    is
7314       Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
7315
7316       Source_Dir        : String_List_Id;
7317       Element           : String_Element;
7318       Src_Dir_Rank      : Number_List_Index;
7319       Num_Nod           : Number_Node;
7320       Dir               : Dir_Type;
7321       Name              : String (1 .. 1_000);
7322       Last              : Natural;
7323       File_Name         : File_Name_Type;
7324       Display_File_Name : File_Name_Type;
7325
7326    begin
7327       Debug_Increase_Indent ("looking for sources of", Project.Project.Name);
7328
7329       --  Loop through subdirectories
7330
7331       Src_Dir_Rank := Project.Project.Source_Dir_Ranks;
7332
7333       Source_Dir := Project.Project.Source_Dirs;
7334       while Source_Dir /= Nil_String loop
7335          begin
7336             Num_Nod := Shared.Number_Lists.Table (Src_Dir_Rank);
7337             Element := Shared.String_Elements.Table (Source_Dir);
7338
7339             --  Use Element.Value in this test, not Display_Value, because we
7340             --  want the symbolic links to be resolved when appropriate.
7341
7342             if Element.Value /= No_Name then
7343                declare
7344                   Source_Directory : constant String :=
7345                                        Get_Name_String (Element.Value)
7346                                          & Directory_Separator;
7347
7348                   Dir_Last : constant Natural :=
7349                                Compute_Directory_Last (Source_Directory);
7350
7351                   Display_Source_Directory : constant String :=
7352                                                Get_Name_String
7353                                                  (Element.Display_Value)
7354                                                   & Directory_Separator;
7355                   --  Display_Source_Directory is to allow us to open a UTF-8
7356                   --  encoded directory on Windows.
7357
7358                begin
7359                   if Current_Verbosity = High then
7360                      Debug_Increase_Indent
7361                        ("Source_Dir (node=" & Num_Nod.Number'Img & ") """
7362                         & Source_Directory (Source_Directory'First .. Dir_Last)
7363                         & '"');
7364                   end if;
7365
7366                   --  We look to every entry in the source directory
7367
7368                   Open (Dir, Display_Source_Directory);
7369
7370                   loop
7371                      Read (Dir, Name, Last);
7372                      exit when Last = 0;
7373
7374                      --  In fast project loading mode (without -eL), the user
7375                      --  guarantees that no directory has a name which is a
7376                      --  valid source name, so we can avoid doing a system call
7377                      --  here. This provides a very significant speed up on
7378                      --  slow file systems (remote files for instance).
7379
7380                      if not Opt.Follow_Links_For_Files
7381                        or else Is_Regular_File
7382                                  (Display_Source_Directory & Name (1 .. Last))
7383                      then
7384                         Name_Len := Last;
7385                         Name_Buffer (1 .. Name_Len) := Name (1 .. Last);
7386                         Display_File_Name := Name_Find;
7387
7388                         if Osint.File_Names_Case_Sensitive then
7389                            File_Name := Display_File_Name;
7390                         else
7391                            Canonical_Case_File_Name
7392                              (Name_Buffer (1 .. Name_Len));
7393                            File_Name := Name_Find;
7394                         end if;
7395
7396                         declare
7397                            Path_Name : constant String :=
7398                                          Normalize_Pathname
7399                                            (Name (1 .. Last),
7400                                             Directory       =>
7401                                               Source_Directory
7402                                                 (Source_Directory'First ..
7403                                                  Dir_Last),
7404                                             Resolve_Links   =>
7405                                               Opt.Follow_Links_For_Files,
7406                                             Case_Sensitive => True);
7407
7408                            Path      : Path_Name_Type;
7409                            FF        : File_Found :=
7410                                          Excluded_Sources_Htable.Get
7411                                            (Project.Excluded, File_Name);
7412                            To_Remove : Boolean := False;
7413
7414                         begin
7415                            Name_Len := Path_Name'Length;
7416                            Name_Buffer (1 .. Name_Len) := Path_Name;
7417
7418                            if Osint.File_Names_Case_Sensitive then
7419                               Path := Name_Find;
7420                            else
7421                               Canonical_Case_File_Name
7422                                 (Name_Buffer (1 .. Name_Len));
7423                               Path := Name_Find;
7424                            end if;
7425
7426                            if FF /= No_File_Found then
7427                               if not FF.Found then
7428                                  FF.Found := True;
7429                                  Excluded_Sources_Htable.Set
7430                                    (Project.Excluded, File_Name, FF);
7431
7432                                  Debug_Output
7433                                    ("excluded source ",
7434                                     Name_Id (Display_File_Name));
7435
7436                                  --  Will mark the file as removed, but we
7437                                  --  still need to add it to the list: if we
7438                                  --  don't, the file will not appear in the
7439                                  --  mapping file and will cause the compiler
7440                                  --  to fail.
7441
7442                                  To_Remove := True;
7443                               end if;
7444                            end if;
7445
7446                            --  Preserve the user's original casing and use of
7447                            --  links. The display_value (a directory) already
7448                            --  ends with a directory separator by construction,
7449                            --  so no need to add one.
7450
7451                            Get_Name_String (Element.Display_Value);
7452                            Get_Name_String_And_Append (Display_File_Name);
7453
7454                            Check_File
7455                              (Project           => Project,
7456                               Source_Dir_Rank   => Num_Nod.Number,
7457                               Data              => Data,
7458                               Path              => Path,
7459                               Display_Path      => Name_Find,
7460                               File_Name         => File_Name,
7461                               Locally_Removed   => To_Remove,
7462                               Display_File_Name => Display_File_Name,
7463                               For_All_Sources   => For_All_Sources);
7464                         end;
7465
7466                      else
7467                         if Current_Verbosity = High then
7468                            Debug_Output ("ignore " & Name (1 .. Last));
7469                         end if;
7470                      end if;
7471                   end loop;
7472
7473                   Debug_Decrease_Indent;
7474                   Close (Dir);
7475                end;
7476             end if;
7477
7478          exception
7479             when Directory_Error =>
7480                null;
7481          end;
7482
7483          Source_Dir := Element.Next;
7484          Src_Dir_Rank := Num_Nod.Next;
7485       end loop;
7486
7487       Debug_Decrease_Indent ("end looking for sources.");
7488    end Search_Directories;
7489
7490    ----------------------------
7491    -- Load_Naming_Exceptions --
7492    ----------------------------
7493
7494    procedure Load_Naming_Exceptions
7495      (Project : in out Project_Processing_Data;
7496       Data    : in out Tree_Processing_Data)
7497    is
7498       Source : Source_Id;
7499       Iter   : Source_Iterator;
7500
7501    begin
7502       Iter := For_Each_Source (Data.Tree, Project.Project);
7503       loop
7504          Source := Prj.Element (Iter);
7505          exit when Source = No_Source;
7506
7507          --  An excluded file cannot also be an exception file name
7508
7509          if Excluded_Sources_Htable.Get (Project.Excluded, Source.File) /=
7510                                                                  No_File_Found
7511          then
7512             Error_Msg_File_1 := Source.File;
7513             Error_Msg
7514               (Data.Flags,
7515                "{ cannot be both excluded and an exception file name",
7516                No_Location, Project.Project);
7517          end if;
7518
7519          Debug_Output
7520            ("naming exception: adding source file to source_Names: ",
7521             Name_Id (Source.File));
7522
7523          Source_Names_Htable.Set
7524            (Project.Source_Names,
7525             K => Source.File,
7526             E => Name_Location'
7527                   (Name     => Source.File,
7528                    Location => Source.Location,
7529                    Source   => Source,
7530                    Listed   => False,
7531                    Found    => False));
7532
7533          --  If this is an Ada exception, record in table Unit_Exceptions
7534
7535          if Source.Unit /= No_Unit_Index then
7536             declare
7537                Unit_Except : Unit_Exception :=
7538                                Unit_Exceptions_Htable.Get
7539                                  (Project.Unit_Exceptions, Source.Unit.Name);
7540
7541             begin
7542                Unit_Except.Name := Source.Unit.Name;
7543
7544                if Source.Kind = Spec then
7545                   Unit_Except.Spec := Source.File;
7546                else
7547                   Unit_Except.Impl := Source.File;
7548                end if;
7549
7550                Unit_Exceptions_Htable.Set
7551                  (Project.Unit_Exceptions, Source.Unit.Name, Unit_Except);
7552             end;
7553          end if;
7554
7555          Next (Iter);
7556       end loop;
7557    end Load_Naming_Exceptions;
7558
7559    ----------------------
7560    -- Look_For_Sources --
7561    ----------------------
7562
7563    procedure Look_For_Sources
7564      (Project : in out Project_Processing_Data;
7565       Data    : in out Tree_Processing_Data)
7566    is
7567       Object_Files : Object_File_Names_Htable.Instance;
7568       Iter         : Source_Iterator;
7569       Src          : Source_Id;
7570
7571       procedure Check_Object (Src : Source_Id);
7572       --  Check if object file name of Src is already used in the project tree,
7573       --  and report an error if so.
7574
7575       procedure Check_Object_Files;
7576       --  Check that no two sources of this project have the same object file
7577
7578       procedure Mark_Excluded_Sources;
7579       --  Mark as such the sources that are declared as excluded
7580
7581       procedure Check_Missing_Sources;
7582       --  Check whether one of the languages has no sources, and report an
7583       --  error when appropriate
7584
7585       procedure Get_Sources_From_Source_Info;
7586       --  Get the source information from the tables that were created when a
7587       --  source info file was read.
7588
7589       ---------------------------
7590       -- Check_Missing_Sources --
7591       ---------------------------
7592
7593       procedure Check_Missing_Sources is
7594          Extending    : constant Boolean :=
7595                           Project.Project.Extends /= No_Project;
7596          Language     : Language_Ptr;
7597          Source       : Source_Id;
7598          Alt_Lang     : Language_List;
7599          Continuation : Boolean := False;
7600          Iter         : Source_Iterator;
7601       begin
7602          if not Project.Project.Externally_Built
7603            and then not Extending
7604          then
7605             Language := Project.Project.Languages;
7606             while Language /= No_Language_Index loop
7607
7608                --  If there are no sources for this language, check if there
7609                --  are sources for which this is an alternate language.
7610
7611                if Language.First_Source = No_Source
7612                  and then (Data.Flags.Require_Sources_Other_Lang
7613                            or else Language.Name = Name_Ada)
7614                then
7615                   Iter := For_Each_Source (In_Tree => Data.Tree,
7616                                            Project => Project.Project);
7617                   Source_Loop : loop
7618                      Source := Element (Iter);
7619                      exit Source_Loop when Source = No_Source
7620                        or else Source.Language = Language;
7621
7622                      Alt_Lang := Source.Alternate_Languages;
7623                      while Alt_Lang /= null loop
7624                         exit Source_Loop when Alt_Lang.Language = Language;
7625                         Alt_Lang := Alt_Lang.Next;
7626                      end loop;
7627
7628                      Next (Iter);
7629                   end loop Source_Loop;
7630
7631                   if Source = No_Source then
7632                      Report_No_Sources
7633                        (Project.Project,
7634                         Get_Name_String (Language.Display_Name),
7635                         Data,
7636                         Project.Source_List_File_Location,
7637                         Continuation);
7638                      Continuation := True;
7639                   end if;
7640                end if;
7641
7642                Language := Language.Next;
7643             end loop;
7644          end if;
7645       end Check_Missing_Sources;
7646
7647       ------------------
7648       -- Check_Object --
7649       ------------------
7650
7651       procedure Check_Object (Src : Source_Id) is
7652          Source : Source_Id;
7653
7654       begin
7655          Source := Object_File_Names_Htable.Get (Object_Files, Src.Object);
7656
7657          --  We cannot just check on "Source /= Src", since we might have
7658          --  two different entries for the same file (and since that's
7659          --  the same file it is expected that it has the same object)
7660
7661          if Source /= No_Source
7662            and then Source.Replaced_By = No_Source
7663            and then Source.Path /= Src.Path
7664            and then Is_Extending (Src.Project, Source.Project)
7665          then
7666             Error_Msg_File_1 := Src.File;
7667             Error_Msg_File_2 := Source.File;
7668             Error_Msg
7669               (Data.Flags,
7670                "{ and { have the same object file name",
7671                No_Location, Project.Project);
7672
7673          else
7674             Object_File_Names_Htable.Set (Object_Files, Src.Object, Src);
7675          end if;
7676       end Check_Object;
7677
7678       ---------------------------
7679       -- Mark_Excluded_Sources --
7680       ---------------------------
7681
7682       procedure Mark_Excluded_Sources is
7683          Source   : Source_Id := No_Source;
7684          Excluded : File_Found;
7685          Proj     : Project_Id;
7686
7687       begin
7688          --  Minor optimization: if there are no excluded files, no need to
7689          --  traverse the list of sources. We cannot however also check whether
7690          --  the existing exceptions have ".Found" set to True (indicating we
7691          --  found them before) because we need to do some final processing on
7692          --  them in any case.
7693
7694          if Excluded_Sources_Htable.Get_First (Project.Excluded) /=
7695                                                              No_File_Found
7696          then
7697             Proj := Project.Project;
7698             while Proj /= No_Project loop
7699                Iter := For_Each_Source (Data.Tree, Proj);
7700                while Prj.Element (Iter) /= No_Source loop
7701                   Source   := Prj.Element (Iter);
7702                   Excluded := Excluded_Sources_Htable.Get
7703                     (Project.Excluded, Source.File);
7704
7705                   if Excluded /= No_File_Found then
7706                      Source.Locally_Removed := True;
7707                      Source.In_Interfaces   := False;
7708
7709                      if Current_Verbosity = High then
7710                         Debug_Indent;
7711                         Write_Str ("removing file ");
7712                         Write_Line
7713                           (Get_Name_String (Excluded.File)
7714                            & " " & Get_Name_String (Source.Project.Name));
7715                      end if;
7716
7717                      Excluded_Sources_Htable.Remove
7718                        (Project.Excluded, Source.File);
7719                   end if;
7720
7721                   Next (Iter);
7722                end loop;
7723
7724                Proj := Proj.Extends;
7725             end loop;
7726          end if;
7727
7728          --  If we have any excluded element left, that means we did not find
7729          --  the source file
7730
7731          Excluded := Excluded_Sources_Htable.Get_First (Project.Excluded);
7732          while Excluded /= No_File_Found loop
7733             if not Excluded.Found then
7734
7735                --  Check if the file belongs to another imported project to
7736                --  provide a better error message.
7737
7738                Src := Find_Source
7739                  (In_Tree          => Data.Tree,
7740                   Project          => Project.Project,
7741                   In_Imported_Only => True,
7742                   Base_Name        => Excluded.File);
7743
7744                Err_Vars.Error_Msg_File_1 := Excluded.File;
7745
7746                if Src = No_Source then
7747                   if Excluded.Excl_File = No_File then
7748                      Error_Msg
7749                        (Data.Flags,
7750                         "unknown file {", Excluded.Location, Project.Project);
7751
7752                   else
7753                      Error_Msg
7754                     (Data.Flags,
7755                      "in " &
7756                      Get_Name_String (Excluded.Excl_File) & ":" &
7757                      No_Space_Img (Excluded.Excl_Line) &
7758                      ": unknown file {", Excluded.Location, Project.Project);
7759                   end if;
7760
7761                else
7762                   if Excluded.Excl_File = No_File then
7763                      Error_Msg
7764                        (Data.Flags,
7765                         "cannot remove a source from an imported project: {",
7766                         Excluded.Location, Project.Project);
7767
7768                   else
7769                      Error_Msg
7770                        (Data.Flags,
7771                         "in " &
7772                         Get_Name_String (Excluded.Excl_File) & ":" &
7773                           No_Space_Img (Excluded.Excl_Line) &
7774                         ": cannot remove a source from an imported project: {",
7775                         Excluded.Location, Project.Project);
7776                   end if;
7777                end if;
7778             end if;
7779
7780             Excluded := Excluded_Sources_Htable.Get_Next (Project.Excluded);
7781          end loop;
7782       end Mark_Excluded_Sources;
7783
7784       ------------------------
7785       -- Check_Object_Files --
7786       ------------------------
7787
7788       procedure Check_Object_Files is
7789          Iter    : Source_Iterator;
7790          Src_Id  : Source_Id;
7791          Src_Ind : Source_File_Index;
7792
7793       begin
7794          Iter := For_Each_Source (Data.Tree);
7795          loop
7796             Src_Id := Prj.Element (Iter);
7797             exit when Src_Id = No_Source;
7798
7799             if Is_Compilable (Src_Id)
7800               and then Src_Id.Language.Config.Object_Generated
7801               and then Is_Extending (Project.Project, Src_Id.Project)
7802             then
7803                if Src_Id.Unit = No_Unit_Index then
7804                   if Src_Id.Kind = Impl then
7805                      Check_Object (Src_Id);
7806                   end if;
7807
7808                else
7809                   case Src_Id.Kind is
7810                      when Spec =>
7811                         if Other_Part (Src_Id) = No_Source then
7812                            Check_Object (Src_Id);
7813                         end if;
7814
7815                      when Sep =>
7816                         null;
7817
7818                      when Impl =>
7819                         if Other_Part (Src_Id) /= No_Source then
7820                            Check_Object (Src_Id);
7821
7822                         else
7823                            --  Check if it is a subunit
7824
7825                            Src_Ind :=
7826                              Sinput.P.Load_Project_File
7827                                (Get_Name_String (Src_Id.Path.Display_Name));
7828
7829                            if Sinput.P.Source_File_Is_Subunit (Src_Ind) then
7830                               Override_Kind (Src_Id, Sep);
7831                            else
7832                               Check_Object (Src_Id);
7833                            end if;
7834                         end if;
7835                   end case;
7836                end if;
7837             end if;
7838
7839             Next (Iter);
7840          end loop;
7841       end Check_Object_Files;
7842
7843       ----------------------------------
7844       -- Get_Sources_From_Source_Info --
7845       ----------------------------------
7846
7847       procedure Get_Sources_From_Source_Info is
7848          Iter    : Source_Info_Iterator;
7849          Src     : Source_Info;
7850          Id      : Source_Id;
7851          Lang_Id : Language_Ptr;
7852
7853       begin
7854          Initialize (Iter, Project.Project.Name);
7855
7856          loop
7857             Src := Source_Info_Of (Iter);
7858
7859             exit when Src = No_Source_Info;
7860
7861             Id := new Source_Data;
7862
7863             Id.Project := Project.Project;
7864
7865             Lang_Id := Project.Project.Languages;
7866             while Lang_Id /= No_Language_Index
7867               and then Lang_Id.Name /= Src.Language
7868             loop
7869                Lang_Id := Lang_Id.Next;
7870             end loop;
7871
7872             if Lang_Id = No_Language_Index then
7873                Prj.Com.Fail
7874                  ("unknown language " &
7875                   Get_Name_String (Src.Language) &
7876                   " for project " &
7877                   Get_Name_String (Src.Project) &
7878                   " in source info file");
7879             end if;
7880
7881             Id.Language := Lang_Id;
7882             Id.Kind     := Src.Kind;
7883             Id.Index    := Src.Index;
7884
7885             Id.Path :=
7886               (Path_Name_Type (Src.Display_Path_Name),
7887                Path_Name_Type (Src.Path_Name));
7888
7889             Name_Len := 0;
7890             Add_Str_To_Name_Buffer
7891               (Directories.Simple_Name (Get_Name_String (Src.Path_Name)));
7892             Id.File := Name_Find;
7893
7894             Id.Next_With_File_Name :=
7895               Source_Files_Htable.Get (Data.Tree.Source_Files_HT, Id.File);
7896             Source_Files_Htable.Set (Data.Tree.Source_Files_HT, Id.File, Id);
7897
7898             Name_Len := 0;
7899             Add_Str_To_Name_Buffer
7900               (Directories.Simple_Name
7901                  (Get_Name_String (Src.Display_Path_Name)));
7902             Id.Display_File := Name_Find;
7903
7904             Id.Dep_Name         :=
7905               Dependency_Name (Id.File, Id.Language.Config.Dependency_Kind);
7906             Id.Naming_Exception := Src.Naming_Exception;
7907             Id.Object           :=
7908               Object_Name (Id.File, Id.Language.Config.Object_File_Suffix);
7909             Id.Switches         := Switches_Name (Id.File);
7910
7911             --  Add the source id to the Unit_Sources_HT hash table, if the
7912             --  unit name is not null.
7913
7914             if Src.Kind /= Sep and then Src.Unit_Name /= No_Name then
7915
7916                declare
7917                   UData : Unit_Index :=
7918                             Units_Htable.Get
7919                               (Data.Tree.Units_HT, Src.Unit_Name);
7920                begin
7921                   if UData = No_Unit_Index then
7922                      UData := new Unit_Data;
7923                      UData.Name := Src.Unit_Name;
7924                      Units_Htable.Set
7925                        (Data.Tree.Units_HT, Src.Unit_Name, UData);
7926                   end if;
7927
7928                   Id.Unit := UData;
7929                end;
7930
7931                --  Note that this updates Unit information as well
7932
7933                Override_Kind (Id, Id.Kind);
7934             end if;
7935
7936             if Src.Index /= 0 then
7937                Project.Project.Has_Multi_Unit_Sources := True;
7938             end if;
7939
7940             --  Add the source to the language list
7941
7942             Id.Next_In_Lang := Id.Language.First_Source;
7943             Id.Language.First_Source := Id;
7944
7945             Next (Iter);
7946          end loop;
7947       end Get_Sources_From_Source_Info;
7948
7949    --  Start of processing for Look_For_Sources
7950
7951    begin
7952       if Data.Tree.Source_Info_File_Exists then
7953          Get_Sources_From_Source_Info;
7954
7955       else
7956          if Project.Project.Source_Dirs /= Nil_String then
7957             Find_Excluded_Sources (Project, Data);
7958
7959             if Project.Project.Languages /= No_Language_Index then
7960                Load_Naming_Exceptions (Project, Data);
7961                Find_Sources (Project, Data);
7962                Mark_Excluded_Sources;
7963                Check_Object_Files;
7964                Check_Missing_Sources;
7965             end if;
7966          end if;
7967
7968          Object_File_Names_Htable.Reset (Object_Files);
7969       end if;
7970    end Look_For_Sources;
7971
7972    ------------------
7973    -- Path_Name_Of --
7974    ------------------
7975
7976    function Path_Name_Of
7977      (File_Name : File_Name_Type;
7978       Directory : Path_Name_Type) return String
7979    is
7980       Result        : String_Access;
7981       The_Directory : constant String := Get_Name_String (Directory);
7982
7983    begin
7984       Debug_Output ("Path_Name_Of file name=", Name_Id (File_Name));
7985       Debug_Output ("Path_Name_Of directory=", Name_Id (Directory));
7986       Get_Name_String (File_Name);
7987       Result :=
7988         Locate_Regular_File
7989           (File_Name => Name_Buffer (1 .. Name_Len),
7990            Path      => The_Directory);
7991
7992       if Result = null then
7993          return "";
7994       else
7995          declare
7996             R : constant String := Result.all;
7997          begin
7998             Free (Result);
7999             return R;
8000          end;
8001       end if;
8002    end Path_Name_Of;
8003
8004    -------------------
8005    -- Remove_Source --
8006    -------------------
8007
8008    procedure Remove_Source
8009      (Tree        : Project_Tree_Ref;
8010       Id          : Source_Id;
8011       Replaced_By : Source_Id)
8012    is
8013       Source : Source_Id;
8014
8015    begin
8016       if Current_Verbosity = High then
8017          Debug_Indent;
8018          Write_Str ("removing source ");
8019          Write_Str (Get_Name_String (Id.File));
8020
8021          if Id.Index /= 0 then
8022             Write_Str (" at" & Id.Index'Img);
8023          end if;
8024
8025          Write_Eol;
8026       end if;
8027
8028       if Replaced_By /= No_Source then
8029          Id.Replaced_By := Replaced_By;
8030          Replaced_By.Declared_In_Interfaces := Id.Declared_In_Interfaces;
8031
8032          if Id.File /= Replaced_By.File then
8033             declare
8034                Replacement : constant File_Name_Type :=
8035                                Replaced_Source_HTable.Get
8036                                  (Tree.Replaced_Sources, Id.File);
8037
8038             begin
8039                Replaced_Source_HTable.Set
8040                  (Tree.Replaced_Sources, Id.File, Replaced_By.File);
8041
8042                if Replacement = No_File then
8043                   Tree.Replaced_Source_Number :=
8044                     Tree.Replaced_Source_Number + 1;
8045                end if;
8046             end;
8047          end if;
8048       end if;
8049
8050       Id.In_Interfaces := False;
8051       Id.Locally_Removed := True;
8052
8053       --  ??? Should we remove the source from the unit ? The file is not used,
8054       --  so probably should not be referenced from the unit. On the other hand
8055       --  it might give useful additional info
8056       --        if Id.Unit /= null then
8057       --           Id.Unit.File_Names (Id.Kind) := null;
8058       --        end if;
8059
8060       Source := Id.Language.First_Source;
8061
8062       if Source = Id then
8063          Id.Language.First_Source := Id.Next_In_Lang;
8064
8065       else
8066          while Source.Next_In_Lang /= Id loop
8067             Source := Source.Next_In_Lang;
8068          end loop;
8069
8070          Source.Next_In_Lang := Id.Next_In_Lang;
8071       end if;
8072    end Remove_Source;
8073
8074    -----------------------
8075    -- Report_No_Sources --
8076    -----------------------
8077
8078    procedure Report_No_Sources
8079      (Project      : Project_Id;
8080       Lang_Name    : String;
8081       Data         : Tree_Processing_Data;
8082       Location     : Source_Ptr;
8083       Continuation : Boolean := False)
8084    is
8085    begin
8086       case Data.Flags.When_No_Sources is
8087          when Silent =>
8088             null;
8089
8090          when Warning | Error =>
8091             declare
8092                Msg : constant String :=
8093                       "<there are no "
8094                       & Lang_Name & " sources in this project";
8095
8096             begin
8097                Error_Msg_Warn := Data.Flags.When_No_Sources = Warning;
8098
8099                if Continuation then
8100                   Error_Msg (Data.Flags, "\" & Msg, Location, Project);
8101                else
8102                   Error_Msg (Data.Flags, Msg, Location, Project);
8103                end if;
8104             end;
8105       end case;
8106    end Report_No_Sources;
8107
8108    ----------------------
8109    -- Show_Source_Dirs --
8110    ----------------------
8111
8112    procedure Show_Source_Dirs
8113      (Project : Project_Id;
8114       Shared  : Shared_Project_Tree_Data_Access)
8115    is
8116       Current : String_List_Id;
8117       Element : String_Element;
8118
8119    begin
8120       if Project.Source_Dirs = Nil_String then
8121          Debug_Output ("no Source_Dirs");
8122       else
8123          Debug_Increase_Indent ("Source_Dirs:");
8124
8125          Current := Project.Source_Dirs;
8126          while Current /= Nil_String loop
8127             Element := Shared.String_Elements.Table (Current);
8128             Debug_Output (Get_Name_String (Element.Display_Value));
8129             Current := Element.Next;
8130          end loop;
8131
8132          Debug_Decrease_Indent ("end Source_Dirs.");
8133       end if;
8134    end Show_Source_Dirs;
8135
8136    ---------------------------
8137    -- Process_Naming_Scheme --
8138    ---------------------------
8139
8140    procedure Process_Naming_Scheme
8141      (Tree         : Project_Tree_Ref;
8142       Root_Project : Project_Id;
8143       Node_Tree    : Prj.Tree.Project_Node_Tree_Ref;
8144       Flags        : Processing_Flags)
8145    is
8146
8147       procedure Check
8148         (Project          : Project_Id;
8149          In_Aggregate_Lib : Boolean;
8150          Data             : in out Tree_Processing_Data);
8151       --  Process the naming scheme for a single project
8152
8153       procedure Recursive_Check
8154         (Project  : Project_Id;
8155          Prj_Tree : Project_Tree_Ref;
8156          Context  : Project_Context;
8157          Data     : in out Tree_Processing_Data);
8158       --  Check_Naming_Scheme for the project
8159
8160       -----------
8161       -- Check --
8162       -----------
8163
8164       procedure Check
8165         (Project          : Project_Id;
8166          In_Aggregate_Lib : Boolean;
8167          Data             : in out Tree_Processing_Data)
8168       is
8169          procedure Check_Aggregate
8170            (Project : Project_Id;
8171             Data    : in out Tree_Processing_Data);
8172          --  Check the aggregate project attributes, reject any not supported
8173          --  attributes.
8174
8175          procedure Check_Aggregated
8176            (Project : Project_Id;
8177             Data    : in out Tree_Processing_Data);
8178          --  Check aggregated projects which should not be externally built.
8179          --  What is Data??? if same as outer Data, why passed???
8180          --  What exact check is performed here??? Seems a bad idea to have
8181          --  two procedures with such close names ???
8182
8183          ---------------------
8184          -- Check_Aggregate --
8185          ---------------------
8186
8187          procedure Check_Aggregate
8188            (Project : Project_Id;
8189             Data    : in out Tree_Processing_Data)
8190          is
8191             procedure Check_Not_Defined (Name : Name_Id);
8192             --  Report an error if Var is defined
8193
8194             -----------------------
8195             -- Check_Not_Defined --
8196             -----------------------
8197
8198             procedure Check_Not_Defined (Name : Name_Id) is
8199                Var : constant Prj.Variable_Value :=
8200                        Prj.Util.Value_Of
8201                          (Name,
8202                           Project.Decl.Attributes,
8203                           Data.Tree.Shared);
8204             begin
8205                if not Var.Default then
8206                   Error_Msg_Name_1 := Name;
8207                   Error_Msg
8208                     (Data.Flags, "wrong attribute %% in aggregate library",
8209                      Var.Location, Project);
8210                end if;
8211             end Check_Not_Defined;
8212
8213          --  Start of processing for Check_Aggregate
8214
8215          begin
8216             Check_Not_Defined (Snames.Name_Library_Dir);
8217             Check_Not_Defined (Snames.Name_Library_Interface);
8218             Check_Not_Defined (Snames.Name_Library_Name);
8219             Check_Not_Defined (Snames.Name_Library_Ali_Dir);
8220             Check_Not_Defined (Snames.Name_Library_Src_Dir);
8221             Check_Not_Defined (Snames.Name_Library_Options);
8222             Check_Not_Defined (Snames.Name_Library_Standalone);
8223             Check_Not_Defined (Snames.Name_Library_Kind);
8224             Check_Not_Defined (Snames.Name_Leading_Library_Options);
8225             Check_Not_Defined (Snames.Name_Library_Version);
8226          end Check_Aggregate;
8227
8228          ----------------------
8229          -- Check_Aggregated --
8230          ----------------------
8231
8232          procedure Check_Aggregated
8233            (Project : Project_Id;
8234             Data    : in out Tree_Processing_Data)
8235          is
8236             L : Aggregated_Project_List;
8237
8238          begin
8239             --  Check that aggregated projects are not externally built
8240
8241             L := Project.Aggregated_Projects;
8242             while L /= null loop
8243                declare
8244                   Var : constant Prj.Variable_Value :=
8245                           Prj.Util.Value_Of
8246                             (Snames.Name_Externally_Built,
8247                              L.Project.Decl.Attributes,
8248                              Data.Tree.Shared);
8249                begin
8250                   if not Var.Default then
8251                      Error_Msg_Name_1 := L.Project.Display_Name;
8252                      Error_Msg
8253                        (Data.Flags,
8254                         "cannot aggregate externally build library %%",
8255                         Var.Location, Project);
8256                   end if;
8257                end;
8258
8259                L := L.Next;
8260             end loop;
8261          end Check_Aggregated;
8262
8263          --  Local Variables
8264
8265          Shared   : constant Shared_Project_Tree_Data_Access :=
8266                       Data.Tree.Shared;
8267          Prj_Data : Project_Processing_Data;
8268
8269       --  Start of processing for Check
8270
8271       begin
8272          Debug_Increase_Indent ("check", Project.Name);
8273
8274          Initialize (Prj_Data, Project);
8275
8276          Check_If_Externally_Built (Project, Data);
8277
8278          case Project.Qualifier is
8279             when Aggregate =>
8280                Check_Aggregated (Project, Data);
8281
8282             when Aggregate_Library =>
8283                Check_Aggregated (Project, Data);
8284
8285                if Project.Object_Directory = No_Path_Information then
8286                   Project.Object_Directory := Project.Directory;
8287                end if;
8288
8289             when others =>
8290                Get_Directories (Project, Data);
8291                Check_Programming_Languages (Project, Data);
8292
8293                if Current_Verbosity = High then
8294                   Show_Source_Dirs (Project, Shared);
8295                end if;
8296
8297                if Project.Qualifier = Dry then
8298                   Check_Abstract_Project (Project, Data);
8299                end if;
8300          end case;
8301
8302          --  Check configuration. Must be done for gnatmake (even though no
8303          --  user configuration file was provided) since the default config we
8304          --  generate indicates whether libraries are supported for instance.
8305
8306          Check_Configuration (Project, Data);
8307
8308          --  For aggregate project check no library attributes are defined
8309
8310          if Project.Qualifier = Aggregate then
8311             Check_Aggregate (Project, Data);
8312
8313          else
8314             Check_Library_Attributes (Project, Data);
8315             Check_Package_Naming (Project, Data);
8316
8317             --  An aggregate library has no source, no need to look for them
8318
8319             if Project.Qualifier /= Aggregate_Library then
8320                Look_For_Sources (Prj_Data, Data);
8321             end if;
8322
8323             Check_Interfaces (Project, Data);
8324
8325             --  If this library is part of an aggregated library don't check it
8326             --  as it has no sources by itself and so interface won't be found.
8327
8328             if Project.Library and not In_Aggregate_Lib then
8329                Check_Stand_Alone_Library (Project, Data);
8330             end if;
8331
8332             Get_Mains (Project, Data);
8333          end if;
8334
8335          Free (Prj_Data);
8336
8337          Debug_Decrease_Indent ("done check");
8338       end Check;
8339
8340       ---------------------
8341       -- Recursive_Check --
8342       ---------------------
8343
8344       procedure Recursive_Check
8345         (Project  : Project_Id;
8346          Prj_Tree : Project_Tree_Ref;
8347          Context  : Project_Context;
8348          Data     : in out Tree_Processing_Data)
8349       is
8350       begin
8351          if Current_Verbosity = High then
8352             Debug_Increase_Indent
8353               ("Processing_Naming_Scheme for project", Project.Name);
8354          end if;
8355
8356          Data.Tree := Prj_Tree;
8357          Data.In_Aggregate_Lib := Context.In_Aggregate_Lib;
8358
8359          Check (Project, Context.In_Aggregate_Lib, Data);
8360
8361          if Current_Verbosity = High then
8362             Debug_Decrease_Indent ("done Processing_Naming_Scheme");
8363          end if;
8364       end Recursive_Check;
8365
8366       procedure Check_All_Projects is new For_Every_Project_Imported_Context
8367         (Tree_Processing_Data, Recursive_Check);
8368       --  Comment required???
8369
8370       --  Local Variables
8371
8372       Data : Tree_Processing_Data;
8373
8374    --  Start of processing for Process_Naming_Scheme
8375
8376    begin
8377       Lib_Data_Table.Init;
8378       Initialize (Data, Tree => Tree, Node_Tree => Node_Tree, Flags => Flags);
8379       Check_All_Projects (Root_Project, Tree, Data, Imported_First => True);
8380       Free (Data);
8381
8382       --  Adjust language configs for projects that are extended
8383
8384       declare
8385          List : Project_List;
8386          Proj : Project_Id;
8387          Exte : Project_Id;
8388          Lang : Language_Ptr;
8389          Elng : Language_Ptr;
8390
8391       begin
8392          List := Tree.Projects;
8393          while List /= null loop
8394             Proj := List.Project;
8395
8396             Exte := Proj;
8397             while Exte.Extended_By /= No_Project loop
8398                Exte := Exte.Extended_By;
8399             end loop;
8400
8401             if Exte /= Proj then
8402                Lang := Proj.Languages;
8403
8404                if Lang /= No_Language_Index then
8405                   loop
8406                      Elng := Get_Language_From_Name
8407                        (Exte, Get_Name_String (Lang.Name));
8408                      exit when Elng /= No_Language_Index;
8409                      Exte := Exte.Extends;
8410                   end loop;
8411
8412                   if Elng /= Lang then
8413                      Lang.Config := Elng.Config;
8414                   end if;
8415                end if;
8416             end if;
8417
8418             List := List.Next;
8419          end loop;
8420       end;
8421    end Process_Naming_Scheme;
8422
8423 end Prj.Nmsc;