OSDN Git Service

2011-12-05 Bob Duff <duff@adacore.com>
[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-2011, 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    end record;
158    --  Temporary data which is needed while parsing a project. It does not need
159    --  to be kept in memory once a project has been fully loaded, but is
160    --  necessary while performing consistency checks (duplicate sources,...)
161    --  This data must be initialized before processing any project, and the
162    --  same data is used for processing all projects in the tree.
163
164    type Lib_Data is record
165       Name : Name_Id;
166       Proj : Project_Id;
167    end record;
168
169    package Lib_Data_Table is new GNAT.Table
170      (Table_Component_Type => Lib_Data,
171       Table_Index_Type     => Natural,
172       Table_Low_Bound      => 1,
173       Table_Initial        => 10,
174       Table_Increment      => 100);
175    --  A table to record library names in order to check that two library
176    --  projects do not have the same library names.
177
178    procedure Initialize
179      (Data      : out Tree_Processing_Data;
180       Tree      : Project_Tree_Ref;
181       Node_Tree : Prj.Tree.Project_Node_Tree_Ref;
182       Flags     : Prj.Processing_Flags);
183    --  Initialize Data
184
185    procedure Free (Data : in out Tree_Processing_Data);
186    --  Free the memory occupied by Data
187
188    procedure Check
189      (Project : Project_Id;
190       Data    : in out Tree_Processing_Data);
191    --  Process the naming scheme for a single project
192
193    procedure Initialize
194      (Data    : in out Project_Processing_Data;
195       Project : Project_Id);
196    procedure Free (Data : in out Project_Processing_Data);
197    --  Initialize or free memory for a project-specific data
198
199    procedure Find_Excluded_Sources
200      (Project : in out Project_Processing_Data;
201       Data    : in out Tree_Processing_Data);
202    --  Find the list of files that should not be considered as source files
203    --  for this project. Sets the list in the Project.Excluded_Sources_Htable.
204
205    procedure Override_Kind (Source : Source_Id; Kind : Source_Kind);
206    --  Override the reference kind for a source file. This properly updates
207    --  the unit data if necessary.
208
209    procedure Load_Naming_Exceptions
210      (Project : in out Project_Processing_Data;
211       Data    : in out Tree_Processing_Data);
212    --  All source files in Data.First_Source are considered as naming
213    --  exceptions, and copied into the Source_Names and Unit_Exceptions tables
214    --  as appropriate.
215
216    type Search_Type is (Search_Files, Search_Directories);
217
218    generic
219       with procedure Callback
220         (Path          : Path_Information;
221          Pattern_Index : Natural);
222    procedure Expand_Subdirectory_Pattern
223      (Project       : Project_Id;
224       Data          : in out Tree_Processing_Data;
225       Patterns      : String_List_Id;
226       Ignore        : String_List_Id;
227       Search_For    : Search_Type;
228       Resolve_Links : Boolean);
229    --  Search the subdirectories of Project's directory for files or
230    --  directories that match the globbing patterns found in Patterns (for
231    --  instance "**/*.adb"). Typically, Patterns will be the value of the
232    --  Source_Dirs or Excluded_Source_Dirs attributes.
233    --
234    --  Every time such a file or directory is found, the callback is called.
235    --  Resolve_Links indicates whether we should resolve links while
236    --  normalizing names.
237    --
238    --  In the callback, Pattern_Index is the index within Patterns where the
239    --  expanded pattern was found (1 for the first element of Patterns and
240    --  all its matching directories, then 2,...).
241    --
242    --  We use a generic and not an access-to-subprogram because in some cases
243    --  this code is compiled with the restriction No_Implicit_Dynamic_Code.
244    --  An error message is raised if a pattern does not match any file.
245
246    procedure Add_Source
247      (Id                  : out Source_Id;
248       Data                : in out Tree_Processing_Data;
249       Project             : Project_Id;
250       Source_Dir_Rank     : Natural;
251       Lang_Id             : Language_Ptr;
252       Kind                : Source_Kind;
253       File_Name           : File_Name_Type;
254       Display_File        : File_Name_Type;
255       Naming_Exception    : Naming_Exception_Type := No;
256       Path                : Path_Information      := No_Path_Information;
257       Alternate_Languages : Language_List         := null;
258       Unit                : Name_Id               := No_Name;
259       Index               : Int                   := 0;
260       Locally_Removed     : Boolean               := False;
261       Location            : Source_Ptr            := No_Location);
262    --  Add a new source to the different lists: list of all sources in the
263    --  project tree, list of source of a project and list of sources of a
264    --  language. If Path is specified, the file is also added to
265    --  Source_Paths_HT. Location is used for error messages
266
267    function Canonical_Case_File_Name (Name : Name_Id) return File_Name_Type;
268    --  Same as Osint.Canonical_Case_File_Name but applies to Name_Id.
269    --  This alters Name_Buffer.
270
271    function Suffix_Matches
272      (Filename : String;
273       Suffix   : File_Name_Type) return Boolean;
274    --  True if the file name ends with the given suffix. Always returns False
275    --  if Suffix is No_Name.
276
277    procedure Replace_Into_Name_Buffer
278      (Str         : String;
279       Pattern     : String;
280       Replacement : Character);
281    --  Copy Str into Name_Buffer, replacing Pattern with Replacement. Str is
282    --  converted to lower-case at the same time.
283
284    procedure Check_Abstract_Project
285      (Project : Project_Id;
286       Data    : in out Tree_Processing_Data);
287    --  Check abstract projects attributes
288
289    procedure Check_Configuration
290      (Project : Project_Id;
291       Data    : in out Tree_Processing_Data);
292    --  Check the configuration attributes for the project
293
294    procedure Check_If_Externally_Built
295      (Project : Project_Id;
296       Data    : in out Tree_Processing_Data);
297    --  Check attribute Externally_Built of project Project in project tree
298    --  Data.Tree and modify its data Data if it has the value "true".
299
300    procedure Check_Interfaces
301      (Project : Project_Id;
302       Data    : in out Tree_Processing_Data);
303    --  If a list of sources is specified in attribute Interfaces, set
304    --  In_Interfaces only for the sources specified in the list.
305
306    procedure Check_Library_Attributes
307      (Project : Project_Id;
308       Data    : in out Tree_Processing_Data);
309    --  Check the library attributes of project Project in project tree
310    --  and modify its data Data accordingly.
311
312    procedure Check_Package_Naming
313      (Project : Project_Id;
314       Data    : in out Tree_Processing_Data);
315    --  Check the naming scheme part of Data, and initialize the naming scheme
316    --  data in the config of the various languages.
317
318    procedure Check_Programming_Languages
319      (Project : Project_Id;
320       Data    : in out Tree_Processing_Data);
321    --  Check attribute Languages for the project with data Data in project
322    --  tree Data.Tree and set the components of Data for all the programming
323    --  languages indicated in attribute Languages, if any.
324
325    procedure Check_Stand_Alone_Library
326      (Project : Project_Id;
327       Data    : in out Tree_Processing_Data);
328    --  Check if project Project in project tree Data.Tree is a Stand-Alone
329    --  Library project, and modify its data Data accordingly if it is one.
330
331    procedure Check_Unit_Name (Name : String; Unit : out Name_Id);
332    --  Check that a name is a valid unit name
333
334    function Compute_Directory_Last (Dir : String) return Natural;
335    --  Return the index of the last significant character in Dir. This is used
336    --  to avoid duplicate '/' (slash) characters at the end of directory names.
337
338    procedure Search_Directories
339      (Project         : in out Project_Processing_Data;
340       Data            : in out Tree_Processing_Data;
341       For_All_Sources : Boolean);
342    --  Search the source directories to find the sources. If For_All_Sources is
343    --  True, check each regular file name against the naming schemes of the
344    --  various languages. Otherwise consider only the file names in hash table
345    --  Source_Names. If Allow_Duplicate_Basenames then files with identical
346    --  base names are permitted within a project for source-based languages
347    --  (never for unit based languages).
348
349    procedure Check_File
350      (Project           : in out Project_Processing_Data;
351       Data              : in out Tree_Processing_Data;
352       Source_Dir_Rank   : Natural;
353       Path              : Path_Name_Type;
354       Display_Path      : Path_Name_Type;
355       File_Name         : File_Name_Type;
356       Display_File_Name : File_Name_Type;
357       Locally_Removed   : Boolean;
358       For_All_Sources   : Boolean);
359    --  Check if file File_Name is a valid source of the project. This is used
360    --  in multi-language mode only. When the file matches one of the naming
361    --  schemes, it is added to various htables through Add_Source and to
362    --  Source_Paths_Htable.
363    --
364    --  File_Name is the same as Display_File_Name, but has been normalized.
365    --  They do not include the directory information.
366    --
367    --  Path and Display_Path on the other hand are the full path to the file.
368    --  Path must have been normalized (canonical casing and possibly links
369    --  resolved).
370    --
371    --  Source_Directory is the directory in which the file was found. It is
372    --  neither normalized nor has had links resolved, and must not end with a
373    --  a directory separator, to avoid duplicates later on.
374    --
375    --  If For_All_Sources is True, then all possible file names are analyzed
376    --  otherwise only those currently set in the Source_Names hash table.
377
378    procedure Check_File_Naming_Schemes
379      (Project               : Project_Processing_Data;
380       File_Name             : File_Name_Type;
381       Alternate_Languages   : out Language_List;
382       Language              : out Language_Ptr;
383       Display_Language_Name : out Name_Id;
384       Unit                  : out Name_Id;
385       Lang_Kind             : out Language_Kind;
386       Kind                  : out Source_Kind);
387    --  Check if the file name File_Name conforms to one of the naming schemes
388    --  of the project. If the file does not match one of the naming schemes,
389    --  set Language to No_Language_Index. Filename is the name of the file
390    --  being investigated. It has been normalized (case-folded). File_Name is
391    --  the same value.
392
393    procedure Get_Directories
394      (Project : Project_Id;
395       Data    : in out Tree_Processing_Data);
396    --  Get the object directory, the exec directory and the source directories
397    --  of a project.
398
399    procedure Get_Mains
400      (Project : Project_Id;
401       Data    : in out Tree_Processing_Data);
402    --  Get the mains of a project from attribute Main, if it exists, and put
403    --  them in the project data.
404
405    procedure Get_Sources_From_File
406      (Path     : String;
407       Location : Source_Ptr;
408       Project  : in out Project_Processing_Data;
409       Data     : in out Tree_Processing_Data);
410    --  Get the list of sources from a text file and put them in hash table
411    --  Source_Names.
412
413    procedure Find_Sources
414      (Project : in out Project_Processing_Data;
415       Data    : in out Tree_Processing_Data);
416    --  Process the Source_Files and Source_List_File attributes, and store the
417    --  list of source files into the Source_Names htable. When these attributes
418    --  are not defined, find all files matching the naming schemes in the
419    --  source directories. If Allow_Duplicate_Basenames, then files with the
420    --  same base names are authorized within a project for source-based
421    --  languages (never for unit based languages)
422
423    procedure Compute_Unit_Name
424      (File_Name : File_Name_Type;
425       Naming    : Lang_Naming_Data;
426       Kind      : out Source_Kind;
427       Unit      : out Name_Id;
428       Project   : Project_Processing_Data);
429    --  Check whether the file matches the naming scheme. If it does,
430    --  compute its unit name. If Unit is set to No_Name on exit, none of the
431    --  other out parameters are relevant.
432
433    procedure Check_Illegal_Suffix
434      (Project         : Project_Id;
435       Suffix          : File_Name_Type;
436       Dot_Replacement : File_Name_Type;
437       Attribute_Name  : String;
438       Location        : Source_Ptr;
439       Data            : in out Tree_Processing_Data);
440    --  Display an error message if the given suffix is illegal for some reason.
441    --  The name of the attribute we are testing is specified in Attribute_Name,
442    --  which is used in the error message. Location is the location where the
443    --  suffix is defined.
444
445    procedure Locate_Directory
446      (Project          : Project_Id;
447       Name             : File_Name_Type;
448       Path             : out Path_Information;
449       Dir_Exists       : out Boolean;
450       Data             : in out Tree_Processing_Data;
451       Create           : String := "";
452       Location         : Source_Ptr := No_Location;
453       Must_Exist       : Boolean := True;
454       Externally_Built : Boolean := False);
455    --  Locate a directory. Name is the directory name. Relative paths are
456    --  resolved relative to the project's directory. If the directory does not
457    --  exist and Setup_Projects is True and Create is a non null string, an
458    --  attempt is made to create the directory. If the directory does not
459    --  exist, it is either created if Setup_Projects is False (and then
460    --  returned), or simply returned without checking for its existence (if
461    --  Must_Exist is False) or No_Path_Information is returned. In all cases,
462    --  Dir_Exists indicates whether the directory now exists. Create is also
463    --  used for debugging traces to show which path we are computing.
464
465    procedure Look_For_Sources
466      (Project : in out Project_Processing_Data;
467       Data    : in out Tree_Processing_Data);
468    --  Find all the sources of project Project in project tree Data.Tree and
469    --  update its Data accordingly. This assumes that the special naming
470    --  exceptions have already been processed.
471
472    function Path_Name_Of
473      (File_Name : File_Name_Type;
474       Directory : Path_Name_Type) return String;
475    --  Returns the path name of a (non project) file. Returns an empty string
476    --  if file cannot be found.
477
478    procedure Remove_Source
479      (Tree        : Project_Tree_Ref;
480       Id          : Source_Id;
481       Replaced_By : Source_Id);
482    --  Remove a file from the list of sources of a project. This might be
483    --  because the file is replaced by another one in an extending project,
484    --  or because a file was added as a naming exception but was not found
485    --  in the end.
486
487    procedure Report_No_Sources
488      (Project      : Project_Id;
489       Lang_Name    : String;
490       Data         : Tree_Processing_Data;
491       Location     : Source_Ptr;
492       Continuation : Boolean := False);
493    --  Report an error or a warning depending on the value of When_No_Sources
494    --  when there are no sources for language Lang_Name.
495
496    procedure Show_Source_Dirs
497      (Project : Project_Id;
498       Shared  : Shared_Project_Tree_Data_Access);
499    --  List all the source directories of a project
500
501    procedure Write_Attr (Name, Value : String);
502    --  Debug print a value for a specific property. Does nothing when not in
503    --  debug mode
504
505    procedure Error_Or_Warning
506      (Flags    : Processing_Flags;
507       Kind     : Error_Warning;
508       Msg      : String;
509       Location : Source_Ptr;
510       Project  : Project_Id);
511    --  Emits either an error or warning message (or nothing), depending on Kind
512
513    function No_Space_Img (N : Natural) return String;
514    --  Image of a Natural without the initial space
515
516    ----------------------
517    -- Error_Or_Warning --
518    ----------------------
519
520    procedure Error_Or_Warning
521      (Flags    : Processing_Flags;
522       Kind     : Error_Warning;
523       Msg      : String;
524       Location : Source_Ptr;
525       Project  : Project_Id) is
526    begin
527       case Kind is
528          when Error   => Error_Msg (Flags, Msg, Location, Project);
529          when Warning => Error_Msg (Flags, "?" & Msg, Location, Project);
530          when Silent  => null;
531       end case;
532    end Error_Or_Warning;
533
534    ------------------------------
535    -- Replace_Into_Name_Buffer --
536    ------------------------------
537
538    procedure Replace_Into_Name_Buffer
539      (Str         : String;
540       Pattern     : String;
541       Replacement : Character)
542    is
543       Max : constant Integer := Str'Last - Pattern'Length + 1;
544       J   : Positive;
545
546    begin
547       Name_Len := 0;
548
549       J := Str'First;
550       while J <= Str'Last loop
551          Name_Len := Name_Len + 1;
552
553          if J <= Max
554            and then Str (J .. J + Pattern'Length - 1) = Pattern
555          then
556             Name_Buffer (Name_Len) := Replacement;
557             J := J + Pattern'Length;
558
559          else
560             Name_Buffer (Name_Len) := GNAT.Case_Util.To_Lower (Str (J));
561             J := J + 1;
562          end if;
563       end loop;
564    end Replace_Into_Name_Buffer;
565
566    --------------------
567    -- Suffix_Matches --
568    --------------------
569
570    function Suffix_Matches
571      (Filename : String;
572       Suffix   : File_Name_Type) return Boolean
573    is
574       Min_Prefix_Length : Natural := 0;
575
576    begin
577       if Suffix = No_File or else Suffix = Empty_File then
578          return False;
579       end if;
580
581       declare
582          Suf : String := Get_Name_String (Suffix);
583
584       begin
585          --  On non case-sensitive systems, use proper suffix casing
586
587          Canonical_Case_File_Name (Suf);
588
589          --  The file name must end with the suffix (which is not an extension)
590          --  For instance a suffix "configure.in" must match a file with the
591          --  same name. To avoid dummy cases, though, a suffix starting with
592          --  '.' requires a file that is at least one character longer ('.cpp'
593          --  should not match a file with the same name).
594
595          if Suf (Suf'First) = '.' then
596             Min_Prefix_Length := 1;
597          end if;
598
599          return Filename'Length >= Suf'Length + Min_Prefix_Length
600            and then
601              Filename (Filename'Last - Suf'Length + 1 .. Filename'Last) = Suf;
602       end;
603    end Suffix_Matches;
604
605    ----------------
606    -- Write_Attr --
607    ----------------
608
609    procedure Write_Attr (Name, Value : String) is
610    begin
611       if Current_Verbosity = High then
612          Debug_Output (Name & " = """ & Value & '"');
613       end if;
614    end Write_Attr;
615
616    ----------------
617    -- Add_Source --
618    ----------------
619
620    procedure Add_Source
621      (Id                  : out Source_Id;
622       Data                : in out Tree_Processing_Data;
623       Project             : Project_Id;
624       Source_Dir_Rank     : Natural;
625       Lang_Id             : Language_Ptr;
626       Kind                : Source_Kind;
627       File_Name           : File_Name_Type;
628       Display_File        : File_Name_Type;
629       Naming_Exception    : Naming_Exception_Type := No;
630       Path                : Path_Information      := No_Path_Information;
631       Alternate_Languages : Language_List         := null;
632       Unit                : Name_Id               := No_Name;
633       Index               : Int                   := 0;
634       Locally_Removed     : Boolean               := False;
635       Location            : Source_Ptr            := No_Location)
636    is
637       Config            : constant Language_Config := Lang_Id.Config;
638       UData             : Unit_Index;
639       Add_Src           : Boolean;
640       Source            : Source_Id;
641       Prev_Unit         : Unit_Index := No_Unit_Index;
642       Source_To_Replace : Source_Id := No_Source;
643
644    begin
645       --  Check if the same file name or unit is used in the prj tree
646
647       Add_Src := True;
648
649       if Unit /= No_Name then
650          Prev_Unit := Units_Htable.Get (Data.Tree.Units_HT, Unit);
651       end if;
652
653       if Prev_Unit /= No_Unit_Index
654         and then (Kind = Impl or else Kind = Spec)
655         and then Prev_Unit.File_Names (Kind) /= null
656       then
657          --  Suspicious, we need to check later whether this is authorized
658
659          Add_Src := False;
660          Source := Prev_Unit.File_Names (Kind);
661
662       else
663          Source := Source_Files_Htable.Get
664            (Data.Tree.Source_Files_HT, File_Name);
665
666          if Source /= No_Source and then Source.Index = Index then
667             Add_Src := False;
668          end if;
669       end if;
670
671       --  Duplication of file/unit in same project is allowed if order of
672       --  source directories is known, or if there is no compiler for the
673       --  language.
674
675       if Add_Src = False then
676          Add_Src := True;
677
678          if Project = Source.Project then
679             if Prev_Unit = No_Unit_Index then
680                if Data.Flags.Allow_Duplicate_Basenames then
681                   Add_Src := True;
682
683                elsif Lang_Id.Config.Compiler_Driver = Empty_File then
684                   Add_Src := True;
685
686                elsif Source_Dir_Rank /= Source.Source_Dir_Rank then
687                   Add_Src := False;
688
689                else
690                   Error_Msg_File_1 := File_Name;
691                   Error_Msg
692                     (Data.Flags, "duplicate source file name {",
693                      Location, Project);
694                   Add_Src := False;
695                end if;
696
697             else
698                if Source_Dir_Rank /= Source.Source_Dir_Rank then
699                   Add_Src := False;
700
701                --  We might be seeing the same file through a different path
702                --  (for instance because of symbolic links).
703
704                elsif Source.Path.Name /= Path.Name then
705                   if not Source.Duplicate_Unit then
706                      Error_Msg_Name_1 := Unit;
707                      Error_Msg
708                        (Data.Flags, "\duplicate unit %%", Location, Project);
709                      Source.Duplicate_Unit := True;
710                   end if;
711
712                   Add_Src := False;
713                end if;
714             end if;
715
716             --  Do not allow the same unit name in different projects, except
717             --  if one is extending the other.
718
719             --  For a file based language, the same file name replaces a file
720             --  in a project being extended, but it is allowed to have the same
721             --  file name in unrelated projects.
722
723          elsif Is_Extending (Project, Source.Project) then
724             if not Locally_Removed and then Naming_Exception /= Inherited then
725                Source_To_Replace := Source;
726             end if;
727
728          elsif Prev_Unit /= No_Unit_Index
729            and then Prev_Unit.File_Names (Kind) /= null
730            and then not Source.Locally_Removed
731          then
732             --  Path is set if this is a source we found on the disk, in which
733             --  case we can provide more explicit error message. Path is unset
734             --  when the source is added from one of the naming exceptions in
735             --  the project.
736
737             if Path /= No_Path_Information then
738                Error_Msg_Name_1 := Unit;
739                Error_Msg
740                  (Data.Flags,
741                   "unit %% cannot belong to several projects",
742                   Location, Project);
743
744                Error_Msg_Name_1 := Project.Name;
745                Error_Msg_Name_2 := Name_Id (Path.Display_Name);
746                Error_Msg
747                  (Data.Flags, "\  project %%, %%", Location, Project);
748
749                Error_Msg_Name_1 := Source.Project.Name;
750                Error_Msg_Name_2 := Name_Id (Source.Path.Display_Name);
751                Error_Msg
752                  (Data.Flags, "\  project %%, %%", Location, Project);
753
754             else
755                Error_Msg_Name_1 := Unit;
756                Error_Msg_Name_2 := Source.Project.Name;
757                Error_Msg
758                  (Data.Flags, "unit %% already belongs to project %%",
759                   Location, Project);
760             end if;
761
762             Add_Src := False;
763
764          elsif not Source.Locally_Removed
765            and then not Data.Flags.Allow_Duplicate_Basenames
766            and then Lang_Id.Config.Kind = Unit_Based
767            and then Source.Language.Config.Kind = Unit_Based
768          then
769             Error_Msg_File_1 := File_Name;
770             Error_Msg_File_2 := File_Name_Type (Source.Project.Name);
771             Error_Msg
772               (Data.Flags,
773                "{ is already a source of project {", Location, Project);
774
775             --  Add the file anyway, to avoid further warnings like "language
776             --  unknown".
777
778             Add_Src := True;
779          end if;
780       end if;
781
782       if not Add_Src then
783          return;
784       end if;
785
786       --  Add the new file
787
788       Id := new Source_Data;
789
790       if Current_Verbosity = High then
791          Debug_Indent;
792          Write_Str ("adding source File: ");
793          Write_Str (Get_Name_String (Display_File));
794
795          if Index /= 0 then
796             Write_Str (" at" & Index'Img);
797          end if;
798
799          if Lang_Id.Config.Kind = Unit_Based then
800             Write_Str (" Unit: ");
801
802             --  ??? in gprclean, it seems we sometimes pass an empty Unit name
803             --  (see test extended_projects).
804
805             if Unit /= No_Name then
806                Write_Str (Get_Name_String (Unit));
807             end if;
808
809             Write_Str (" Kind: ");
810             Write_Str (Source_Kind'Image (Kind));
811          end if;
812
813          Write_Eol;
814       end if;
815
816       Id.Project             := Project;
817       Id.Location            := Location;
818       Id.Source_Dir_Rank     := Source_Dir_Rank;
819       Id.Language            := Lang_Id;
820       Id.Kind                := Kind;
821       Id.Alternate_Languages := Alternate_Languages;
822       Id.Locally_Removed     := Locally_Removed;
823       Id.Index               := Index;
824       Id.File                := File_Name;
825       Id.Display_File        := Display_File;
826       Id.Dep_Name            := Dependency_Name
827                                   (File_Name, Lang_Id.Config.Dependency_Kind);
828       Id.Naming_Exception    := Naming_Exception;
829       Id.Object              := Object_Name
830                                   (File_Name, Config.Object_File_Suffix);
831       Id.Switches            := Switches_Name (File_Name);
832
833       --  Add the source id to the Unit_Sources_HT hash table, if the unit name
834       --  is not null.
835
836       if Unit /= No_Name then
837
838          --  Note: we might be creating a dummy unit here, when we in fact have
839          --  a separate. For instance, file file-bar.adb will initially be
840          --  assumed to be the IMPL of unit "file.bar". Only later on (in
841          --  Check_Object_Files) will we parse those units that only have an
842          --  impl and no spec to make sure whether we have a Separate in fact
843          --  (that significantly reduces the number of times we need to parse
844          --  the files, since we are then only interested in those with no
845          --  spec). We still need those dummy units in the table, since that's
846          --  the name we find in the ALI file
847
848          UData := Units_Htable.Get (Data.Tree.Units_HT, Unit);
849
850          if UData = No_Unit_Index then
851             UData := new Unit_Data;
852             UData.Name := Unit;
853
854             if Naming_Exception /= Inherited then
855                Units_Htable.Set (Data.Tree.Units_HT, Unit, UData);
856             end if;
857          end if;
858
859          Id.Unit := UData;
860
861          --  Note that this updates Unit information as well
862
863          if Naming_Exception /= Inherited then
864             Override_Kind (Id, Kind);
865          end if;
866       end if;
867
868       if Path /= No_Path_Information then
869          Id.Path := Path;
870          Source_Paths_Htable.Set (Data.Tree.Source_Paths_HT, Path.Name, Id);
871       end if;
872
873       Id.Next_With_File_Name :=
874         Source_Files_Htable.Get (Data.Tree.Source_Files_HT, File_Name);
875       Source_Files_Htable.Set (Data.Tree.Source_Files_HT, File_Name, Id);
876
877       if Index /= 0 then
878          Project.Has_Multi_Unit_Sources := True;
879       end if;
880
881       --  Add the source to the language list
882
883       Id.Next_In_Lang := Lang_Id.First_Source;
884       Lang_Id.First_Source := Id;
885
886       if Source_To_Replace /= No_Source then
887          Remove_Source (Data.Tree, Source_To_Replace, Id);
888       end if;
889
890       if Data.Tree.Replaced_Source_Number > 0
891         and then
892           Replaced_Source_HTable.Get
893             (Data.Tree.Replaced_Sources, Id.File) /= No_File
894       then
895          Replaced_Source_HTable.Remove (Data.Tree.Replaced_Sources, Id.File);
896          Data.Tree.Replaced_Source_Number :=
897            Data.Tree.Replaced_Source_Number - 1;
898       end if;
899    end Add_Source;
900
901    ------------------------------
902    -- Canonical_Case_File_Name --
903    ------------------------------
904
905    function Canonical_Case_File_Name (Name : Name_Id) return File_Name_Type is
906    begin
907       if Osint.File_Names_Case_Sensitive then
908          return File_Name_Type (Name);
909       else
910          Get_Name_String (Name);
911          Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
912          return Name_Find;
913       end if;
914    end Canonical_Case_File_Name;
915
916    ---------------------------------
917    -- Process_Aggregated_Projects --
918    ---------------------------------
919
920    procedure Process_Aggregated_Projects
921      (Tree      : Project_Tree_Ref;
922       Project   : Project_Id;
923       Node_Tree : Prj.Tree.Project_Node_Tree_Ref;
924       Flags     : Processing_Flags)
925    is
926       Data : Tree_Processing_Data :=
927                (Tree      => Tree,
928                 Node_Tree => Node_Tree,
929                 Flags     => Flags);
930
931       Project_Files : constant Prj.Variable_Value :=
932                         Prj.Util.Value_Of
933                           (Snames.Name_Project_Files,
934                            Project.Decl.Attributes,
935                            Tree.Shared);
936
937       Project_Path_For_Aggregate : Prj.Env.Project_Search_Path;
938
939       procedure Found_Project_File (Path : Path_Information; Rank : Natural);
940       --  Called for each project file aggregated by Project
941
942       procedure Expand_Project_Files is
943         new Expand_Subdirectory_Pattern (Callback => Found_Project_File);
944       --  Search for all project files referenced by the patterns given in
945       --  parameter. Calls Found_Project_File for each of them.
946
947       ------------------------
948       -- Found_Project_File --
949       ------------------------
950
951       procedure Found_Project_File (Path : Path_Information; Rank : Natural) is
952          pragma Unreferenced (Rank);
953
954       begin
955          if Path.Name /= Project.Path.Name then
956             Debug_Output ("aggregates: ", Name_Id (Path.Display_Name));
957
958             --  For usual "with" statement, this phase will have been done when
959             --  parsing the project itself. However, for aggregate projects, we
960             --  can only do this when processing the aggregate project, since
961             --  the exact list of project files or project directories can
962             --  depend on scenario variables.
963             --
964             --  We only load the projects explicitly here, but do not process
965             --  them. For the processing, Prj.Proc will take care of processing
966             --  them, within the same call to Recursive_Process (thus avoiding
967             --  the processing of a given project multiple times).
968             --
969             --  ??? We might already have loaded the project
970
971             Add_Aggregated_Project (Project, Path => Path.Name);
972
973          else
974             Debug_Output ("pattern returned the aggregate itself, ignored");
975          end if;
976       end Found_Project_File;
977
978    --  Start of processing for Check_Aggregate_Project
979
980    begin
981       pragma Assert (Project.Qualifier in Aggregate_Project);
982
983       if Project_Files.Default then
984          Error_Msg_Name_1 := Snames.Name_Project_Files;
985          Error_Msg
986            (Flags,
987             "Attribute %% must be specified in aggregate project",
988             Project.Location, Project);
989          return;
990       end if;
991
992       --  The aggregated projects are only searched relative to the directory
993       --  of the aggregate project, not in the default project path.
994
995       Initialize_Empty (Project_Path_For_Aggregate);
996
997       Free (Project.Aggregated_Projects);
998
999       --  Look for aggregated projects. For similarity with source files and
1000       --  dirs, the aggregated project files are not searched for on the
1001       --  project path, and are only found through the path specified in
1002       --  the Project_Files attribute.
1003
1004       Expand_Project_Files
1005         (Project       => Project,
1006          Data          => Data,
1007          Patterns      => Project_Files.Values,
1008          Ignore        => Nil_String,
1009          Search_For    => Search_Files,
1010          Resolve_Links => Opt.Follow_Links_For_Files);
1011
1012       Free (Project_Path_For_Aggregate);
1013    end Process_Aggregated_Projects;
1014
1015    -----------
1016    -- Check --
1017    -----------
1018
1019    procedure Check
1020      (Project : Project_Id;
1021       Data    : in out Tree_Processing_Data)
1022    is
1023       Shared   : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
1024       Prj_Data : Project_Processing_Data;
1025
1026    begin
1027       Debug_Increase_Indent ("check", Project.Name);
1028
1029       Initialize (Prj_Data, Project);
1030
1031       Check_If_Externally_Built (Project, Data);
1032
1033       case Project.Qualifier is
1034          when Aggregate =>
1035             null;
1036
1037          when Aggregate_Library =>
1038             if Project.Object_Directory = No_Path_Information then
1039                Project.Object_Directory := Project.Directory;
1040             end if;
1041
1042          when others =>
1043             Get_Directories (Project, Data);
1044             Check_Programming_Languages (Project, Data);
1045
1046             if Current_Verbosity = High then
1047                Show_Source_Dirs (Project, Shared);
1048             end if;
1049
1050             if Project.Qualifier = Dry then
1051                Check_Abstract_Project (Project, Data);
1052             end if;
1053       end case;
1054
1055       --  Check configuration. This must be done even for gnatmake (even though
1056       --  no user configuration file was provided) since the default config we
1057       --  generate indicates whether libraries are supported for instance.
1058
1059       Check_Configuration (Project, Data);
1060
1061       if Project.Qualifier /= Aggregate then
1062          Check_Library_Attributes (Project, Data);
1063          Check_Package_Naming (Project, Data);
1064
1065          --  An aggregate library has no source, no need to look for them
1066
1067          if Project.Qualifier /= Aggregate_Library then
1068             Look_For_Sources (Prj_Data, Data);
1069          end if;
1070
1071          Check_Interfaces (Project, Data);
1072
1073          if Project.Library then
1074             Check_Stand_Alone_Library (Project, Data);
1075          end if;
1076
1077          Get_Mains (Project, Data);
1078       end if;
1079
1080       Free (Prj_Data);
1081
1082       Debug_Decrease_Indent ("done check");
1083    end Check;
1084
1085    ----------------------------
1086    -- Check_Abstract_Project --
1087    ----------------------------
1088
1089    procedure Check_Abstract_Project
1090      (Project : Project_Id;
1091       Data    : in out Tree_Processing_Data)
1092    is
1093       Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
1094
1095       Source_Dirs      : constant Variable_Value :=
1096                            Util.Value_Of
1097                              (Name_Source_Dirs,
1098                               Project.Decl.Attributes, Shared);
1099       Source_Files     : constant Variable_Value :=
1100                            Util.Value_Of
1101                              (Name_Source_Files,
1102                               Project.Decl.Attributes, Shared);
1103       Source_List_File : constant Variable_Value :=
1104                            Util.Value_Of
1105                              (Name_Source_List_File,
1106                               Project.Decl.Attributes, Shared);
1107       Languages        : constant Variable_Value :=
1108                            Util.Value_Of
1109                              (Name_Languages,
1110                               Project.Decl.Attributes, Shared);
1111
1112    begin
1113       if Project.Source_Dirs /= Nil_String then
1114          if Source_Dirs.Values  = Nil_String
1115            and then Source_Files.Values = Nil_String
1116            and then Languages.Values = Nil_String
1117            and then Source_List_File.Default
1118          then
1119             Project.Source_Dirs := Nil_String;
1120
1121          else
1122             Error_Msg
1123               (Data.Flags,
1124                "at least one of Source_Files, Source_Dirs or Languages "
1125                & "must be declared empty for an abstract project",
1126                Project.Location, Project);
1127          end if;
1128       end if;
1129    end Check_Abstract_Project;
1130
1131    -------------------------
1132    -- Check_Configuration --
1133    -------------------------
1134
1135    procedure Check_Configuration
1136      (Project : Project_Id;
1137       Data    : in out Tree_Processing_Data)
1138    is
1139       Shared          : constant Shared_Project_Tree_Data_Access :=
1140                           Data.Tree.Shared;
1141
1142       Dot_Replacement : File_Name_Type := No_File;
1143       Casing          : Casing_Type    := All_Lower_Case;
1144       Separate_Suffix : File_Name_Type := No_File;
1145
1146       Lang_Index : Language_Ptr := No_Language_Index;
1147       --  The index of the language data being checked
1148
1149       Prev_Index : Language_Ptr := No_Language_Index;
1150       --  The index of the previous language
1151
1152       procedure Process_Project_Level_Simple_Attributes;
1153       --  Process the simple attributes at the project level
1154
1155       procedure Process_Project_Level_Array_Attributes;
1156       --  Process the associate array attributes at the project level
1157
1158       procedure Process_Packages;
1159       --  Read the packages of the project
1160
1161       ----------------------
1162       -- Process_Packages --
1163       ----------------------
1164
1165       procedure Process_Packages is
1166          Packages : Package_Id;
1167          Element  : Package_Element;
1168
1169          procedure Process_Binder (Arrays : Array_Id);
1170          --  Process the associate array attributes of package Binder
1171
1172          procedure Process_Builder (Attributes : Variable_Id);
1173          --  Process the simple attributes of package Builder
1174
1175          procedure Process_Compiler (Arrays : Array_Id);
1176          --  Process the associate array attributes of package Compiler
1177
1178          procedure Process_Naming (Attributes : Variable_Id);
1179          --  Process the simple attributes of package Naming
1180
1181          procedure Process_Naming (Arrays : Array_Id);
1182          --  Process the associate array attributes of package Naming
1183
1184          procedure Process_Linker (Attributes : Variable_Id);
1185          --  Process the simple attributes of package Linker of a
1186          --  configuration project.
1187
1188          --------------------
1189          -- Process_Binder --
1190          --------------------
1191
1192          procedure Process_Binder (Arrays : Array_Id) is
1193             Current_Array_Id : Array_Id;
1194             Current_Array    : Array_Data;
1195             Element_Id       : Array_Element_Id;
1196             Element          : Array_Element;
1197
1198          begin
1199             --  Process the associative array attribute of package Binder
1200
1201             Current_Array_Id := Arrays;
1202             while Current_Array_Id /= No_Array loop
1203                Current_Array := Shared.Arrays.Table (Current_Array_Id);
1204
1205                Element_Id := Current_Array.Value;
1206                while Element_Id /= No_Array_Element loop
1207                   Element := Shared.Array_Elements.Table (Element_Id);
1208
1209                   if Element.Index /= All_Other_Names then
1210
1211                      --  Get the name of the language
1212
1213                      Lang_Index :=
1214                        Get_Language_From_Name
1215                          (Project, Get_Name_String (Element.Index));
1216
1217                      if Lang_Index /= No_Language_Index then
1218                         case Current_Array.Name is
1219                            when Name_Driver =>
1220
1221                               --  Attribute Driver (<language>)
1222
1223                               Lang_Index.Config.Binder_Driver :=
1224                                 File_Name_Type (Element.Value.Value);
1225
1226                            when Name_Required_Switches =>
1227                               Put
1228                                 (Into_List =>
1229                                    Lang_Index.Config.Binder_Required_Switches,
1230                                  From_List => Element.Value.Values,
1231                                  In_Tree   => Data.Tree);
1232
1233                            when Name_Prefix =>
1234
1235                               --  Attribute Prefix (<language>)
1236
1237                               Lang_Index.Config.Binder_Prefix :=
1238                                 Element.Value.Value;
1239
1240                            when Name_Objects_Path =>
1241
1242                               --  Attribute Objects_Path (<language>)
1243
1244                               Lang_Index.Config.Objects_Path :=
1245                                 Element.Value.Value;
1246
1247                            when Name_Objects_Path_File =>
1248
1249                               --  Attribute Objects_Path (<language>)
1250
1251                               Lang_Index.Config.Objects_Path_File :=
1252                                 Element.Value.Value;
1253
1254                            when others =>
1255                               null;
1256                         end case;
1257                      end if;
1258                   end if;
1259
1260                   Element_Id := Element.Next;
1261                end loop;
1262
1263                Current_Array_Id := Current_Array.Next;
1264             end loop;
1265          end Process_Binder;
1266
1267          ---------------------
1268          -- Process_Builder --
1269          ---------------------
1270
1271          procedure Process_Builder (Attributes : Variable_Id) is
1272             Attribute_Id : Variable_Id;
1273             Attribute    : Variable;
1274
1275          begin
1276             --  Process non associated array attribute from package Builder
1277
1278             Attribute_Id := Attributes;
1279             while Attribute_Id /= No_Variable loop
1280                Attribute := Shared.Variable_Elements.Table (Attribute_Id);
1281
1282                if not Attribute.Value.Default then
1283                   if Attribute.Name = Name_Executable_Suffix then
1284
1285                      --  Attribute Executable_Suffix: the suffix of the
1286                      --  executables.
1287
1288                      Project.Config.Executable_Suffix :=
1289                        Attribute.Value.Value;
1290                   end if;
1291                end if;
1292
1293                Attribute_Id := Attribute.Next;
1294             end loop;
1295          end Process_Builder;
1296
1297          ----------------------
1298          -- Process_Compiler --
1299          ----------------------
1300
1301          procedure Process_Compiler (Arrays : Array_Id) is
1302             Current_Array_Id : Array_Id;
1303             Current_Array    : Array_Data;
1304             Element_Id       : Array_Element_Id;
1305             Element          : Array_Element;
1306             List             : String_List_Id;
1307
1308          begin
1309             --  Process the associative array attribute of package Compiler
1310
1311             Current_Array_Id := Arrays;
1312             while Current_Array_Id /= No_Array loop
1313                Current_Array := Shared.Arrays.Table (Current_Array_Id);
1314
1315                Element_Id := Current_Array.Value;
1316                while Element_Id /= No_Array_Element loop
1317                   Element := Shared.Array_Elements.Table (Element_Id);
1318
1319                   if Element.Index /= All_Other_Names then
1320
1321                      --  Get the name of the language
1322
1323                      Lang_Index := Get_Language_From_Name
1324                        (Project, Get_Name_String (Element.Index));
1325
1326                      if Lang_Index /= No_Language_Index then
1327                         case Current_Array.Name is
1328
1329                         --  Attribute Dependency_Kind (<language>)
1330
1331                         when Name_Dependency_Kind =>
1332                            Get_Name_String (Element.Value.Value);
1333
1334                            begin
1335                               Lang_Index.Config.Dependency_Kind :=
1336                                 Dependency_File_Kind'Value
1337                                   (Name_Buffer (1 .. Name_Len));
1338
1339                            exception
1340                               when Constraint_Error =>
1341                                  Error_Msg
1342                                    (Data.Flags,
1343                                     "illegal value for Dependency_Kind",
1344                                     Element.Value.Location,
1345                                     Project);
1346                            end;
1347
1348                         --  Attribute Dependency_Switches (<language>)
1349
1350                         when Name_Dependency_Switches =>
1351                            if Lang_Index.Config.Dependency_Kind = None then
1352                               Lang_Index.Config.Dependency_Kind := Makefile;
1353                            end if;
1354
1355                            List := Element.Value.Values;
1356
1357                            if List /= Nil_String then
1358                               Put (Into_List =>
1359                                      Lang_Index.Config.Dependency_Option,
1360                                    From_List => List,
1361                                    In_Tree   => Data.Tree);
1362                            end if;
1363
1364                         --  Attribute Dependency_Driver (<language>)
1365
1366                         when Name_Dependency_Driver =>
1367                            if Lang_Index.Config.Dependency_Kind = None then
1368                               Lang_Index.Config.Dependency_Kind := Makefile;
1369                            end if;
1370
1371                            List := Element.Value.Values;
1372
1373                            if List /= Nil_String then
1374                               Put (Into_List =>
1375                                      Lang_Index.Config.Compute_Dependency,
1376                                    From_List => List,
1377                                    In_Tree   => Data.Tree);
1378                            end if;
1379
1380                         --  Attribute Language_Kind (<language>)
1381
1382                         when Name_Language_Kind =>
1383                            Get_Name_String (Element.Value.Value);
1384
1385                            begin
1386                               Lang_Index.Config.Kind :=
1387                                 Language_Kind'Value
1388                                   (Name_Buffer (1 .. Name_Len));
1389
1390                            exception
1391                               when Constraint_Error =>
1392                                  Error_Msg
1393                                    (Data.Flags,
1394                                     "illegal value for Language_Kind",
1395                                     Element.Value.Location,
1396                                     Project);
1397                            end;
1398
1399                         --  Attribute Include_Switches (<language>)
1400
1401                         when Name_Include_Switches =>
1402                            List := Element.Value.Values;
1403
1404                            if List = Nil_String then
1405                               Error_Msg
1406                                 (Data.Flags, "include option cannot be null",
1407                                  Element.Value.Location, Project);
1408                            end if;
1409
1410                            Put (Into_List => Lang_Index.Config.Include_Option,
1411                                 From_List => List,
1412                                 In_Tree   => Data.Tree);
1413
1414                         --  Attribute Include_Path (<language>)
1415
1416                         when Name_Include_Path =>
1417                            Lang_Index.Config.Include_Path :=
1418                              Element.Value.Value;
1419
1420                         --  Attribute Include_Path_File (<language>)
1421
1422                         when Name_Include_Path_File =>
1423                            Lang_Index.Config.Include_Path_File :=
1424                              Element.Value.Value;
1425
1426                         --  Attribute Driver (<language>)
1427
1428                         when Name_Driver =>
1429                            Lang_Index.Config.Compiler_Driver :=
1430                              File_Name_Type (Element.Value.Value);
1431
1432                         when Name_Required_Switches
1433                            | Name_Leading_Required_Switches
1434                            =>
1435                            Put (Into_List =>
1436                                   Lang_Index.Config.
1437                                     Compiler_Leading_Required_Switches,
1438                                 From_List => Element.Value.Values,
1439                                 In_Tree   => Data.Tree);
1440
1441                         when Name_Trailing_Required_Switches =>
1442                            Put (Into_List =>
1443                                   Lang_Index.Config.
1444                                     Compiler_Trailing_Required_Switches,
1445                                 From_List => Element.Value.Values,
1446                                 In_Tree   => Data.Tree);
1447
1448                         when Name_Multi_Unit_Switches =>
1449                            Put (Into_List =>
1450                                   Lang_Index.Config.Multi_Unit_Switches,
1451                                 From_List => Element.Value.Values,
1452                                 In_Tree   => Data.Tree);
1453
1454                         when Name_Multi_Unit_Object_Separator =>
1455                            Get_Name_String (Element.Value.Value);
1456
1457                            if Name_Len /= 1 then
1458                               Error_Msg
1459                                 (Data.Flags,
1460                                  "multi-unit object separator must have " &
1461                                  "a single character",
1462                                  Element.Value.Location, Project);
1463
1464                            elsif Name_Buffer (1) = ' ' then
1465                               Error_Msg
1466                                 (Data.Flags,
1467                                  "multi-unit object separator cannot be " &
1468                                  "a space",
1469                                  Element.Value.Location, Project);
1470
1471                            else
1472                               Lang_Index.Config.Multi_Unit_Object_Separator :=
1473                                 Name_Buffer (1);
1474                            end if;
1475
1476                         when Name_Path_Syntax =>
1477                            begin
1478                               Lang_Index.Config.Path_Syntax :=
1479                                   Path_Syntax_Kind'Value
1480                                     (Get_Name_String (Element.Value.Value));
1481
1482                            exception
1483                               when Constraint_Error =>
1484                                  Error_Msg
1485                                    (Data.Flags,
1486                                     "invalid value for Path_Syntax",
1487                                     Element.Value.Location, Project);
1488                            end;
1489
1490                         when Name_Source_File_Switches =>
1491                            Put (Into_List =>
1492                                   Lang_Index.Config.Source_File_Switches,
1493                                 From_List => Element.Value.Values,
1494                                 In_Tree   => Data.Tree);
1495
1496                         when Name_Object_File_Suffix =>
1497                            if Get_Name_String (Element.Value.Value) = "" then
1498                               Error_Msg
1499                                 (Data.Flags,
1500                                  "object file suffix cannot be empty",
1501                                  Element.Value.Location, Project);
1502
1503                            else
1504                               Lang_Index.Config.Object_File_Suffix :=
1505                                 Element.Value.Value;
1506                            end if;
1507
1508                         when Name_Object_File_Switches =>
1509                            Put (Into_List =>
1510                                   Lang_Index.Config.Object_File_Switches,
1511                                 From_List => Element.Value.Values,
1512                                 In_Tree   => Data.Tree);
1513
1514                         --  Attribute Compiler_Pic_Option (<language>)
1515
1516                         when Name_Pic_Option =>
1517                            List := Element.Value.Values;
1518
1519                            if List = Nil_String then
1520                               Error_Msg
1521                                 (Data.Flags,
1522                                  "compiler PIC option cannot be null",
1523                                  Element.Value.Location, Project);
1524                            end if;
1525
1526                            Put (Into_List =>
1527                                   Lang_Index.Config.Compilation_PIC_Option,
1528                                 From_List => List,
1529                                 In_Tree   => Data.Tree);
1530
1531                         --  Attribute Mapping_File_Switches (<language>)
1532
1533                         when Name_Mapping_File_Switches =>
1534                            List := Element.Value.Values;
1535
1536                            if List = Nil_String then
1537                               Error_Msg
1538                                 (Data.Flags,
1539                                  "mapping file switches cannot be null",
1540                                  Element.Value.Location, Project);
1541                            end if;
1542
1543                            Put (Into_List =>
1544                                 Lang_Index.Config.Mapping_File_Switches,
1545                                 From_List => List,
1546                                 In_Tree   => Data.Tree);
1547
1548                         --  Attribute Mapping_Spec_Suffix (<language>)
1549
1550                         when Name_Mapping_Spec_Suffix =>
1551                            Lang_Index.Config.Mapping_Spec_Suffix :=
1552                              File_Name_Type (Element.Value.Value);
1553
1554                         --  Attribute Mapping_Body_Suffix (<language>)
1555
1556                         when Name_Mapping_Body_Suffix =>
1557                            Lang_Index.Config.Mapping_Body_Suffix :=
1558                              File_Name_Type (Element.Value.Value);
1559
1560                         --  Attribute Config_File_Switches (<language>)
1561
1562                         when Name_Config_File_Switches =>
1563                            List := Element.Value.Values;
1564
1565                            if List = Nil_String then
1566                               Error_Msg
1567                                 (Data.Flags,
1568                                  "config file switches cannot be null",
1569                                  Element.Value.Location, Project);
1570                            end if;
1571
1572                            Put (Into_List =>
1573                                   Lang_Index.Config.Config_File_Switches,
1574                                 From_List => List,
1575                                 In_Tree   => Data.Tree);
1576
1577                         --  Attribute Objects_Path (<language>)
1578
1579                         when Name_Objects_Path =>
1580                            Lang_Index.Config.Objects_Path :=
1581                              Element.Value.Value;
1582
1583                         --  Attribute Objects_Path_File (<language>)
1584
1585                         when Name_Objects_Path_File =>
1586                            Lang_Index.Config.Objects_Path_File :=
1587                              Element.Value.Value;
1588
1589                         --  Attribute Config_Body_File_Name (<language>)
1590
1591                         when Name_Config_Body_File_Name =>
1592                            Lang_Index.Config.Config_Body :=
1593                              Element.Value.Value;
1594
1595                         --  Attribute Config_Body_File_Name_Index (< Language>)
1596
1597                         when Name_Config_Body_File_Name_Index =>
1598                            Lang_Index.Config.Config_Body_Index :=
1599                              Element.Value.Value;
1600
1601                         --  Attribute Config_Body_File_Name_Pattern(<language>)
1602
1603                         when Name_Config_Body_File_Name_Pattern =>
1604                            Lang_Index.Config.Config_Body_Pattern :=
1605                              Element.Value.Value;
1606
1607                            --  Attribute Config_Spec_File_Name (<language>)
1608
1609                         when Name_Config_Spec_File_Name =>
1610                            Lang_Index.Config.Config_Spec :=
1611                              Element.Value.Value;
1612
1613                         --  Attribute Config_Spec_File_Name_Index (<language>)
1614
1615                         when Name_Config_Spec_File_Name_Index =>
1616                            Lang_Index.Config.Config_Spec_Index :=
1617                              Element.Value.Value;
1618
1619                         --  Attribute Config_Spec_File_Name_Pattern(<language>)
1620
1621                         when Name_Config_Spec_File_Name_Pattern =>
1622                            Lang_Index.Config.Config_Spec_Pattern :=
1623                              Element.Value.Value;
1624
1625                         --  Attribute Config_File_Unique (<language>)
1626
1627                         when Name_Config_File_Unique =>
1628                            begin
1629                               Lang_Index.Config.Config_File_Unique :=
1630                                 Boolean'Value
1631                                   (Get_Name_String (Element.Value.Value));
1632                            exception
1633                               when Constraint_Error =>
1634                                  Error_Msg
1635                                    (Data.Flags,
1636                                     "illegal value for Config_File_Unique",
1637                                     Element.Value.Location, Project);
1638                            end;
1639
1640                         when others =>
1641                            null;
1642                         end case;
1643                      end if;
1644                   end if;
1645
1646                   Element_Id := Element.Next;
1647                end loop;
1648
1649                Current_Array_Id := Current_Array.Next;
1650             end loop;
1651          end Process_Compiler;
1652
1653          --------------------
1654          -- Process_Naming --
1655          --------------------
1656
1657          procedure Process_Naming (Attributes : Variable_Id) is
1658             Attribute_Id : Variable_Id;
1659             Attribute    : Variable;
1660
1661          begin
1662             --  Process non associated array attribute from package Naming
1663
1664             Attribute_Id := Attributes;
1665             while Attribute_Id /= No_Variable loop
1666                Attribute := Shared.Variable_Elements.Table (Attribute_Id);
1667
1668                if not Attribute.Value.Default then
1669                   if Attribute.Name = Name_Separate_Suffix then
1670
1671                      --  Attribute Separate_Suffix
1672
1673                      Get_Name_String (Attribute.Value.Value);
1674                      Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len));
1675                      Separate_Suffix := Name_Find;
1676
1677                   elsif Attribute.Name = Name_Casing then
1678
1679                      --  Attribute Casing
1680
1681                      begin
1682                         Casing :=
1683                           Value (Get_Name_String (Attribute.Value.Value));
1684
1685                      exception
1686                         when Constraint_Error =>
1687                            Error_Msg
1688                              (Data.Flags,
1689                               "invalid value for Casing",
1690                               Attribute.Value.Location, Project);
1691                      end;
1692
1693                   elsif Attribute.Name = Name_Dot_Replacement then
1694
1695                      --  Attribute Dot_Replacement
1696
1697                      Dot_Replacement := File_Name_Type (Attribute.Value.Value);
1698
1699                   end if;
1700                end if;
1701
1702                Attribute_Id := Attribute.Next;
1703             end loop;
1704          end Process_Naming;
1705
1706          procedure Process_Naming (Arrays : Array_Id) is
1707             Current_Array_Id : Array_Id;
1708             Current_Array    : Array_Data;
1709             Element_Id       : Array_Element_Id;
1710             Element          : Array_Element;
1711
1712          begin
1713             --  Process the associative array attribute of package Naming
1714
1715             Current_Array_Id := Arrays;
1716             while Current_Array_Id /= No_Array loop
1717                Current_Array := Shared.Arrays.Table (Current_Array_Id);
1718
1719                Element_Id := Current_Array.Value;
1720                while Element_Id /= No_Array_Element loop
1721                   Element := Shared.Array_Elements.Table (Element_Id);
1722
1723                   --  Get the name of the language
1724
1725                   Lang_Index := Get_Language_From_Name
1726                     (Project, Get_Name_String (Element.Index));
1727
1728                   if Lang_Index /= No_Language_Index then
1729                      case Current_Array.Name is
1730                         when Name_Spec_Suffix | Name_Specification_Suffix =>
1731
1732                            --  Attribute Spec_Suffix (<language>)
1733
1734                            Get_Name_String (Element.Value.Value);
1735                            Canonical_Case_File_Name
1736                              (Name_Buffer (1 .. Name_Len));
1737                            Lang_Index.Config.Naming_Data.Spec_Suffix :=
1738                              Name_Find;
1739
1740                         when Name_Implementation_Suffix | Name_Body_Suffix =>
1741
1742                            Get_Name_String (Element.Value.Value);
1743                            Canonical_Case_File_Name
1744                              (Name_Buffer (1 .. Name_Len));
1745
1746                            --  Attribute Body_Suffix (<language>)
1747
1748                            Lang_Index.Config.Naming_Data.Body_Suffix :=
1749                              Name_Find;
1750                            Lang_Index.Config.Naming_Data.Separate_Suffix :=
1751                              Lang_Index.Config.Naming_Data.Body_Suffix;
1752
1753                         when others =>
1754                            null;
1755                      end case;
1756                   end if;
1757
1758                   Element_Id := Element.Next;
1759                end loop;
1760
1761                Current_Array_Id := Current_Array.Next;
1762             end loop;
1763          end Process_Naming;
1764
1765          --------------------
1766          -- Process_Linker --
1767          --------------------
1768
1769          procedure Process_Linker (Attributes : Variable_Id) is
1770             Attribute_Id : Variable_Id;
1771             Attribute    : Variable;
1772
1773          begin
1774             --  Process non associated array attribute from package Linker
1775
1776             Attribute_Id := Attributes;
1777             while Attribute_Id /= No_Variable loop
1778                Attribute := Shared.Variable_Elements.Table (Attribute_Id);
1779
1780                if not Attribute.Value.Default then
1781                   if Attribute.Name = Name_Driver then
1782
1783                      --  Attribute Linker'Driver: the default linker to use
1784
1785                      Project.Config.Linker :=
1786                        Path_Name_Type (Attribute.Value.Value);
1787
1788                      --  Linker'Driver is also used to link shared libraries
1789                      --  if the obsolescent attribute Library_GCC has not been
1790                      --  specified.
1791
1792                      if Project.Config.Shared_Lib_Driver = No_File then
1793                         Project.Config.Shared_Lib_Driver :=
1794                           File_Name_Type (Attribute.Value.Value);
1795                      end if;
1796
1797                   elsif Attribute.Name = Name_Required_Switches then
1798
1799                      --  Attribute Required_Switches: the minimum trailing
1800                      --  options to use when invoking the linker
1801
1802                      Put (Into_List =>
1803                             Project.Config.Trailing_Linker_Required_Switches,
1804                           From_List => Attribute.Value.Values,
1805                           In_Tree   => Data.Tree);
1806
1807                   elsif Attribute.Name = Name_Map_File_Option then
1808                      Project.Config.Map_File_Option := Attribute.Value.Value;
1809
1810                   elsif Attribute.Name = Name_Max_Command_Line_Length then
1811                      begin
1812                         Project.Config.Max_Command_Line_Length :=
1813                           Natural'Value (Get_Name_String
1814                                          (Attribute.Value.Value));
1815
1816                      exception
1817                         when Constraint_Error =>
1818                            Error_Msg
1819                              (Data.Flags,
1820                               "value must be positive or equal to 0",
1821                               Attribute.Value.Location, Project);
1822                      end;
1823
1824                   elsif Attribute.Name = Name_Response_File_Format then
1825                      declare
1826                         Name  : Name_Id;
1827
1828                      begin
1829                         Get_Name_String (Attribute.Value.Value);
1830                         To_Lower (Name_Buffer (1 .. Name_Len));
1831                         Name := Name_Find;
1832
1833                         if Name = Name_None then
1834                            Project.Config.Resp_File_Format := None;
1835
1836                         elsif Name = Name_Gnu then
1837                            Project.Config.Resp_File_Format := GNU;
1838
1839                         elsif Name = Name_Object_List then
1840                            Project.Config.Resp_File_Format := Object_List;
1841
1842                         elsif Name = Name_Option_List then
1843                            Project.Config.Resp_File_Format := Option_List;
1844
1845                         elsif Name_Buffer (1 .. Name_Len) = "gcc" then
1846                            Project.Config.Resp_File_Format := GCC;
1847
1848                         elsif Name_Buffer (1 .. Name_Len) = "gcc_gnu" then
1849                            Project.Config.Resp_File_Format := GCC_GNU;
1850
1851                         elsif
1852                           Name_Buffer (1 .. Name_Len) = "gcc_option_list"
1853                         then
1854                            Project.Config.Resp_File_Format := GCC_Option_List;
1855
1856                         elsif
1857                           Name_Buffer (1 .. Name_Len) = "gcc_object_list"
1858                         then
1859                            Project.Config.Resp_File_Format := GCC_Object_List;
1860
1861                         else
1862                            Error_Msg
1863                              (Data.Flags,
1864                               "illegal response file format",
1865                               Attribute.Value.Location, Project);
1866                         end if;
1867                      end;
1868
1869                   elsif Attribute.Name = Name_Response_File_Switches then
1870                      Put (Into_List => Project.Config.Resp_File_Options,
1871                           From_List => Attribute.Value.Values,
1872                           In_Tree   => Data.Tree);
1873                   end if;
1874                end if;
1875
1876                Attribute_Id := Attribute.Next;
1877             end loop;
1878          end Process_Linker;
1879
1880       --  Start of processing for Process_Packages
1881
1882       begin
1883          Packages := Project.Decl.Packages;
1884          while Packages /= No_Package loop
1885             Element := Shared.Packages.Table (Packages);
1886
1887             case Element.Name is
1888                when Name_Binder =>
1889
1890                   --  Process attributes of package Binder
1891
1892                   Process_Binder (Element.Decl.Arrays);
1893
1894                when Name_Builder =>
1895
1896                   --  Process attributes of package Builder
1897
1898                   Process_Builder (Element.Decl.Attributes);
1899
1900                when Name_Compiler =>
1901
1902                   --  Process attributes of package Compiler
1903
1904                   Process_Compiler (Element.Decl.Arrays);
1905
1906                when Name_Linker =>
1907
1908                   --  Process attributes of package Linker
1909
1910                   Process_Linker (Element.Decl.Attributes);
1911
1912                when Name_Naming =>
1913
1914                   --  Process attributes of package Naming
1915
1916                   Process_Naming (Element.Decl.Attributes);
1917                   Process_Naming (Element.Decl.Arrays);
1918
1919                when others =>
1920                   null;
1921             end case;
1922
1923             Packages := Element.Next;
1924          end loop;
1925       end Process_Packages;
1926
1927       ---------------------------------------------
1928       -- Process_Project_Level_Simple_Attributes --
1929       ---------------------------------------------
1930
1931       procedure Process_Project_Level_Simple_Attributes is
1932          Attribute_Id : Variable_Id;
1933          Attribute    : Variable;
1934          List         : String_List_Id;
1935
1936       begin
1937          --  Process non associated array attribute at project level
1938
1939          Attribute_Id := Project.Decl.Attributes;
1940          while Attribute_Id /= No_Variable loop
1941             Attribute := Shared.Variable_Elements.Table (Attribute_Id);
1942
1943             if not Attribute.Value.Default then
1944                if Attribute.Name = Name_Target then
1945
1946                   --  Attribute Target: the target specified
1947
1948                   Project.Config.Target := Attribute.Value.Value;
1949
1950                elsif Attribute.Name = Name_Library_Builder then
1951
1952                   --  Attribute Library_Builder: the application to invoke
1953                   --  to build libraries.
1954
1955                   Project.Config.Library_Builder :=
1956                     Path_Name_Type (Attribute.Value.Value);
1957
1958                elsif Attribute.Name = Name_Archive_Builder then
1959
1960                   --  Attribute Archive_Builder: the archive builder
1961                   --  (usually "ar") and its minimum options (usually "cr").
1962
1963                   List := Attribute.Value.Values;
1964
1965                   if List = Nil_String then
1966                      Error_Msg
1967                        (Data.Flags,
1968                         "archive builder cannot be null",
1969                         Attribute.Value.Location, Project);
1970                   end if;
1971
1972                   Put (Into_List => Project.Config.Archive_Builder,
1973                        From_List => List,
1974                        In_Tree   => Data.Tree);
1975
1976                elsif Attribute.Name = Name_Archive_Builder_Append_Option then
1977
1978                   --  Attribute Archive_Builder: the archive builder
1979                   --  (usually "ar") and its minimum options (usually "cr").
1980
1981                   List := Attribute.Value.Values;
1982
1983                   if List /= Nil_String then
1984                      Put
1985                        (Into_List =>
1986                           Project.Config.Archive_Builder_Append_Option,
1987                         From_List => List,
1988                         In_Tree   => Data.Tree);
1989                   end if;
1990
1991                elsif Attribute.Name = Name_Archive_Indexer then
1992
1993                   --  Attribute Archive_Indexer: the optional archive
1994                   --  indexer (usually "ranlib") with its minimum options
1995                   --  (usually none).
1996
1997                   List := Attribute.Value.Values;
1998
1999                   if List = Nil_String then
2000                      Error_Msg
2001                        (Data.Flags,
2002                         "archive indexer cannot be null",
2003                         Attribute.Value.Location, Project);
2004                   end if;
2005
2006                   Put (Into_List => Project.Config.Archive_Indexer,
2007                        From_List => List,
2008                        In_Tree   => Data.Tree);
2009
2010                elsif Attribute.Name = Name_Library_Partial_Linker then
2011
2012                   --  Attribute Library_Partial_Linker: the optional linker
2013                   --  driver with its minimum options, to partially link
2014                   --  archives.
2015
2016                   List := Attribute.Value.Values;
2017
2018                   if List = Nil_String then
2019                      Error_Msg
2020                        (Data.Flags,
2021                         "partial linker cannot be null",
2022                         Attribute.Value.Location, Project);
2023                   end if;
2024
2025                   Put (Into_List => Project.Config.Lib_Partial_Linker,
2026                        From_List => List,
2027                        In_Tree   => Data.Tree);
2028
2029                elsif Attribute.Name = Name_Library_GCC then
2030                   Project.Config.Shared_Lib_Driver :=
2031                     File_Name_Type (Attribute.Value.Value);
2032                   Error_Msg
2033                     (Data.Flags,
2034                      "?Library_'G'C'C is an obsolescent attribute, " &
2035                      "use Linker''Driver instead",
2036                      Attribute.Value.Location, Project);
2037
2038                elsif Attribute.Name = Name_Archive_Suffix then
2039                   Project.Config.Archive_Suffix :=
2040                     File_Name_Type (Attribute.Value.Value);
2041
2042                elsif Attribute.Name = Name_Linker_Executable_Option then
2043
2044                   --  Attribute Linker_Executable_Option: optional options
2045                   --  to specify an executable name. Defaults to "-o".
2046
2047                   List := Attribute.Value.Values;
2048
2049                   if List = Nil_String then
2050                      Error_Msg
2051                        (Data.Flags,
2052                         "linker executable option cannot be null",
2053                         Attribute.Value.Location, Project);
2054                   end if;
2055
2056                   Put (Into_List => Project.Config.Linker_Executable_Option,
2057                        From_List => List,
2058                        In_Tree   => Data.Tree);
2059
2060                elsif Attribute.Name = Name_Linker_Lib_Dir_Option then
2061
2062                   --  Attribute Linker_Lib_Dir_Option: optional options
2063                   --  to specify a library search directory. Defaults to
2064                   --  "-L".
2065
2066                   Get_Name_String (Attribute.Value.Value);
2067
2068                   if Name_Len = 0 then
2069                      Error_Msg
2070                        (Data.Flags,
2071                         "linker library directory option cannot be empty",
2072                         Attribute.Value.Location, Project);
2073                   end if;
2074
2075                   Project.Config.Linker_Lib_Dir_Option :=
2076                     Attribute.Value.Value;
2077
2078                elsif Attribute.Name = Name_Linker_Lib_Name_Option then
2079
2080                   --  Attribute Linker_Lib_Name_Option: optional options
2081                   --  to specify the name of a library to be linked in.
2082                   --  Defaults to "-l".
2083
2084                   Get_Name_String (Attribute.Value.Value);
2085
2086                   if Name_Len = 0 then
2087                      Error_Msg
2088                        (Data.Flags,
2089                         "linker library name option cannot be empty",
2090                         Attribute.Value.Location, Project);
2091                   end if;
2092
2093                   Project.Config.Linker_Lib_Name_Option :=
2094                     Attribute.Value.Value;
2095
2096                elsif Attribute.Name = Name_Run_Path_Option then
2097
2098                   --  Attribute Run_Path_Option: optional options to
2099                   --  specify a path for libraries.
2100
2101                   List := Attribute.Value.Values;
2102
2103                   if List /= Nil_String then
2104                      Put (Into_List => Project.Config.Run_Path_Option,
2105                           From_List => List,
2106                           In_Tree   => Data.Tree);
2107                   end if;
2108
2109                elsif Attribute.Name = Name_Run_Path_Origin then
2110                   Get_Name_String (Attribute.Value.Value);
2111
2112                   if Name_Len = 0 then
2113                      Error_Msg
2114                        (Data.Flags,
2115                         "run path origin cannot be empty",
2116                         Attribute.Value.Location, Project);
2117                   end if;
2118
2119                   Project.Config.Run_Path_Origin := Attribute.Value.Value;
2120
2121                elsif Attribute.Name = Name_Library_Install_Name_Option then
2122                   Project.Config.Library_Install_Name_Option :=
2123                     Attribute.Value.Value;
2124
2125                elsif Attribute.Name = Name_Separate_Run_Path_Options then
2126                   declare
2127                      pragma Unsuppress (All_Checks);
2128                   begin
2129                      Project.Config.Separate_Run_Path_Options :=
2130                        Boolean'Value (Get_Name_String (Attribute.Value.Value));
2131                   exception
2132                      when Constraint_Error =>
2133                         Error_Msg
2134                           (Data.Flags,
2135                            "invalid value """ &
2136                            Get_Name_String (Attribute.Value.Value) &
2137                            """ for Separate_Run_Path_Options",
2138                            Attribute.Value.Location, Project);
2139                   end;
2140
2141                elsif Attribute.Name = Name_Library_Support then
2142                   declare
2143                      pragma Unsuppress (All_Checks);
2144                   begin
2145                      Project.Config.Lib_Support :=
2146                        Library_Support'Value (Get_Name_String
2147                                               (Attribute.Value.Value));
2148                   exception
2149                      when Constraint_Error =>
2150                         Error_Msg
2151                           (Data.Flags,
2152                            "invalid value """ &
2153                            Get_Name_String (Attribute.Value.Value) &
2154                            """ for Library_Support",
2155                            Attribute.Value.Location, Project);
2156                   end;
2157
2158                elsif Attribute.Name = Name_Shared_Library_Prefix then
2159                   Project.Config.Shared_Lib_Prefix :=
2160                     File_Name_Type (Attribute.Value.Value);
2161
2162                elsif Attribute.Name = Name_Shared_Library_Suffix then
2163                   Project.Config.Shared_Lib_Suffix :=
2164                     File_Name_Type (Attribute.Value.Value);
2165
2166                elsif Attribute.Name = Name_Symbolic_Link_Supported then
2167                   declare
2168                      pragma Unsuppress (All_Checks);
2169                   begin
2170                      Project.Config.Symbolic_Link_Supported :=
2171                        Boolean'Value (Get_Name_String
2172                                       (Attribute.Value.Value));
2173                   exception
2174                      when Constraint_Error =>
2175                         Error_Msg
2176                           (Data.Flags,
2177                            "invalid value """
2178                              & Get_Name_String (Attribute.Value.Value)
2179                              & """ for Symbolic_Link_Supported",
2180                            Attribute.Value.Location, Project);
2181                   end;
2182
2183                elsif
2184                  Attribute.Name = Name_Library_Major_Minor_Id_Supported
2185                then
2186                   declare
2187                      pragma Unsuppress (All_Checks);
2188                   begin
2189                      Project.Config.Lib_Maj_Min_Id_Supported :=
2190                        Boolean'Value (Get_Name_String
2191                                       (Attribute.Value.Value));
2192                   exception
2193                      when Constraint_Error =>
2194                         Error_Msg
2195                           (Data.Flags,
2196                            "invalid value """ &
2197                            Get_Name_String (Attribute.Value.Value) &
2198                            """ for Library_Major_Minor_Id_Supported",
2199                            Attribute.Value.Location, Project);
2200                   end;
2201
2202                elsif Attribute.Name = Name_Library_Auto_Init_Supported then
2203                   declare
2204                      pragma Unsuppress (All_Checks);
2205                   begin
2206                      Project.Config.Auto_Init_Supported :=
2207                        Boolean'Value (Get_Name_String (Attribute.Value.Value));
2208                   exception
2209                      when Constraint_Error =>
2210                         Error_Msg
2211                           (Data.Flags,
2212                            "invalid value """
2213                              & Get_Name_String (Attribute.Value.Value)
2214                              & """ for Library_Auto_Init_Supported",
2215                            Attribute.Value.Location, Project);
2216                   end;
2217
2218                elsif Attribute.Name = Name_Shared_Library_Minimum_Switches then
2219                   List := Attribute.Value.Values;
2220
2221                   if List /= Nil_String then
2222                      Put (Into_List => Project.Config.Shared_Lib_Min_Options,
2223                           From_List => List,
2224                           In_Tree   => Data.Tree);
2225                   end if;
2226
2227                elsif Attribute.Name = Name_Library_Version_Switches then
2228                   List := Attribute.Value.Values;
2229
2230                   if List /= Nil_String then
2231                      Put (Into_List => Project.Config.Lib_Version_Options,
2232                           From_List => List,
2233                           In_Tree   => Data.Tree);
2234                   end if;
2235                end if;
2236             end if;
2237
2238             Attribute_Id := Attribute.Next;
2239          end loop;
2240       end Process_Project_Level_Simple_Attributes;
2241
2242       --------------------------------------------
2243       -- Process_Project_Level_Array_Attributes --
2244       --------------------------------------------
2245
2246       procedure Process_Project_Level_Array_Attributes is
2247          Current_Array_Id : Array_Id;
2248          Current_Array    : Array_Data;
2249          Element_Id       : Array_Element_Id;
2250          Element          : Array_Element;
2251          List             : String_List_Id;
2252
2253       begin
2254          --  Process the associative array attributes at project level
2255
2256          Current_Array_Id := Project.Decl.Arrays;
2257          while Current_Array_Id /= No_Array loop
2258             Current_Array := Shared.Arrays.Table (Current_Array_Id);
2259
2260             Element_Id := Current_Array.Value;
2261             while Element_Id /= No_Array_Element loop
2262                Element := Shared.Array_Elements.Table (Element_Id);
2263
2264                --  Get the name of the language
2265
2266                Lang_Index :=
2267                  Get_Language_From_Name
2268                    (Project, Get_Name_String (Element.Index));
2269
2270                if Lang_Index /= No_Language_Index then
2271                   case Current_Array.Name is
2272                      when Name_Inherit_Source_Path =>
2273                         List := Element.Value.Values;
2274
2275                         if List /= Nil_String then
2276                            Put
2277                              (Into_List  =>
2278                                 Lang_Index.Config.Include_Compatible_Languages,
2279                               From_List  => List,
2280                               In_Tree    => Data.Tree,
2281                               Lower_Case => True);
2282                         end if;
2283
2284                      when Name_Toolchain_Description =>
2285
2286                         --  Attribute Toolchain_Description (<language>)
2287
2288                         Lang_Index.Config.Toolchain_Description :=
2289                           Element.Value.Value;
2290
2291                      when Name_Toolchain_Version =>
2292
2293                         --  Attribute Toolchain_Version (<language>)
2294
2295                         Lang_Index.Config.Toolchain_Version :=
2296                           Element.Value.Value;
2297
2298                         --  For Ada, set proper checksum computation mode
2299
2300                         if Lang_Index.Name = Name_Ada then
2301                            declare
2302                               Vers : constant String :=
2303                                        Get_Name_String (Element.Value.Value);
2304                               pragma Assert (Vers'First = 1);
2305
2306                            begin
2307                               --  Version 6.3 or earlier
2308
2309                               if Vers'Length >= 8
2310                                 and then Vers (1 .. 5) = "GNAT "
2311                                 and then Vers (7) = '.'
2312                                 and then
2313                                   (Vers (6) < '6'
2314                                     or else
2315                                       (Vers (6) = '6' and then Vers (8) < '4'))
2316                               then
2317                                  Checksum_GNAT_6_3 := True;
2318
2319                                  --  Version 5.03 or earlier
2320
2321                                  if Vers (6) < '5'
2322                                    or else (Vers (6) = '5'
2323                                              and then Vers (Vers'Last) < '4')
2324                                  then
2325                                     Checksum_GNAT_5_03 := True;
2326
2327                                     --  Version 5.02 or earlier
2328
2329                                     if Vers (6) /= '5'
2330                                       or else Vers (Vers'Last) < '3'
2331                                     then
2332                                        Checksum_Accumulate_Token_Checksum :=
2333                                          False;
2334                                     end if;
2335                                  end if;
2336                               end if;
2337                            end;
2338                         end if;
2339
2340                      when Name_Runtime_Library_Dir =>
2341
2342                         --  Attribute Runtime_Library_Dir (<language>)
2343
2344                         Lang_Index.Config.Runtime_Library_Dir :=
2345                           Element.Value.Value;
2346
2347                      when Name_Runtime_Source_Dir =>
2348
2349                         --  Attribute Runtime_Source_Dir (<language>)
2350
2351                         Lang_Index.Config.Runtime_Source_Dir :=
2352                           Element.Value.Value;
2353
2354                      when Name_Object_Generated =>
2355                         declare
2356                            pragma Unsuppress (All_Checks);
2357                            Value : Boolean;
2358
2359                         begin
2360                            Value :=
2361                              Boolean'Value
2362                                (Get_Name_String (Element.Value.Value));
2363
2364                            Lang_Index.Config.Object_Generated := Value;
2365
2366                            --  If no object is generated, no object may be
2367                            --  linked.
2368
2369                            if not Value then
2370                               Lang_Index.Config.Objects_Linked := False;
2371                            end if;
2372
2373                         exception
2374                            when Constraint_Error =>
2375                               Error_Msg
2376                                 (Data.Flags,
2377                                  "invalid value """
2378                                  & Get_Name_String (Element.Value.Value)
2379                                  & """ for Object_Generated",
2380                                  Element.Value.Location, Project);
2381                         end;
2382
2383                      when Name_Objects_Linked =>
2384                         declare
2385                            pragma Unsuppress (All_Checks);
2386                            Value : Boolean;
2387
2388                         begin
2389                            Value :=
2390                              Boolean'Value
2391                                (Get_Name_String (Element.Value.Value));
2392
2393                            --  No change if Object_Generated is False, as this
2394                            --  forces Objects_Linked to be False too.
2395
2396                            if Lang_Index.Config.Object_Generated then
2397                               Lang_Index.Config.Objects_Linked := Value;
2398                            end if;
2399
2400                         exception
2401                            when Constraint_Error =>
2402                               Error_Msg
2403                                 (Data.Flags,
2404                                  "invalid value """
2405                                  & Get_Name_String (Element.Value.Value)
2406                                  & """ for Objects_Linked",
2407                                  Element.Value.Location, Project);
2408                         end;
2409                      when others =>
2410                         null;
2411                   end case;
2412                end if;
2413
2414                Element_Id := Element.Next;
2415             end loop;
2416
2417             Current_Array_Id := Current_Array.Next;
2418          end loop;
2419       end Process_Project_Level_Array_Attributes;
2420
2421    --  Start of processing for Check_Configuration
2422
2423    begin
2424       Process_Project_Level_Simple_Attributes;
2425       Process_Project_Level_Array_Attributes;
2426       Process_Packages;
2427
2428       --  For unit based languages, set Casing, Dot_Replacement and
2429       --  Separate_Suffix in Naming_Data.
2430
2431       Lang_Index := Project.Languages;
2432       while Lang_Index /= No_Language_Index loop
2433          if Lang_Index.Config.Kind = Unit_Based then
2434             Lang_Index.Config.Naming_Data.Casing := Casing;
2435             Lang_Index.Config.Naming_Data.Dot_Replacement := Dot_Replacement;
2436
2437             if Separate_Suffix /= No_File then
2438                Lang_Index.Config.Naming_Data.Separate_Suffix :=
2439                  Separate_Suffix;
2440             end if;
2441
2442             exit;
2443          end if;
2444
2445          Lang_Index := Lang_Index.Next;
2446       end loop;
2447
2448       --  Give empty names to various prefixes/suffixes, if they have not
2449       --  been specified in the configuration.
2450
2451       if Project.Config.Archive_Suffix = No_File then
2452          Project.Config.Archive_Suffix := Empty_File;
2453       end if;
2454
2455       if Project.Config.Shared_Lib_Prefix = No_File then
2456          Project.Config.Shared_Lib_Prefix := Empty_File;
2457       end if;
2458
2459       if Project.Config.Shared_Lib_Suffix = No_File then
2460          Project.Config.Shared_Lib_Suffix := Empty_File;
2461       end if;
2462
2463       Lang_Index := Project.Languages;
2464       while Lang_Index /= No_Language_Index loop
2465
2466          --  For all languages, Compiler_Driver needs to be specified. This is
2467          --  only needed if we do intend to compile (not in GPS for instance).
2468
2469          if Data.Flags.Compiler_Driver_Mandatory
2470            and then Lang_Index.Config.Compiler_Driver = No_File
2471          then
2472             Error_Msg_Name_1 := Lang_Index.Display_Name;
2473             Error_Msg
2474               (Data.Flags,
2475                "?no compiler specified for language %%" &
2476                  ", ignoring all its sources",
2477                No_Location, Project);
2478
2479             if Lang_Index = Project.Languages then
2480                Project.Languages := Lang_Index.Next;
2481             else
2482                Prev_Index.Next := Lang_Index.Next;
2483             end if;
2484
2485          elsif Lang_Index.Config.Kind = Unit_Based then
2486             Prev_Index := Lang_Index;
2487
2488             --  For unit based languages, Dot_Replacement, Spec_Suffix and
2489             --  Body_Suffix need to be specified.
2490
2491             if Lang_Index.Config.Naming_Data.Dot_Replacement = No_File then
2492                Error_Msg
2493                  (Data.Flags,
2494                   "Dot_Replacement not specified for " &
2495                   Get_Name_String (Lang_Index.Name),
2496                   No_Location, Project);
2497             end if;
2498
2499             if Lang_Index.Config.Naming_Data.Spec_Suffix = No_File then
2500                Error_Msg
2501                  (Data.Flags,
2502                   "Spec_Suffix not specified for " &
2503                   Get_Name_String (Lang_Index.Name),
2504                   No_Location, Project);
2505             end if;
2506
2507             if Lang_Index.Config.Naming_Data.Body_Suffix = No_File then
2508                Error_Msg
2509                  (Data.Flags,
2510                   "Body_Suffix not specified for " &
2511                   Get_Name_String (Lang_Index.Name),
2512                   No_Location, Project);
2513             end if;
2514
2515          else
2516             Prev_Index := Lang_Index;
2517
2518             --  For file based languages, either Spec_Suffix or Body_Suffix
2519             --  need to be specified.
2520
2521             if Data.Flags.Require_Sources_Other_Lang
2522               and then Lang_Index.Config.Naming_Data.Spec_Suffix = No_File
2523               and then Lang_Index.Config.Naming_Data.Body_Suffix = No_File
2524             then
2525                Error_Msg_Name_1 := Lang_Index.Display_Name;
2526                Error_Msg
2527                  (Data.Flags,
2528                   "no suffixes specified for %%",
2529                   No_Location, Project);
2530             end if;
2531          end if;
2532
2533          Lang_Index := Lang_Index.Next;
2534       end loop;
2535    end Check_Configuration;
2536
2537    -------------------------------
2538    -- Check_If_Externally_Built --
2539    -------------------------------
2540
2541    procedure Check_If_Externally_Built
2542      (Project : Project_Id;
2543       Data    : in out Tree_Processing_Data)
2544    is
2545       Shared   : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
2546       Externally_Built : constant Variable_Value :=
2547                            Util.Value_Of
2548                             (Name_Externally_Built,
2549                              Project.Decl.Attributes, Shared);
2550
2551    begin
2552       if not Externally_Built.Default then
2553          Get_Name_String (Externally_Built.Value);
2554          To_Lower (Name_Buffer (1 .. Name_Len));
2555
2556          if Name_Buffer (1 .. Name_Len) = "true" then
2557             Project.Externally_Built := True;
2558
2559          elsif Name_Buffer (1 .. Name_Len) /= "false" then
2560             Error_Msg (Data.Flags,
2561                        "Externally_Built may only be true or false",
2562                        Externally_Built.Location, Project);
2563          end if;
2564       end if;
2565
2566       --  A virtual project extending an externally built project is itself
2567       --  externally built.
2568
2569       if Project.Virtual and then Project.Extends /= No_Project then
2570          Project.Externally_Built := Project.Extends.Externally_Built;
2571       end if;
2572
2573       if Project.Externally_Built then
2574          Debug_Output ("project is externally built");
2575       else
2576          Debug_Output ("project is not externally built");
2577       end if;
2578    end Check_If_Externally_Built;
2579
2580    ----------------------
2581    -- Check_Interfaces --
2582    ----------------------
2583
2584    procedure Check_Interfaces
2585      (Project : Project_Id;
2586       Data    : in out Tree_Processing_Data)
2587    is
2588       Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
2589
2590       Interfaces : constant Prj.Variable_Value :=
2591                      Prj.Util.Value_Of
2592                        (Snames.Name_Interfaces,
2593                         Project.Decl.Attributes,
2594                         Shared);
2595
2596       Library_Interface : constant Prj.Variable_Value :=
2597                             Prj.Util.Value_Of
2598                               (Snames.Name_Library_Interface,
2599                                Project.Decl.Attributes,
2600                                Shared);
2601
2602       List      : String_List_Id;
2603       Element   : String_Element;
2604       Name      : File_Name_Type;
2605       Iter      : Source_Iterator;
2606       Source    : Source_Id;
2607       Project_2 : Project_Id;
2608       Other     : Source_Id;
2609
2610    begin
2611       if not Interfaces.Default then
2612
2613          --  Set In_Interfaces to False for all sources. It will be set to True
2614          --  later for the sources in the Interfaces list.
2615
2616          Project_2 := Project;
2617          while Project_2 /= No_Project loop
2618             Iter := For_Each_Source (Data.Tree, Project_2);
2619             loop
2620                Source := Prj.Element (Iter);
2621                exit when Source = No_Source;
2622                Source.In_Interfaces := False;
2623                Next (Iter);
2624             end loop;
2625
2626             Project_2 := Project_2.Extends;
2627          end loop;
2628
2629          List := Interfaces.Values;
2630          while List /= Nil_String loop
2631             Element := Shared.String_Elements.Table (List);
2632             Name := Canonical_Case_File_Name (Element.Value);
2633
2634             Project_2 := Project;
2635             Big_Loop :
2636             while Project_2 /= No_Project loop
2637                Iter := For_Each_Source (Data.Tree, Project_2);
2638
2639                loop
2640                   Source := Prj.Element (Iter);
2641                   exit when Source = No_Source;
2642
2643                   if Source.File = Name then
2644                      if not Source.Locally_Removed then
2645                         Source.In_Interfaces := True;
2646                         Source.Declared_In_Interfaces := True;
2647
2648                         Other := Other_Part (Source);
2649
2650                         if Other /= No_Source then
2651                            Other.In_Interfaces := True;
2652                            Other.Declared_In_Interfaces := True;
2653                         end if;
2654
2655                         Debug_Output
2656                           ("interface: ", Name_Id (Source.Path.Name));
2657                      end if;
2658
2659                      exit Big_Loop;
2660                   end if;
2661
2662                   Next (Iter);
2663                end loop;
2664
2665                Project_2 := Project_2.Extends;
2666             end loop Big_Loop;
2667
2668             if Source = No_Source then
2669                Error_Msg_File_1 := File_Name_Type (Element.Value);
2670                Error_Msg_Name_1 := Project.Name;
2671
2672                Error_Msg
2673                  (Data.Flags,
2674                   "{ cannot be an interface of project %% "
2675                   & "as it is not one of its sources",
2676                   Element.Location, Project);
2677             end if;
2678
2679             List := Element.Next;
2680          end loop;
2681
2682          Project.Interfaces_Defined := True;
2683
2684       elsif Project.Library and then not Library_Interface.Default then
2685
2686          --  Set In_Interfaces to False for all sources. It will be set to True
2687          --  later for the sources in the Library_Interface list.
2688
2689          Project_2 := Project;
2690          while Project_2 /= No_Project loop
2691             Iter := For_Each_Source (Data.Tree, Project_2);
2692             loop
2693                Source := Prj.Element (Iter);
2694                exit when Source = No_Source;
2695                Source.In_Interfaces := False;
2696                Next (Iter);
2697             end loop;
2698
2699             Project_2 := Project_2.Extends;
2700          end loop;
2701
2702          List := Library_Interface.Values;
2703          while List /= Nil_String loop
2704             Element := Shared.String_Elements.Table (List);
2705             Get_Name_String (Element.Value);
2706             To_Lower (Name_Buffer (1 .. Name_Len));
2707             Name := Name_Find;
2708
2709             Project_2 := Project;
2710             Big_Loop_2 :
2711             while Project_2 /= No_Project loop
2712                Iter := For_Each_Source (Data.Tree, Project_2);
2713
2714                loop
2715                   Source := Prj.Element (Iter);
2716                   exit when Source = No_Source;
2717
2718                   if Source.Unit /= No_Unit_Index
2719                     and then Source.Unit.Name = Name_Id (Name)
2720                   then
2721                      if not Source.Locally_Removed then
2722                         Source.In_Interfaces := True;
2723                         Source.Declared_In_Interfaces := True;
2724
2725                         Other := Other_Part (Source);
2726
2727                         if Other /= No_Source then
2728                            Other.In_Interfaces := True;
2729                            Other.Declared_In_Interfaces := True;
2730                         end if;
2731
2732                         Debug_Output
2733                           ("interface: ", Name_Id (Source.Path.Name));
2734                      end if;
2735
2736                      exit Big_Loop_2;
2737                   end if;
2738
2739                   Next (Iter);
2740                end loop;
2741
2742                Project_2 := Project_2.Extends;
2743             end loop Big_Loop_2;
2744
2745             List := Element.Next;
2746          end loop;
2747
2748          Project.Interfaces_Defined := True;
2749
2750       elsif Project.Extends /= No_Project
2751         and then Project.Extends.Interfaces_Defined
2752       then
2753          Project.Interfaces_Defined := True;
2754
2755          Iter := For_Each_Source (Data.Tree, Project);
2756          loop
2757             Source := Prj.Element (Iter);
2758             exit when Source = No_Source;
2759
2760             if not Source.Declared_In_Interfaces then
2761                Source.In_Interfaces := False;
2762             end if;
2763
2764             Next (Iter);
2765          end loop;
2766       end if;
2767    end Check_Interfaces;
2768
2769    ------------------------------
2770    -- Check_Library_Attributes --
2771    ------------------------------
2772
2773    --  This procedure is awfully long (over 700 lines) should be broken up???
2774
2775    procedure Check_Library_Attributes
2776      (Project : Project_Id;
2777       Data    : in out Tree_Processing_Data)
2778    is
2779       Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
2780
2781       Attributes   : constant Prj.Variable_Id := Project.Decl.Attributes;
2782
2783       Lib_Dir      : constant Prj.Variable_Value :=
2784                        Prj.Util.Value_Of
2785                          (Snames.Name_Library_Dir, Attributes, Shared);
2786
2787       Lib_Name     : constant Prj.Variable_Value :=
2788                        Prj.Util.Value_Of
2789                          (Snames.Name_Library_Name, Attributes, Shared);
2790
2791       Lib_Version  : constant Prj.Variable_Value :=
2792                        Prj.Util.Value_Of
2793                          (Snames.Name_Library_Version, Attributes, Shared);
2794
2795       Lib_ALI_Dir  : constant Prj.Variable_Value :=
2796                        Prj.Util.Value_Of
2797                          (Snames.Name_Library_Ali_Dir, Attributes, Shared);
2798
2799       Lib_GCC      : constant Prj.Variable_Value :=
2800                        Prj.Util.Value_Of
2801                          (Snames.Name_Library_GCC, Attributes, Shared);
2802
2803       The_Lib_Kind : constant Prj.Variable_Value :=
2804                        Prj.Util.Value_Of
2805                          (Snames.Name_Library_Kind, Attributes, Shared);
2806
2807       Imported_Project_List : Project_List;
2808
2809       Continuation : String_Access := No_Continuation_String'Access;
2810
2811       Support_For_Libraries : Library_Support;
2812
2813       Library_Directory_Present : Boolean;
2814
2815       procedure Check_Library (Proj : Project_Id; Extends : Boolean);
2816       --  Check if an imported or extended project if also a library project
2817
2818       -------------------
2819       -- Check_Library --
2820       -------------------
2821
2822       procedure Check_Library (Proj : Project_Id; Extends : Boolean) is
2823          Src_Id : Source_Id;
2824          Iter   : Source_Iterator;
2825
2826       begin
2827          if Proj /= No_Project then
2828             if not Proj.Library then
2829
2830                --  The only not library projects that are OK are those that
2831                --  have no sources. However, header files from non-Ada
2832                --  languages are OK, as there is nothing to compile.
2833
2834                Iter := For_Each_Source (Data.Tree, Proj);
2835                loop
2836                   Src_Id := Prj.Element (Iter);
2837                   exit when Src_Id = No_Source
2838                     or else Src_Id.Language.Config.Kind /= File_Based
2839                     or else Src_Id.Kind /= Spec;
2840                   Next (Iter);
2841                end loop;
2842
2843                if Src_Id /= No_Source then
2844                   Error_Msg_Name_1 := Project.Name;
2845                   Error_Msg_Name_2 := Proj.Name;
2846
2847                   if Extends then
2848                      if Project.Library_Kind /= Static then
2849                         Error_Msg
2850                           (Data.Flags,
2851                            Continuation.all &
2852                            "shared library project %% cannot extend " &
2853                            "project %% that is not a library project",
2854                            Project.Location, Project);
2855                         Continuation := Continuation_String'Access;
2856                      end if;
2857
2858                   elsif (not Unchecked_Shared_Lib_Imports)
2859                         and then Project.Library_Kind /= Static
2860                   then
2861                      Error_Msg
2862                        (Data.Flags,
2863                         Continuation.all &
2864                         "shared library project %% cannot import project %% " &
2865                         "that is not a shared library project",
2866                         Project.Location, Project);
2867                      Continuation := Continuation_String'Access;
2868                   end if;
2869                end if;
2870
2871             elsif Project.Library_Kind /= Static
2872               and then Proj.Library_Kind = Static
2873             then
2874                Error_Msg_Name_1 := Project.Name;
2875                Error_Msg_Name_2 := Proj.Name;
2876
2877                if Extends then
2878                   Error_Msg
2879                     (Data.Flags,
2880                      Continuation.all &
2881                      "shared library project %% cannot extend static " &
2882                      "library project %%",
2883                      Project.Location, Project);
2884                   Continuation := Continuation_String'Access;
2885
2886                elsif not Unchecked_Shared_Lib_Imports then
2887                   Error_Msg
2888                     (Data.Flags,
2889                      Continuation.all &
2890                      "shared library project %% cannot import static " &
2891                      "library project %%",
2892                      Project.Location, Project);
2893                   Continuation := Continuation_String'Access;
2894                end if;
2895
2896             end if;
2897          end if;
2898       end Check_Library;
2899
2900       Dir_Exists : Boolean;
2901
2902    --  Start of processing for Check_Library_Attributes
2903
2904    begin
2905       Library_Directory_Present := Lib_Dir.Value /= Empty_String;
2906
2907       --  Special case of extending project
2908
2909       if Project.Extends /= No_Project then
2910
2911          --  If the project extended is a library project, we inherit the
2912          --  library name, if it is not redefined; we check that the library
2913          --  directory is specified.
2914
2915          if Project.Extends.Library then
2916             if Project.Qualifier = Standard then
2917                Error_Msg
2918                  (Data.Flags,
2919                   "a standard project cannot extend a library project",
2920                   Project.Location, Project);
2921
2922             else
2923                if Lib_Name.Default then
2924                   Project.Library_Name := Project.Extends.Library_Name;
2925                end if;
2926
2927                if Lib_Dir.Default then
2928                   if not Project.Virtual then
2929                      Error_Msg
2930                        (Data.Flags,
2931                         "a project extending a library project must " &
2932                         "specify an attribute Library_Dir",
2933                         Project.Location, Project);
2934
2935                   else
2936                      --  For a virtual project extending a library project,
2937                      --  inherit library directory and library kind.
2938
2939                      Project.Library_Dir := Project.Extends.Library_Dir;
2940                      Library_Directory_Present := True;
2941                      Project.Library_Kind := Project.Extends.Library_Kind;
2942                   end if;
2943                end if;
2944             end if;
2945          end if;
2946       end if;
2947
2948       pragma Assert (Lib_Name.Kind = Single);
2949
2950       if Lib_Name.Value = Empty_String then
2951          if Current_Verbosity = High
2952            and then Project.Library_Name = No_Name
2953          then
2954             Debug_Indent;
2955             Write_Line ("no library name");
2956          end if;
2957
2958       else
2959          --  There is no restriction on the syntax of library names
2960
2961          Project.Library_Name := Lib_Name.Value;
2962       end if;
2963
2964       if Project.Library_Name /= No_Name then
2965          if Current_Verbosity = High then
2966             Write_Attr
2967               ("Library name: ", Get_Name_String (Project.Library_Name));
2968          end if;
2969
2970          pragma Assert (Lib_Dir.Kind = Single);
2971
2972          if not Library_Directory_Present then
2973             Debug_Output ("no library directory");
2974
2975          else
2976             --  Find path name (unless inherited), check that it is a directory
2977
2978             if Project.Library_Dir = No_Path_Information then
2979                Locate_Directory
2980                  (Project,
2981                   File_Name_Type (Lib_Dir.Value),
2982                   Path             => Project.Library_Dir,
2983                   Dir_Exists       => Dir_Exists,
2984                   Data             => Data,
2985                   Create           => "library",
2986                   Must_Exist       => False,
2987                   Location         => Lib_Dir.Location,
2988                   Externally_Built => Project.Externally_Built);
2989
2990             else
2991                Dir_Exists :=
2992                  Is_Directory
2993                    (Get_Name_String (Project.Library_Dir.Display_Name));
2994             end if;
2995
2996             if not Dir_Exists then
2997
2998                --  Get the absolute name of the library directory that
2999                --  does not exist, to report an error.
3000
3001                Err_Vars.Error_Msg_File_1 :=
3002                  File_Name_Type (Project.Library_Dir.Display_Name);
3003                Error_Msg
3004                  (Data.Flags,
3005                   "library directory { does not exist",
3006                   Lib_Dir.Location, Project);
3007
3008             elsif not Project.Externally_Built then
3009
3010                --  Library directory cannot be the same as Object directory
3011
3012                if Project.Library_Dir.Name = Project.Object_Directory.Name then
3013                   Error_Msg
3014                     (Data.Flags,
3015                      "library directory cannot be the same " &
3016                      "as object directory",
3017                      Lib_Dir.Location, Project);
3018                   Project.Library_Dir := No_Path_Information;
3019
3020                else
3021                   declare
3022                      OK       : Boolean := True;
3023                      Dirs_Id  : String_List_Id;
3024                      Dir_Elem : String_Element;
3025                      Pid      : Project_List;
3026
3027                   begin
3028                      --  The library directory cannot be the same as a source
3029                      --  directory of the current project.
3030
3031                      Dirs_Id := Project.Source_Dirs;
3032                      while Dirs_Id /= Nil_String loop
3033                         Dir_Elem := Shared.String_Elements.Table (Dirs_Id);
3034                         Dirs_Id  := Dir_Elem.Next;
3035
3036                         if Project.Library_Dir.Name =
3037                           Path_Name_Type (Dir_Elem.Value)
3038                         then
3039                            Err_Vars.Error_Msg_File_1 :=
3040                              File_Name_Type (Dir_Elem.Value);
3041                            Error_Msg
3042                              (Data.Flags,
3043                               "library directory cannot be the same " &
3044                               "as source directory {",
3045                               Lib_Dir.Location, Project);
3046                            OK := False;
3047                            exit;
3048                         end if;
3049                      end loop;
3050
3051                      if OK then
3052
3053                         --  The library directory cannot be the same as a
3054                         --  source directory of another project either.
3055
3056                         Pid := Data.Tree.Projects;
3057                         Project_Loop : loop
3058                            exit Project_Loop when Pid = null;
3059
3060                            if Pid.Project /= Project then
3061                               Dirs_Id := Pid.Project.Source_Dirs;
3062
3063                               Dir_Loop : while Dirs_Id /= Nil_String loop
3064                                  Dir_Elem :=
3065                                    Shared.String_Elements.Table (Dirs_Id);
3066                                  Dirs_Id  := Dir_Elem.Next;
3067
3068                                  if Project.Library_Dir.Name =
3069                                    Path_Name_Type (Dir_Elem.Value)
3070                                  then
3071                                     Err_Vars.Error_Msg_File_1 :=
3072                                       File_Name_Type (Dir_Elem.Value);
3073                                     Err_Vars.Error_Msg_Name_1 :=
3074                                       Pid.Project.Name;
3075
3076                                     Error_Msg
3077                                       (Data.Flags,
3078                                        "library directory cannot be the same" &
3079                                        " as source directory { of project %%",
3080                                        Lib_Dir.Location, Project);
3081                                     OK := False;
3082                                     exit Project_Loop;
3083                                  end if;
3084                               end loop Dir_Loop;
3085                            end if;
3086
3087                            Pid := Pid.Next;
3088                         end loop Project_Loop;
3089                      end if;
3090
3091                      if not OK then
3092                         Project.Library_Dir := No_Path_Information;
3093
3094                      elsif Current_Verbosity = High then
3095
3096                         --  Display the Library directory in high verbosity
3097
3098                         Write_Attr
3099                           ("Library directory",
3100                            Get_Name_String (Project.Library_Dir.Display_Name));
3101                      end if;
3102                   end;
3103                end if;
3104             end if;
3105          end if;
3106
3107       end if;
3108
3109       Project.Library :=
3110         Project.Library_Dir /= No_Path_Information
3111         and then Project.Library_Name /= No_Name;
3112
3113       if Project.Extends = No_Project then
3114          case Project.Qualifier is
3115             when Standard =>
3116                if Project.Library then
3117                   Error_Msg
3118                     (Data.Flags,
3119                      "a standard project cannot be a library project",
3120                      Lib_Name.Location, Project);
3121                end if;
3122
3123             when Library =>
3124                if not Project.Library then
3125                   if Project.Library_Name = No_Name then
3126                      Error_Msg
3127                        (Data.Flags,
3128                         "attribute Library_Name not declared",
3129                         Project.Location, Project);
3130
3131                      if not Library_Directory_Present then
3132                         Error_Msg
3133                           (Data.Flags,
3134                            "\attribute Library_Dir not declared",
3135                            Project.Location, Project);
3136                      end if;
3137
3138                   elsif Project.Library_Dir = No_Path_Information then
3139                      Error_Msg
3140                        (Data.Flags,
3141                         "attribute Library_Dir not declared",
3142                         Project.Location, Project);
3143                   end if;
3144                end if;
3145
3146             when others =>
3147                null;
3148
3149          end case;
3150       end if;
3151
3152       if Project.Library then
3153          Support_For_Libraries := Project.Config.Lib_Support;
3154
3155          if Support_For_Libraries = Prj.None then
3156             Error_Msg
3157               (Data.Flags,
3158                "?libraries are not supported on this platform",
3159                Lib_Name.Location, Project);
3160             Project.Library := False;
3161
3162          else
3163             if Lib_ALI_Dir.Value = Empty_String then
3164                Debug_Output ("no library ALI directory specified");
3165                Project.Library_ALI_Dir := Project.Library_Dir;
3166
3167             else
3168                --  Find path name, check that it is a directory
3169
3170                Locate_Directory
3171                  (Project,
3172                   File_Name_Type (Lib_ALI_Dir.Value),
3173                   Path             => Project.Library_ALI_Dir,
3174                   Create           => "library ALI",
3175                   Dir_Exists       => Dir_Exists,
3176                   Data             => Data,
3177                   Must_Exist       => False,
3178                   Location         => Lib_ALI_Dir.Location,
3179                   Externally_Built => Project.Externally_Built);
3180
3181                if not Dir_Exists then
3182
3183                   --  Get the absolute name of the library ALI directory that
3184                   --  does not exist, to report an error.
3185
3186                   Err_Vars.Error_Msg_File_1 :=
3187                     File_Name_Type (Project.Library_ALI_Dir.Display_Name);
3188                   Error_Msg
3189                     (Data.Flags,
3190                      "library 'A'L'I directory { does not exist",
3191                      Lib_ALI_Dir.Location, Project);
3192                end if;
3193
3194                if not Project.Externally_Built
3195                  and then Project.Library_ALI_Dir /= Project.Library_Dir
3196                then
3197                   --  The library ALI directory cannot be the same as the
3198                   --  Object directory.
3199
3200                   if Project.Library_ALI_Dir = Project.Object_Directory then
3201                      Error_Msg
3202                        (Data.Flags,
3203                         "library 'A'L'I directory cannot be the same " &
3204                         "as object directory",
3205                         Lib_ALI_Dir.Location, Project);
3206                      Project.Library_ALI_Dir := No_Path_Information;
3207
3208                   else
3209                      declare
3210                         OK       : Boolean := True;
3211                         Dirs_Id  : String_List_Id;
3212                         Dir_Elem : String_Element;
3213                         Pid      : Project_List;
3214
3215                      begin
3216                         --  The library ALI directory cannot be the same as
3217                         --  a source directory of the current project.
3218
3219                         Dirs_Id := Project.Source_Dirs;
3220                         while Dirs_Id /= Nil_String loop
3221                            Dir_Elem := Shared.String_Elements.Table (Dirs_Id);
3222                            Dirs_Id  := Dir_Elem.Next;
3223
3224                            if Project.Library_ALI_Dir.Name =
3225                              Path_Name_Type (Dir_Elem.Value)
3226                            then
3227                               Err_Vars.Error_Msg_File_1 :=
3228                                 File_Name_Type (Dir_Elem.Value);
3229                               Error_Msg
3230                                 (Data.Flags,
3231                                  "library 'A'L'I directory cannot be " &
3232                                  "the same as source directory {",
3233                                  Lib_ALI_Dir.Location, Project);
3234                               OK := False;
3235                               exit;
3236                            end if;
3237                         end loop;
3238
3239                         if OK then
3240
3241                            --  The library ALI directory cannot be the same as
3242                            --  a source directory of another project either.
3243
3244                            Pid := Data.Tree.Projects;
3245                            ALI_Project_Loop : loop
3246                               exit ALI_Project_Loop when Pid = null;
3247
3248                               if Pid.Project /= Project then
3249                                  Dirs_Id := Pid.Project.Source_Dirs;
3250
3251                                  ALI_Dir_Loop :
3252                                  while Dirs_Id /= Nil_String loop
3253                                     Dir_Elem :=
3254                                       Shared.String_Elements.Table (Dirs_Id);
3255                                     Dirs_Id  := Dir_Elem.Next;
3256
3257                                     if Project.Library_ALI_Dir.Name =
3258                                         Path_Name_Type (Dir_Elem.Value)
3259                                     then
3260                                        Err_Vars.Error_Msg_File_1 :=
3261                                          File_Name_Type (Dir_Elem.Value);
3262                                        Err_Vars.Error_Msg_Name_1 :=
3263                                          Pid.Project.Name;
3264
3265                                        Error_Msg
3266                                          (Data.Flags,
3267                                           "library 'A'L'I directory cannot " &
3268                                           "be the same as source directory " &
3269                                           "{ of project %%",
3270                                           Lib_ALI_Dir.Location, Project);
3271                                        OK := False;
3272                                        exit ALI_Project_Loop;
3273                                     end if;
3274                                  end loop ALI_Dir_Loop;
3275                               end if;
3276                               Pid := Pid.Next;
3277                            end loop ALI_Project_Loop;
3278                         end if;
3279
3280                         if not OK then
3281                            Project.Library_ALI_Dir := No_Path_Information;
3282
3283                         elsif Current_Verbosity = High then
3284
3285                            --  Display Library ALI directory in high verbosity
3286
3287                            Write_Attr
3288                              ("Library ALI dir",
3289                               Get_Name_String
3290                                 (Project.Library_ALI_Dir.Display_Name));
3291                         end if;
3292                      end;
3293                   end if;
3294                end if;
3295             end if;
3296
3297             pragma Assert (Lib_Version.Kind = Single);
3298
3299             if Lib_Version.Value = Empty_String then
3300                Debug_Output ("no library version specified");
3301
3302             else
3303                Project.Lib_Internal_Name := Lib_Version.Value;
3304             end if;
3305
3306             pragma Assert (The_Lib_Kind.Kind = Single);
3307
3308             if The_Lib_Kind.Value = Empty_String then
3309                Debug_Output ("no library kind specified");
3310
3311             else
3312                Get_Name_String (The_Lib_Kind.Value);
3313
3314                declare
3315                   Kind_Name : constant String :=
3316                                 To_Lower (Name_Buffer (1 .. Name_Len));
3317
3318                   OK : Boolean := True;
3319
3320                begin
3321                   if Kind_Name = "static" then
3322                      Project.Library_Kind := Static;
3323
3324                   elsif Kind_Name = "dynamic" then
3325                      Project.Library_Kind := Dynamic;
3326
3327                   elsif Kind_Name = "relocatable" then
3328                      Project.Library_Kind := Relocatable;
3329
3330                   else
3331                      Error_Msg
3332                        (Data.Flags,
3333                         "illegal value for Library_Kind",
3334                         The_Lib_Kind.Location, Project);
3335                      OK := False;
3336                   end if;
3337
3338                   if Current_Verbosity = High and then OK then
3339                      Write_Attr ("Library kind", Kind_Name);
3340                   end if;
3341
3342                   if Project.Library_Kind /= Static then
3343                      if Support_For_Libraries = Prj.Static_Only then
3344                         Error_Msg
3345                           (Data.Flags,
3346                            "only static libraries are supported " &
3347                            "on this platform",
3348                            The_Lib_Kind.Location, Project);
3349                         Project.Library := False;
3350
3351                      else
3352                         --  Check if (obsolescent) attribute Library_GCC or
3353                         --  Linker'Driver is declared.
3354
3355                         if Lib_GCC.Value /= Empty_String then
3356                            Error_Msg
3357                              (Data.Flags,
3358                               "?Library_'G'C'C is an obsolescent attribute, " &
3359                               "use Linker''Driver instead",
3360                               Lib_GCC.Location, Project);
3361                            Project.Config.Shared_Lib_Driver :=
3362                              File_Name_Type (Lib_GCC.Value);
3363
3364                         else
3365                            declare
3366                               Linker : constant Package_Id :=
3367                                          Value_Of
3368                                            (Name_Linker,
3369                                             Project.Decl.Packages,
3370                                             Shared);
3371                               Driver : constant Variable_Value :=
3372                                          Value_Of
3373                                            (Name                 => No_Name,
3374                                             Attribute_Or_Array_Name =>
3375                                               Name_Driver,
3376                                             In_Package           => Linker,
3377                                             Shared               => Shared);
3378
3379                            begin
3380                               if Driver /= Nil_Variable_Value
3381                                  and then Driver.Value /= Empty_String
3382                               then
3383                                  Project.Config.Shared_Lib_Driver :=
3384                                    File_Name_Type (Driver.Value);
3385                               end if;
3386                            end;
3387                         end if;
3388                      end if;
3389                   end if;
3390                end;
3391             end if;
3392
3393             if Project.Library
3394               and then Project.Qualifier /= Aggregate_Library
3395             then
3396                Debug_Output ("this is a library project file");
3397
3398                Check_Library (Project.Extends, Extends => True);
3399
3400                Imported_Project_List := Project.Imported_Projects;
3401                while Imported_Project_List /= null loop
3402                   Check_Library
3403                     (Imported_Project_List.Project,
3404                      Extends => False);
3405                   Imported_Project_List := Imported_Project_List.Next;
3406                end loop;
3407             end if;
3408
3409          end if;
3410       end if;
3411
3412       --  Check if Linker'Switches or Linker'Default_Switches are declared.
3413       --  Warn if they are declared, as it is a common error to think that
3414       --  library are "linked" with Linker switches.
3415
3416       if Project.Library then
3417          declare
3418             Linker_Package_Id : constant Package_Id :=
3419                                   Util.Value_Of
3420                                     (Name_Linker,
3421                                      Project.Decl.Packages, Shared);
3422             Linker_Package    : Package_Element;
3423             Switches          : Array_Element_Id := No_Array_Element;
3424
3425          begin
3426             if Linker_Package_Id /= No_Package then
3427                Linker_Package := Shared.Packages.Table (Linker_Package_Id);
3428
3429                Switches :=
3430                  Value_Of
3431                    (Name      => Name_Switches,
3432                     In_Arrays => Linker_Package.Decl.Arrays,
3433                     Shared    => Shared);
3434
3435                if Switches = No_Array_Element then
3436                   Switches :=
3437                     Value_Of
3438                       (Name      => Name_Default_Switches,
3439                        In_Arrays => Linker_Package.Decl.Arrays,
3440                        Shared    => Shared);
3441                end if;
3442
3443                if Switches /= No_Array_Element then
3444                   Error_Msg
3445                     (Data.Flags,
3446                      "?Linker switches not taken into account in library " &
3447                      "projects",
3448                      No_Location, Project);
3449                end if;
3450             end if;
3451          end;
3452       end if;
3453
3454       if Project.Extends /= No_Project and then Project.Extends.Library then
3455
3456          --  Remove the library name from Lib_Data_Table
3457
3458          for J in 1 .. Lib_Data_Table.Last loop
3459             if Lib_Data_Table.Table (J).Proj = Project.Extends then
3460                Lib_Data_Table.Table (J) :=
3461                  Lib_Data_Table.Table (Lib_Data_Table.Last);
3462                Lib_Data_Table.Set_Last (Lib_Data_Table.Last - 1);
3463                exit;
3464             end if;
3465          end loop;
3466       end if;
3467
3468       if Project.Library and then not Lib_Name.Default then
3469
3470          --  Check if the same library name is used in an other library project
3471
3472          for J in 1 .. Lib_Data_Table.Last loop
3473             if Lib_Data_Table.Table (J).Name = Project.Library_Name then
3474                Error_Msg_Name_1 := Lib_Data_Table.Table (J).Proj.Name;
3475                Error_Msg
3476                  (Data.Flags,
3477                   "Library name cannot be the same as in project %%",
3478                   Lib_Name.Location, Project);
3479                Project.Library := False;
3480                exit;
3481             end if;
3482          end loop;
3483       end if;
3484
3485       if Project.Library then
3486
3487          --  Record the library name
3488
3489          Lib_Data_Table.Append
3490            ((Name => Project.Library_Name, Proj => Project));
3491       end if;
3492    end Check_Library_Attributes;
3493
3494    --------------------------
3495    -- Check_Package_Naming --
3496    --------------------------
3497
3498    procedure Check_Package_Naming
3499      (Project : Project_Id;
3500       Data    : in out Tree_Processing_Data)
3501    is
3502       Shared    : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
3503       Naming_Id : constant Package_Id :=
3504                     Util.Value_Of
3505                       (Name_Naming, Project.Decl.Packages, Shared);
3506       Naming    : Package_Element;
3507
3508       Ada_Body_Suffix_Loc : Source_Ptr := No_Location;
3509
3510       procedure Check_Naming;
3511       --  Check the validity of the Naming package (suffixes valid, ...)
3512
3513       procedure Check_Common
3514         (Dot_Replacement : in out File_Name_Type;
3515          Casing          : in out Casing_Type;
3516          Casing_Defined  : out Boolean;
3517          Separate_Suffix : in out File_Name_Type;
3518          Sep_Suffix_Loc  : out Source_Ptr);
3519       --  Check attributes common
3520
3521       procedure Process_Exceptions_File_Based
3522         (Lang_Id : Language_Ptr;
3523          Kind    : Source_Kind);
3524       procedure Process_Exceptions_Unit_Based
3525         (Lang_Id : Language_Ptr;
3526          Kind    : Source_Kind);
3527       --  Process the naming exceptions for the two types of languages
3528
3529       procedure Initialize_Naming_Data;
3530       --  Initialize internal naming data for the various languages
3531
3532       ------------------
3533       -- Check_Common --
3534       ------------------
3535
3536       procedure Check_Common
3537         (Dot_Replacement : in out File_Name_Type;
3538          Casing          : in out Casing_Type;
3539          Casing_Defined  : out Boolean;
3540          Separate_Suffix : in out File_Name_Type;
3541          Sep_Suffix_Loc  : out Source_Ptr)
3542       is
3543          Dot_Repl      : constant Variable_Value :=
3544                            Util.Value_Of
3545                              (Name_Dot_Replacement,
3546                               Naming.Decl.Attributes,
3547                               Shared);
3548          Casing_String : constant Variable_Value :=
3549                            Util.Value_Of
3550                              (Name_Casing,
3551                               Naming.Decl.Attributes,
3552                               Shared);
3553          Sep_Suffix    : constant Variable_Value :=
3554                            Util.Value_Of
3555                              (Name_Separate_Suffix,
3556                               Naming.Decl.Attributes,
3557                               Shared);
3558          Dot_Repl_Loc  : Source_Ptr;
3559
3560       begin
3561          Sep_Suffix_Loc := No_Location;
3562
3563          if not Dot_Repl.Default then
3564             pragma Assert
3565               (Dot_Repl.Kind = Single, "Dot_Replacement is not a string");
3566
3567             if Length_Of_Name (Dot_Repl.Value) = 0 then
3568                Error_Msg
3569                  (Data.Flags, "Dot_Replacement cannot be empty",
3570                   Dot_Repl.Location, Project);
3571             end if;
3572
3573             Dot_Replacement := Canonical_Case_File_Name (Dot_Repl.Value);
3574             Dot_Repl_Loc    := Dot_Repl.Location;
3575
3576             declare
3577                Repl : constant String := Get_Name_String (Dot_Replacement);
3578
3579             begin
3580                --  Dot_Replacement cannot
3581                --   - be empty
3582                --   - start or end with an alphanumeric
3583                --   - be a single '_'
3584                --   - start with an '_' followed by an alphanumeric
3585                --   - contain a '.' except if it is "."
3586
3587                if Repl'Length = 0
3588                  or else Is_Alphanumeric (Repl (Repl'First))
3589                  or else Is_Alphanumeric (Repl (Repl'Last))
3590                  or else (Repl (Repl'First) = '_'
3591                            and then
3592                              (Repl'Length = 1
3593                                or else
3594                                  Is_Alphanumeric (Repl (Repl'First + 1))))
3595                  or else (Repl'Length > 1
3596                            and then
3597                              Index (Source => Repl, Pattern => ".") /= 0)
3598                then
3599                   Error_Msg
3600                     (Data.Flags,
3601                      '"' & Repl &
3602                      """ is illegal for Dot_Replacement.",
3603                      Dot_Repl_Loc, Project);
3604                end if;
3605             end;
3606          end if;
3607
3608          if Dot_Replacement /= No_File then
3609             Write_Attr
3610               ("Dot_Replacement", Get_Name_String (Dot_Replacement));
3611          end if;
3612
3613          Casing_Defined := False;
3614
3615          if not Casing_String.Default then
3616             pragma Assert
3617               (Casing_String.Kind = Single, "Casing is not a string");
3618
3619             declare
3620                Casing_Image : constant String :=
3621                                 Get_Name_String (Casing_String.Value);
3622
3623             begin
3624                if Casing_Image'Length = 0 then
3625                   Error_Msg
3626                     (Data.Flags,
3627                      "Casing cannot be an empty string",
3628                      Casing_String.Location, Project);
3629                end if;
3630
3631                Casing := Value (Casing_Image);
3632                Casing_Defined := True;
3633
3634             exception
3635                when Constraint_Error =>
3636                   Name_Len := Casing_Image'Length;
3637                   Name_Buffer (1 .. Name_Len) := Casing_Image;
3638                   Err_Vars.Error_Msg_Name_1 := Name_Find;
3639                   Error_Msg
3640                     (Data.Flags,
3641                      "%% is not a correct Casing",
3642                      Casing_String.Location, Project);
3643             end;
3644          end if;
3645
3646          Write_Attr ("Casing", Image (Casing));
3647
3648          if not Sep_Suffix.Default then
3649             if Length_Of_Name (Sep_Suffix.Value) = 0 then
3650                Error_Msg
3651                  (Data.Flags,
3652                   "Separate_Suffix cannot be empty",
3653                   Sep_Suffix.Location, Project);
3654
3655             else
3656                Separate_Suffix := Canonical_Case_File_Name (Sep_Suffix.Value);
3657                Sep_Suffix_Loc  := Sep_Suffix.Location;
3658
3659                Check_Illegal_Suffix
3660                  (Project, Separate_Suffix,
3661                   Dot_Replacement, "Separate_Suffix", Sep_Suffix.Location,
3662                   Data);
3663             end if;
3664          end if;
3665
3666          if Separate_Suffix /= No_File then
3667             Write_Attr
3668               ("Separate_Suffix", Get_Name_String (Separate_Suffix));
3669          end if;
3670       end Check_Common;
3671
3672       -----------------------------------
3673       -- Process_Exceptions_File_Based --
3674       -----------------------------------
3675
3676       procedure Process_Exceptions_File_Based
3677         (Lang_Id : Language_Ptr;
3678          Kind    : Source_Kind)
3679       is
3680          Lang           : constant Name_Id := Lang_Id.Name;
3681          Exceptions     : Array_Element_Id;
3682          Exception_List : Variable_Value;
3683          Element_Id     : String_List_Id;
3684          Element        : String_Element;
3685          File_Name      : File_Name_Type;
3686          Source         : Source_Id;
3687
3688       begin
3689          case Kind is
3690             when Impl | Sep =>
3691                Exceptions :=
3692                  Value_Of
3693                    (Name_Implementation_Exceptions,
3694                     In_Arrays => Naming.Decl.Arrays,
3695                     Shared    => Shared);
3696
3697             when Spec =>
3698                Exceptions :=
3699                  Value_Of
3700                    (Name_Specification_Exceptions,
3701                     In_Arrays => Naming.Decl.Arrays,
3702                     Shared    => Shared);
3703          end case;
3704
3705          Exception_List :=
3706            Value_Of
3707              (Index    => Lang,
3708               In_Array => Exceptions,
3709               Shared   => Shared);
3710
3711          if Exception_List /= Nil_Variable_Value then
3712             Element_Id := Exception_List.Values;
3713             while Element_Id /= Nil_String loop
3714                Element   := Shared.String_Elements.Table (Element_Id);
3715                File_Name := Canonical_Case_File_Name (Element.Value);
3716
3717                Source :=
3718                  Source_Files_Htable.Get
3719                    (Data.Tree.Source_Files_HT, File_Name);
3720                while Source /= No_Source
3721                  and then Source.Project /= Project
3722                loop
3723                   Source := Source.Next_With_File_Name;
3724                end loop;
3725
3726                if Source = No_Source then
3727                   Add_Source
3728                     (Id               => Source,
3729                      Data             => Data,
3730                      Project          => Project,
3731                      Source_Dir_Rank  => 0,
3732                      Lang_Id          => Lang_Id,
3733                      Kind             => Kind,
3734                      File_Name        => File_Name,
3735                      Display_File     => File_Name_Type (Element.Value),
3736                      Naming_Exception => Yes,
3737                      Location         => Element.Location);
3738
3739                else
3740                   --  Check if the file name is already recorded for another
3741                   --  language or another kind.
3742
3743                   if Source.Language /= Lang_Id then
3744                      Error_Msg
3745                        (Data.Flags,
3746                         "the same file cannot be a source of two languages",
3747                         Element.Location, Project);
3748
3749                   elsif Source.Kind /= Kind then
3750                      Error_Msg
3751                        (Data.Flags,
3752                         "the same file cannot be a source and a template",
3753                         Element.Location, Project);
3754                   end if;
3755
3756                   --  If the file is already recorded for the same
3757                   --  language and the same kind, it means that the file
3758                   --  name appears several times in the *_Exceptions
3759                   --  attribute; so there is nothing to do.
3760                end if;
3761
3762                Element_Id := Element.Next;
3763             end loop;
3764          end if;
3765       end Process_Exceptions_File_Based;
3766
3767       -----------------------------------
3768       -- Process_Exceptions_Unit_Based --
3769       -----------------------------------
3770
3771       procedure Process_Exceptions_Unit_Based
3772         (Lang_Id : Language_Ptr;
3773          Kind    : Source_Kind)
3774       is
3775          Exceptions : Array_Element_Id;
3776          Element    : Array_Element;
3777          Unit       : Name_Id;
3778          Index      : Int;
3779          File_Name  : File_Name_Type;
3780          Source     : Source_Id;
3781
3782          Naming_Exception : Naming_Exception_Type;
3783
3784       begin
3785          case Kind is
3786             when Impl | Sep =>
3787                Exceptions :=
3788                  Value_Of
3789                    (Name_Body,
3790                     In_Arrays => Naming.Decl.Arrays,
3791                     Shared    => Shared);
3792
3793                if Exceptions = No_Array_Element then
3794                   Exceptions :=
3795                     Value_Of
3796                       (Name_Implementation,
3797                        In_Arrays => Naming.Decl.Arrays,
3798                        Shared    => Shared);
3799                end if;
3800
3801             when Spec =>
3802                Exceptions :=
3803                  Value_Of
3804                    (Name_Spec,
3805                     In_Arrays => Naming.Decl.Arrays,
3806                     Shared    => Shared);
3807
3808                if Exceptions = No_Array_Element then
3809                   Exceptions :=
3810                     Value_Of
3811                       (Name_Specification,
3812                        In_Arrays => Naming.Decl.Arrays,
3813                        Shared    => Shared);
3814                end if;
3815          end case;
3816
3817          while Exceptions /= No_Array_Element loop
3818             Element   := Shared.Array_Elements.Table (Exceptions);
3819
3820             if Element.Restricted then
3821                Naming_Exception := Inherited;
3822             else
3823                Naming_Exception := Yes;
3824             end if;
3825
3826             File_Name := Canonical_Case_File_Name (Element.Value.Value);
3827
3828             Get_Name_String (Element.Index);
3829             To_Lower (Name_Buffer (1 .. Name_Len));
3830             Index := Element.Value.Index;
3831
3832             --  Check if it is a valid unit name
3833
3834             Get_Name_String (Element.Index);
3835             Check_Unit_Name (Name_Buffer (1 .. Name_Len), Unit);
3836
3837             if Unit = No_Name then
3838                Err_Vars.Error_Msg_Name_1 := Element.Index;
3839                Error_Msg
3840                  (Data.Flags,
3841                   "%% is not a valid unit name.",
3842                   Element.Value.Location, Project);
3843             end if;
3844
3845             if Unit /= No_Name then
3846                Add_Source
3847                  (Id               => Source,
3848                   Data             => Data,
3849                   Project          => Project,
3850                   Source_Dir_Rank  => 0,
3851                   Lang_Id          => Lang_Id,
3852                   Kind             => Kind,
3853                   File_Name        => File_Name,
3854                   Display_File     => File_Name_Type (Element.Value.Value),
3855                   Unit             => Unit,
3856                   Index            => Index,
3857                   Location         => Element.Value.Location,
3858                   Naming_Exception => Naming_Exception);
3859             end if;
3860
3861             Exceptions := Element.Next;
3862          end loop;
3863       end Process_Exceptions_Unit_Based;
3864
3865       ------------------
3866       -- Check_Naming --
3867       ------------------
3868
3869       procedure Check_Naming is
3870          Dot_Replacement : File_Name_Type :=
3871                              File_Name_Type
3872                                (First_Name_Id + Character'Pos ('-'));
3873          Separate_Suffix : File_Name_Type := No_File;
3874          Casing          : Casing_Type    := All_Lower_Case;
3875          Casing_Defined  : Boolean;
3876          Lang_Id         : Language_Ptr;
3877          Sep_Suffix_Loc  : Source_Ptr;
3878          Suffix          : Variable_Value;
3879          Lang            : Name_Id;
3880
3881       begin
3882          Check_Common
3883            (Dot_Replacement => Dot_Replacement,
3884             Casing          => Casing,
3885             Casing_Defined  => Casing_Defined,
3886             Separate_Suffix => Separate_Suffix,
3887             Sep_Suffix_Loc  => Sep_Suffix_Loc);
3888
3889          --  For all unit based languages, if any, set the specified value
3890          --  of Dot_Replacement, Casing and/or Separate_Suffix. Do not
3891          --  systematically overwrite, since the defaults come from the
3892          --  configuration file.
3893
3894          if Dot_Replacement /= No_File
3895            or else Casing_Defined
3896            or else Separate_Suffix /= No_File
3897          then
3898             Lang_Id := Project.Languages;
3899             while Lang_Id /= No_Language_Index loop
3900                if Lang_Id.Config.Kind = Unit_Based then
3901                   if Dot_Replacement /= No_File then
3902                      Lang_Id.Config.Naming_Data.Dot_Replacement :=
3903                          Dot_Replacement;
3904                   end if;
3905
3906                   if Casing_Defined then
3907                      Lang_Id.Config.Naming_Data.Casing := Casing;
3908                   end if;
3909                end if;
3910
3911                Lang_Id := Lang_Id.Next;
3912             end loop;
3913          end if;
3914
3915          --  Next, get the spec and body suffixes
3916
3917          Lang_Id := Project.Languages;
3918          while Lang_Id /= No_Language_Index loop
3919             Lang := Lang_Id.Name;
3920
3921             --  Spec_Suffix
3922
3923             Suffix := Value_Of
3924               (Name                    => Lang,
3925                Attribute_Or_Array_Name => Name_Spec_Suffix,
3926                In_Package              => Naming_Id,
3927                Shared                  => Shared);
3928
3929             if Suffix = Nil_Variable_Value then
3930                Suffix := Value_Of
3931                  (Name                    => Lang,
3932                   Attribute_Or_Array_Name => Name_Specification_Suffix,
3933                   In_Package              => Naming_Id,
3934                   Shared                  => Shared);
3935             end if;
3936
3937             if Suffix /= Nil_Variable_Value then
3938                Lang_Id.Config.Naming_Data.Spec_Suffix :=
3939                    File_Name_Type (Suffix.Value);
3940
3941                Check_Illegal_Suffix
3942                  (Project,
3943                   Lang_Id.Config.Naming_Data.Spec_Suffix,
3944                   Lang_Id.Config.Naming_Data.Dot_Replacement,
3945                   "Spec_Suffix", Suffix.Location, Data);
3946
3947                Write_Attr
3948                  ("Spec_Suffix",
3949                   Get_Name_String (Lang_Id.Config.Naming_Data.Spec_Suffix));
3950             end if;
3951
3952             --  Body_Suffix
3953
3954             Suffix :=
3955               Value_Of
3956                 (Name                    => Lang,
3957                  Attribute_Or_Array_Name => Name_Body_Suffix,
3958                  In_Package              => Naming_Id,
3959                  Shared                  => Shared);
3960
3961             if Suffix = Nil_Variable_Value then
3962                Suffix :=
3963                  Value_Of
3964                    (Name                    => Lang,
3965                     Attribute_Or_Array_Name => Name_Implementation_Suffix,
3966                     In_Package              => Naming_Id,
3967                     Shared                  => Shared);
3968             end if;
3969
3970             if Suffix /= Nil_Variable_Value then
3971                Lang_Id.Config.Naming_Data.Body_Suffix :=
3972                  File_Name_Type (Suffix.Value);
3973
3974                --  The default value of separate suffix should be the same as
3975                --  the body suffix, so we need to compute that first.
3976
3977                if Separate_Suffix = No_File then
3978                   Lang_Id.Config.Naming_Data.Separate_Suffix :=
3979                     Lang_Id.Config.Naming_Data.Body_Suffix;
3980                   Write_Attr
3981                     ("Sep_Suffix",
3982                      Get_Name_String
3983                        (Lang_Id.Config.Naming_Data.Separate_Suffix));
3984                else
3985                   Lang_Id.Config.Naming_Data.Separate_Suffix :=
3986                     Separate_Suffix;
3987                end if;
3988
3989                Check_Illegal_Suffix
3990                  (Project,
3991                   Lang_Id.Config.Naming_Data.Body_Suffix,
3992                   Lang_Id.Config.Naming_Data.Dot_Replacement,
3993                   "Body_Suffix", Suffix.Location, Data);
3994
3995                Write_Attr
3996                  ("Body_Suffix",
3997                   Get_Name_String (Lang_Id.Config.Naming_Data.Body_Suffix));
3998
3999             elsif Separate_Suffix /= No_File then
4000                Lang_Id.Config.Naming_Data.Separate_Suffix := Separate_Suffix;
4001             end if;
4002
4003             --  Spec_Suffix cannot be equal to Body_Suffix or Separate_Suffix,
4004             --  since that would cause a clear ambiguity. Note that we do allow
4005             --  a Spec_Suffix to have the same termination as one of these,
4006             --  which causes a potential ambiguity, but we resolve that by
4007             --  matching the longest possible suffix.
4008
4009             if Lang_Id.Config.Naming_Data.Spec_Suffix /= No_File
4010               and then Lang_Id.Config.Naming_Data.Spec_Suffix =
4011                        Lang_Id.Config.Naming_Data.Body_Suffix
4012             then
4013                Error_Msg
4014                  (Data.Flags,
4015                   "Body_Suffix ("""
4016                   & Get_Name_String (Lang_Id.Config.Naming_Data.Body_Suffix)
4017                   & """) cannot be the same as Spec_Suffix.",
4018                   Ada_Body_Suffix_Loc, Project);
4019             end if;
4020
4021             if Lang_Id.Config.Naming_Data.Body_Suffix /=
4022                Lang_Id.Config.Naming_Data.Separate_Suffix
4023               and then Lang_Id.Config.Naming_Data.Spec_Suffix =
4024                        Lang_Id.Config.Naming_Data.Separate_Suffix
4025             then
4026                Error_Msg
4027                  (Data.Flags,
4028                   "Separate_Suffix ("""
4029                   & Get_Name_String
4030                     (Lang_Id.Config.Naming_Data.Separate_Suffix)
4031                   & """) cannot be the same as Spec_Suffix.",
4032                   Sep_Suffix_Loc, Project);
4033             end if;
4034
4035             Lang_Id := Lang_Id.Next;
4036          end loop;
4037
4038          --  Get the naming exceptions for all languages
4039
4040          for Kind in Spec_Or_Body loop
4041             Lang_Id := Project.Languages;
4042             while Lang_Id /= No_Language_Index loop
4043                case Lang_Id.Config.Kind is
4044                   when File_Based =>
4045                      Process_Exceptions_File_Based (Lang_Id, Kind);
4046
4047                   when Unit_Based =>
4048                      Process_Exceptions_Unit_Based (Lang_Id, Kind);
4049                end case;
4050
4051                Lang_Id := Lang_Id.Next;
4052             end loop;
4053          end loop;
4054       end Check_Naming;
4055
4056       ----------------------------
4057       -- Initialize_Naming_Data --
4058       ----------------------------
4059
4060       procedure Initialize_Naming_Data is
4061          Specs : Array_Element_Id :=
4062                    Util.Value_Of
4063                      (Name_Spec_Suffix,
4064                       Naming.Decl.Arrays,
4065                       Shared);
4066
4067          Impls : Array_Element_Id :=
4068                    Util.Value_Of
4069                      (Name_Body_Suffix,
4070                       Naming.Decl.Arrays,
4071                       Shared);
4072
4073          Lang      : Language_Ptr;
4074          Lang_Name : Name_Id;
4075          Value     : Variable_Value;
4076          Extended  : Project_Id;
4077
4078       begin
4079          --  At this stage, the project already contains the default extensions
4080          --  for the various languages. We now merge those suffixes read in the
4081          --  user project, and they override the default.
4082
4083          while Specs /= No_Array_Element loop
4084             Lang_Name := Shared.Array_Elements.Table (Specs).Index;
4085             Lang :=
4086               Get_Language_From_Name
4087                 (Project, Name => Get_Name_String (Lang_Name));
4088
4089             --  An extending project inherits its parent projects' languages
4090             --  so if needed we should create entries for those languages
4091
4092             if Lang = null  then
4093                Extended := Project.Extends;
4094                while Extended /= null loop
4095                   Lang := Get_Language_From_Name
4096                     (Extended, Name => Get_Name_String (Lang_Name));
4097                   exit when Lang /= null;
4098
4099                   Extended := Extended.Extends;
4100                end loop;
4101
4102                if Lang /= null then
4103                   Lang := new Language_Data'(Lang.all);
4104                   Lang.First_Source := null;
4105                   Lang.Next := Project.Languages;
4106                   Project.Languages := Lang;
4107                end if;
4108             end if;
4109
4110             --  If language was not found in project or the projects it extends
4111
4112             if Lang = null then
4113                Debug_Output
4114                  ("ignoring spec naming data (lang. not in project): ",
4115                   Lang_Name);
4116
4117             else
4118                Value := Shared.Array_Elements.Table (Specs).Value;
4119
4120                if Value.Kind = Single then
4121                   Lang.Config.Naming_Data.Spec_Suffix :=
4122                     Canonical_Case_File_Name (Value.Value);
4123                end if;
4124             end if;
4125
4126             Specs := Shared.Array_Elements.Table (Specs).Next;
4127          end loop;
4128
4129          while Impls /= No_Array_Element loop
4130             Lang_Name := Shared.Array_Elements.Table (Impls).Index;
4131             Lang :=
4132               Get_Language_From_Name
4133                 (Project, Name => Get_Name_String (Lang_Name));
4134
4135             if Lang = null then
4136                Debug_Output
4137                  ("ignoring impl naming data (lang. not in project): ",
4138                   Lang_Name);
4139             else
4140                Value := Shared.Array_Elements.Table (Impls).Value;
4141
4142                if Lang.Name = Name_Ada then
4143                   Ada_Body_Suffix_Loc := Value.Location;
4144                end if;
4145
4146                if Value.Kind = Single then
4147                   Lang.Config.Naming_Data.Body_Suffix :=
4148                     Canonical_Case_File_Name (Value.Value);
4149                end if;
4150             end if;
4151
4152             Impls := Shared.Array_Elements.Table (Impls).Next;
4153          end loop;
4154       end Initialize_Naming_Data;
4155
4156    --  Start of processing for Check_Naming_Schemes
4157
4158    begin
4159       --  No Naming package or parsing a configuration file? nothing to do
4160
4161       if Naming_Id /= No_Package
4162         and then Project.Qualifier /= Configuration
4163       then
4164          Naming := Shared.Packages.Table (Naming_Id);
4165          Debug_Increase_Indent ("checking package Naming for ", Project.Name);
4166          Initialize_Naming_Data;
4167          Check_Naming;
4168          Debug_Decrease_Indent ("done checking package naming");
4169       end if;
4170    end Check_Package_Naming;
4171
4172    ---------------------------------
4173    -- Check_Programming_Languages --
4174    ---------------------------------
4175
4176    procedure Check_Programming_Languages
4177      (Project : Project_Id;
4178       Data    : in out Tree_Processing_Data)
4179    is
4180       Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
4181
4182       Languages   : Variable_Value := Nil_Variable_Value;
4183       Def_Lang    : Variable_Value := Nil_Variable_Value;
4184       Def_Lang_Id : Name_Id;
4185
4186       procedure Add_Language (Name, Display_Name : Name_Id);
4187       --  Add a new language to the list of languages for the project.
4188       --  Nothing is done if the language has already been defined
4189
4190       ------------------
4191       -- Add_Language --
4192       ------------------
4193
4194       procedure Add_Language (Name, Display_Name : Name_Id) is
4195          Lang : Language_Ptr;
4196
4197       begin
4198          Lang := Project.Languages;
4199          while Lang /= No_Language_Index loop
4200             if Name = Lang.Name then
4201                return;
4202             end if;
4203
4204             Lang := Lang.Next;
4205          end loop;
4206
4207          Lang              := new Language_Data'(No_Language_Data);
4208          Lang.Next         := Project.Languages;
4209          Project.Languages := Lang;
4210          Lang.Name         := Name;
4211          Lang.Display_Name := Display_Name;
4212       end Add_Language;
4213
4214    --  Start of processing for Check_Programming_Languages
4215
4216    begin
4217       Project.Languages := null;
4218       Languages :=
4219         Prj.Util.Value_Of (Name_Languages, Project.Decl.Attributes, Shared);
4220       Def_Lang :=
4221         Prj.Util.Value_Of
4222           (Name_Default_Language, Project.Decl.Attributes, Shared);
4223
4224       if Project.Source_Dirs /= Nil_String then
4225
4226          --  Check if languages are specified in this project
4227
4228          if Languages.Default then
4229
4230             --  Fail if there is no default language defined
4231
4232             if Def_Lang.Default then
4233                Error_Msg
4234                  (Data.Flags,
4235                   "no languages defined for this project",
4236                   Project.Location, Project);
4237                Def_Lang_Id := No_Name;
4238
4239             else
4240                Get_Name_String (Def_Lang.Value);
4241                To_Lower (Name_Buffer (1 .. Name_Len));
4242                Def_Lang_Id := Name_Find;
4243             end if;
4244
4245             if Def_Lang_Id /= No_Name then
4246                Get_Name_String (Def_Lang_Id);
4247                Name_Buffer (1) := GNAT.Case_Util.To_Upper (Name_Buffer (1));
4248                Add_Language
4249                  (Name         => Def_Lang_Id,
4250                   Display_Name => Name_Find);
4251             end if;
4252
4253          else
4254             declare
4255                Current : String_List_Id := Languages.Values;
4256                Element : String_Element;
4257
4258             begin
4259                --  If there are no languages declared, there are no sources
4260
4261                if Current = Nil_String then
4262                   Project.Source_Dirs := Nil_String;
4263
4264                   if Project.Qualifier = Standard then
4265                      Error_Msg
4266                        (Data.Flags,
4267                         "a standard project must have at least one language",
4268                         Languages.Location, Project);
4269                   end if;
4270
4271                else
4272                   --  Look through all the languages specified in attribute
4273                   --  Languages.
4274
4275                   while Current /= Nil_String loop
4276                      Element := Shared.String_Elements.Table (Current);
4277                      Get_Name_String (Element.Value);
4278                      To_Lower (Name_Buffer (1 .. Name_Len));
4279
4280                      Add_Language
4281                        (Name         => Name_Find,
4282                         Display_Name => Element.Value);
4283
4284                      Current := Element.Next;
4285                   end loop;
4286                end if;
4287             end;
4288          end if;
4289       end if;
4290    end Check_Programming_Languages;
4291
4292    -------------------------------
4293    -- Check_Stand_Alone_Library --
4294    -------------------------------
4295
4296    procedure Check_Stand_Alone_Library
4297      (Project : Project_Id;
4298       Data    : in out Tree_Processing_Data)
4299    is
4300       Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
4301
4302       Lib_Name            : constant Prj.Variable_Value :=
4303                               Prj.Util.Value_Of
4304                                (Snames.Name_Library_Name,
4305                                 Project.Decl.Attributes,
4306                                 Shared);
4307
4308       Lib_Interfaces      : constant Prj.Variable_Value :=
4309                               Prj.Util.Value_Of
4310                                 (Snames.Name_Library_Interface,
4311                                  Project.Decl.Attributes,
4312                                  Shared);
4313
4314       Lib_Auto_Init       : constant Prj.Variable_Value :=
4315                               Prj.Util.Value_Of
4316                                 (Snames.Name_Library_Auto_Init,
4317                                  Project.Decl.Attributes,
4318                                  Shared);
4319
4320       Lib_Src_Dir         : constant Prj.Variable_Value :=
4321                               Prj.Util.Value_Of
4322                                 (Snames.Name_Library_Src_Dir,
4323                                  Project.Decl.Attributes,
4324                                  Shared);
4325
4326       Lib_Symbol_File     : constant Prj.Variable_Value :=
4327                               Prj.Util.Value_Of
4328                                 (Snames.Name_Library_Symbol_File,
4329                                  Project.Decl.Attributes,
4330                                  Shared);
4331
4332       Lib_Symbol_Policy   : constant Prj.Variable_Value :=
4333                               Prj.Util.Value_Of
4334                                 (Snames.Name_Library_Symbol_Policy,
4335                                  Project.Decl.Attributes,
4336                                  Shared);
4337
4338       Lib_Ref_Symbol_File : constant Prj.Variable_Value :=
4339                               Prj.Util.Value_Of
4340                                 (Snames.Name_Library_Reference_Symbol_File,
4341                                  Project.Decl.Attributes,
4342                                  Shared);
4343
4344       Auto_Init_Supported : Boolean;
4345       OK                  : Boolean := True;
4346       Source              : Source_Id;
4347       Next_Proj           : Project_Id;
4348       Iter                : Source_Iterator;
4349
4350    begin
4351       Auto_Init_Supported := Project.Config.Auto_Init_Supported;
4352
4353       pragma Assert (Lib_Interfaces.Kind = List);
4354
4355       --  It is a stand-alone library project file if attribute
4356       --  Library_Interface is defined.
4357
4358       if not Lib_Interfaces.Default then
4359
4360          --  The name of a stand-alone library needs to have the syntax of an
4361          --  Ada identifier.
4362
4363          declare
4364             Name : constant String := Get_Name_String (Project.Library_Name);
4365             OK   : Boolean         := Is_Letter (Name (Name'First));
4366
4367             Underline : Boolean := False;
4368
4369          begin
4370             for J in Name'First + 1 .. Name'Last loop
4371                exit when not OK;
4372
4373                if Is_Alphanumeric (Name (J)) then
4374                   Underline := False;
4375
4376                elsif Name (J) = '_' then
4377                   if Underline then
4378                      OK := False;
4379                   else
4380                      Underline := True;
4381                   end if;
4382
4383                else
4384                   OK := False;
4385                end if;
4386             end loop;
4387
4388             OK := OK and not Underline;
4389
4390             if not OK then
4391                Error_Msg
4392                  (Data.Flags,
4393                   "Incorrect library name for a Stand-Alone Library",
4394                   Lib_Name.Location, Project);
4395                return;
4396             end if;
4397          end;
4398
4399          declare
4400             Interfaces     : String_List_Id := Lib_Interfaces.Values;
4401             Interface_ALIs : String_List_Id := Nil_String;
4402             Unit           : Name_Id;
4403
4404          begin
4405             Project.Standalone_Library := True;
4406
4407             --  Library_Interface cannot be an empty list
4408
4409             if Interfaces = Nil_String then
4410                Error_Msg
4411                  (Data.Flags,
4412                   "Library_Interface cannot be an empty list",
4413                   Lib_Interfaces.Location, Project);
4414             end if;
4415
4416             --  Process each unit name specified in the attribute
4417             --  Library_Interface.
4418
4419             while Interfaces /= Nil_String loop
4420                Get_Name_String
4421                  (Shared.String_Elements.Table (Interfaces).Value);
4422                To_Lower (Name_Buffer (1 .. Name_Len));
4423
4424                if Name_Len = 0 then
4425                   Error_Msg
4426                     (Data.Flags,
4427                      "an interface cannot be an empty string",
4428                      Shared.String_Elements.Table (Interfaces).Location,
4429                      Project);
4430
4431                else
4432                   Unit := Name_Find;
4433                   Error_Msg_Name_1 := Unit;
4434
4435                   Next_Proj := Project.Extends;
4436
4437                   if Project.Qualifier = Aggregate_Library then
4438
4439                      --  For an aggregate library we want to consider sources
4440                      --  of all aggregated projects.
4441
4442                      Iter := For_Each_Source (Data.Tree);
4443
4444                   else
4445                      Iter := For_Each_Source (Data.Tree, Project);
4446                   end if;
4447
4448                   loop
4449                      while Prj.Element (Iter) /= No_Source
4450                        and then
4451                          (Prj.Element (Iter).Unit = null
4452                            or else Prj.Element (Iter).Unit.Name /= Unit)
4453                      loop
4454                         Next (Iter);
4455                      end loop;
4456
4457                      Source := Prj.Element (Iter);
4458                      exit when Source /= No_Source
4459                        or else Next_Proj = No_Project;
4460
4461                      Iter := For_Each_Source (Data.Tree, Next_Proj);
4462                      Next_Proj := Next_Proj.Extends;
4463                   end loop;
4464
4465                   if Source /= No_Source then
4466                      if Source.Kind = Sep then
4467                         Source := No_Source;
4468
4469                      elsif Source.Kind = Spec
4470                        and then Other_Part (Source) /= No_Source
4471                      then
4472                         Source := Other_Part (Source);
4473                      end if;
4474                   end if;
4475
4476                   if Source /= No_Source then
4477                      if Source.Project /= Project
4478                        and then not Is_Extending (Project, Source.Project)
4479                        and then Project.Qualifier /= Aggregate_Library
4480                      then
4481                         Source := No_Source;
4482                      end if;
4483                   end if;
4484
4485                   if Source = No_Source then
4486                      Error_Msg
4487                        (Data.Flags,
4488                         "%% is not a unit of this project",
4489                         Shared.String_Elements.Table (Interfaces).Location,
4490                         Project);
4491
4492                   else
4493                      if Source.Kind = Spec
4494                        and then Other_Part (Source) /= No_Source
4495                      then
4496                         Source := Other_Part (Source);
4497                      end if;
4498
4499                      String_Element_Table.Increment_Last
4500                        (Shared.String_Elements);
4501
4502                      Shared.String_Elements.Table
4503                        (String_Element_Table.Last (Shared.String_Elements)) :=
4504                          (Value         => Name_Id (Source.Dep_Name),
4505                           Index         => 0,
4506                           Display_Value => Name_Id (Source.Dep_Name),
4507                           Location      =>
4508                             Shared.String_Elements.Table (Interfaces).Location,
4509                           Flag          => False,
4510                           Next          => Interface_ALIs);
4511
4512                      Interface_ALIs :=
4513                        String_Element_Table.Last (Shared.String_Elements);
4514                   end if;
4515                end if;
4516
4517                Interfaces := Shared.String_Elements.Table (Interfaces).Next;
4518             end loop;
4519
4520             --  Put the list of Interface ALIs in the project data
4521
4522             Project.Lib_Interface_ALIs := Interface_ALIs;
4523
4524             --  Check value of attribute Library_Auto_Init and set
4525             --  Lib_Auto_Init accordingly.
4526
4527             if Lib_Auto_Init.Default then
4528
4529                --  If no attribute Library_Auto_Init is declared, then set auto
4530                --  init only if it is supported.
4531
4532                Project.Lib_Auto_Init := Auto_Init_Supported;
4533
4534             else
4535                Get_Name_String (Lib_Auto_Init.Value);
4536                To_Lower (Name_Buffer (1 .. Name_Len));
4537
4538                if Name_Buffer (1 .. Name_Len) = "false" then
4539                   Project.Lib_Auto_Init := False;
4540
4541                elsif Name_Buffer (1 .. Name_Len) = "true" then
4542                   if Auto_Init_Supported then
4543                      Project.Lib_Auto_Init := True;
4544
4545                   else
4546                      --  Library_Auto_Init cannot be "true" if auto init is not
4547                      --  supported.
4548
4549                      Error_Msg
4550                        (Data.Flags,
4551                         "library auto init not supported " &
4552                         "on this platform",
4553                         Lib_Auto_Init.Location, Project);
4554                   end if;
4555
4556                else
4557                   Error_Msg
4558                     (Data.Flags,
4559                      "invalid value for attribute Library_Auto_Init",
4560                      Lib_Auto_Init.Location, Project);
4561                end if;
4562             end if;
4563          end;
4564
4565          --  If attribute Library_Src_Dir is defined and not the empty string,
4566          --  check if the directory exist and is not the object directory or
4567          --  one of the source directories. This is the directory where copies
4568          --  of the interface sources will be copied. Note that this directory
4569          --  may be the library directory.
4570
4571          if Lib_Src_Dir.Value /= Empty_String then
4572             declare
4573                Dir_Id     : constant File_Name_Type :=
4574                               File_Name_Type (Lib_Src_Dir.Value);
4575                Dir_Exists : Boolean;
4576
4577             begin
4578                Locate_Directory
4579                  (Project,
4580                   Dir_Id,
4581                   Path             => Project.Library_Src_Dir,
4582                   Dir_Exists       => Dir_Exists,
4583                   Data             => Data,
4584                   Must_Exist       => False,
4585                   Create           => "library source copy",
4586                   Location         => Lib_Src_Dir.Location,
4587                   Externally_Built => Project.Externally_Built);
4588
4589                --  If directory does not exist, report an error
4590
4591                if not Dir_Exists then
4592
4593                   --  Get the absolute name of the library directory that does
4594                   --  not exist, to report an error.
4595
4596                   Err_Vars.Error_Msg_File_1 :=
4597                     File_Name_Type (Project.Library_Src_Dir.Display_Name);
4598                   Error_Msg
4599                     (Data.Flags,
4600                      "Directory { does not exist",
4601                      Lib_Src_Dir.Location, Project);
4602
4603                   --  Report error if it is the same as the object directory
4604
4605                elsif Project.Library_Src_Dir = Project.Object_Directory then
4606                   Error_Msg
4607                     (Data.Flags,
4608                      "directory to copy interfaces cannot be " &
4609                      "the object directory",
4610                      Lib_Src_Dir.Location, Project);
4611                   Project.Library_Src_Dir := No_Path_Information;
4612
4613                else
4614                   declare
4615                      Src_Dirs : String_List_Id;
4616                      Src_Dir  : String_Element;
4617                      Pid      : Project_List;
4618
4619                   begin
4620                      --  Interface copy directory cannot be one of the source
4621                      --  directory of the current project.
4622
4623                      Src_Dirs := Project.Source_Dirs;
4624                      while Src_Dirs /= Nil_String loop
4625                         Src_Dir := Shared.String_Elements.Table (Src_Dirs);
4626
4627                         --  Report error if it is one of the source directories
4628
4629                         if Project.Library_Src_Dir.Name =
4630                              Path_Name_Type (Src_Dir.Value)
4631                         then
4632                            Error_Msg
4633                              (Data.Flags,
4634                               "directory to copy interfaces cannot " &
4635                               "be one of the source directories",
4636                               Lib_Src_Dir.Location, Project);
4637                            Project.Library_Src_Dir := No_Path_Information;
4638                            exit;
4639                         end if;
4640
4641                         Src_Dirs := Src_Dir.Next;
4642                      end loop;
4643
4644                      if Project.Library_Src_Dir /= No_Path_Information then
4645
4646                         --  It cannot be a source directory of any other
4647                         --  project either.
4648
4649                         Pid := Data.Tree.Projects;
4650                         Project_Loop : loop
4651                            exit Project_Loop when Pid = null;
4652
4653                            Src_Dirs := Pid.Project.Source_Dirs;
4654                            Dir_Loop : while Src_Dirs /= Nil_String loop
4655                               Src_Dir :=
4656                                 Shared.String_Elements.Table (Src_Dirs);
4657
4658                               --  Report error if it is one of the source
4659                               --  directories.
4660
4661                               if Project.Library_Src_Dir.Name =
4662                                 Path_Name_Type (Src_Dir.Value)
4663                               then
4664                                  Error_Msg_File_1 :=
4665                                    File_Name_Type (Src_Dir.Value);
4666                                  Error_Msg_Name_1 := Pid.Project.Name;
4667                                  Error_Msg
4668                                    (Data.Flags,
4669                                     "directory to copy interfaces cannot " &
4670                                     "be the same as source directory { of " &
4671                                     "project %%",
4672                                     Lib_Src_Dir.Location, Project);
4673                                  Project.Library_Src_Dir :=
4674                                    No_Path_Information;
4675                                  exit Project_Loop;
4676                               end if;
4677
4678                               Src_Dirs := Src_Dir.Next;
4679                            end loop Dir_Loop;
4680
4681                            Pid := Pid.Next;
4682                         end loop Project_Loop;
4683                      end if;
4684                   end;
4685
4686                   --  In high verbosity, if there is a valid Library_Src_Dir,
4687                   --  display its path name.
4688
4689                   if Project.Library_Src_Dir /= No_Path_Information
4690                     and then Current_Verbosity = High
4691                   then
4692                      Write_Attr
4693                        ("Directory to copy interfaces",
4694                         Get_Name_String (Project.Library_Src_Dir.Name));
4695                   end if;
4696                end if;
4697             end;
4698          end if;
4699
4700          --  Check the symbol related attributes
4701
4702          --  First, the symbol policy
4703
4704          if not Lib_Symbol_Policy.Default then
4705             declare
4706                Value : constant String :=
4707                          To_Lower
4708                            (Get_Name_String (Lib_Symbol_Policy.Value));
4709
4710             begin
4711                --  Symbol policy must hove one of a limited number of values
4712
4713                if Value = "autonomous" or else Value = "default" then
4714                   Project.Symbol_Data.Symbol_Policy := Autonomous;
4715
4716                elsif Value = "compliant" then
4717                   Project.Symbol_Data.Symbol_Policy := Compliant;
4718
4719                elsif Value = "controlled" then
4720                   Project.Symbol_Data.Symbol_Policy := Controlled;
4721
4722                elsif Value = "restricted" then
4723                   Project.Symbol_Data.Symbol_Policy := Restricted;
4724
4725                elsif Value = "direct" then
4726                   Project.Symbol_Data.Symbol_Policy := Direct;
4727
4728                else
4729                   Error_Msg
4730                     (Data.Flags,
4731                      "illegal value for Library_Symbol_Policy",
4732                      Lib_Symbol_Policy.Location, Project);
4733                end if;
4734             end;
4735          end if;
4736
4737          --  If attribute Library_Symbol_File is not specified, symbol policy
4738          --  cannot be Restricted.
4739
4740          if Lib_Symbol_File.Default then
4741             if Project.Symbol_Data.Symbol_Policy = Restricted then
4742                Error_Msg
4743                  (Data.Flags,
4744                   "Library_Symbol_File needs to be defined when " &
4745                   "symbol policy is Restricted",
4746                   Lib_Symbol_Policy.Location, Project);
4747             end if;
4748
4749          else
4750             --  Library_Symbol_File is defined
4751
4752             Project.Symbol_Data.Symbol_File :=
4753               Path_Name_Type (Lib_Symbol_File.Value);
4754
4755             Get_Name_String (Lib_Symbol_File.Value);
4756
4757             if Name_Len = 0 then
4758                Error_Msg
4759                  (Data.Flags,
4760                   "symbol file name cannot be an empty string",
4761                   Lib_Symbol_File.Location, Project);
4762
4763             else
4764                OK := not Is_Absolute_Path (Name_Buffer (1 .. Name_Len));
4765
4766                if OK then
4767                   for J in 1 .. Name_Len loop
4768                      if Name_Buffer (J) = '/'
4769                        or else Name_Buffer (J) = Directory_Separator
4770                      then
4771                         OK := False;
4772                         exit;
4773                      end if;
4774                   end loop;
4775                end if;
4776
4777                if not OK then
4778                   Error_Msg_File_1 := File_Name_Type (Lib_Symbol_File.Value);
4779                   Error_Msg
4780                     (Data.Flags,
4781                      "symbol file name { is illegal. " &
4782                      "Name cannot include directory info.",
4783                      Lib_Symbol_File.Location, Project);
4784                end if;
4785             end if;
4786          end if;
4787
4788          --  If attribute Library_Reference_Symbol_File is not defined,
4789          --  symbol policy cannot be Compliant or Controlled.
4790
4791          if Lib_Ref_Symbol_File.Default then
4792             if Project.Symbol_Data.Symbol_Policy = Compliant
4793               or else Project.Symbol_Data.Symbol_Policy = Controlled
4794             then
4795                Error_Msg
4796                  (Data.Flags,
4797                   "a reference symbol file needs to be defined",
4798                   Lib_Symbol_Policy.Location, Project);
4799             end if;
4800
4801          else
4802             --  Library_Reference_Symbol_File is defined, check file exists
4803
4804             Project.Symbol_Data.Reference :=
4805               Path_Name_Type (Lib_Ref_Symbol_File.Value);
4806
4807             Get_Name_String (Lib_Ref_Symbol_File.Value);
4808
4809             if Name_Len = 0 then
4810                Error_Msg
4811                  (Data.Flags,
4812                   "reference symbol file name cannot be an empty string",
4813                   Lib_Symbol_File.Location, Project);
4814
4815             else
4816                if not Is_Absolute_Path (Name_Buffer (1 .. Name_Len)) then
4817                   Name_Len := 0;
4818                   Add_Str_To_Name_Buffer
4819                     (Get_Name_String (Project.Directory.Name));
4820                   Add_Str_To_Name_Buffer
4821                     (Get_Name_String (Lib_Ref_Symbol_File.Value));
4822                   Project.Symbol_Data.Reference := Name_Find;
4823                end if;
4824
4825                if not Is_Regular_File
4826                         (Get_Name_String (Project.Symbol_Data.Reference))
4827                then
4828                   Error_Msg_File_1 :=
4829                     File_Name_Type (Lib_Ref_Symbol_File.Value);
4830
4831                   --  For controlled and direct symbol policies, it is an error
4832                   --  if the reference symbol file does not exist. For other
4833                   --  symbol policies, this is just a warning
4834
4835                   Error_Msg_Warn :=
4836                     Project.Symbol_Data.Symbol_Policy /= Controlled
4837                     and then Project.Symbol_Data.Symbol_Policy /= Direct;
4838
4839                   Error_Msg
4840                     (Data.Flags,
4841                      "<library reference symbol file { does not exist",
4842                      Lib_Ref_Symbol_File.Location, Project);
4843
4844                   --  In addition in the non-controlled case, if symbol policy
4845                   --  is Compliant, it is changed to Autonomous, because there
4846                   --  is no reference to check against, and we don't want to
4847                   --  fail in this case.
4848
4849                   if Project.Symbol_Data.Symbol_Policy /= Controlled then
4850                      if Project.Symbol_Data.Symbol_Policy = Compliant then
4851                         Project.Symbol_Data.Symbol_Policy := Autonomous;
4852                      end if;
4853                   end if;
4854                end if;
4855
4856                --  If both the reference symbol file and the symbol file are
4857                --  defined, then check that they are not the same file.
4858
4859                if Project.Symbol_Data.Symbol_File /= No_Path then
4860                   Get_Name_String (Project.Symbol_Data.Symbol_File);
4861
4862                   if Name_Len > 0 then
4863                      declare
4864                         --  We do not need to pass a Directory to
4865                         --  Normalize_Pathname, since the path_information
4866                         --  already contains absolute information.
4867
4868                         Symb_Path : constant String :=
4869                                       Normalize_Pathname
4870                                         (Get_Name_String
4871                                            (Project.Object_Directory.Name) &
4872                                          Name_Buffer (1 .. Name_Len),
4873                                          Directory     => "/",
4874                                          Resolve_Links =>
4875                                            Opt.Follow_Links_For_Files);
4876                         Ref_Path  : constant String :=
4877                                       Normalize_Pathname
4878                                         (Get_Name_String
4879                                            (Project.Symbol_Data.Reference),
4880                                          Directory     => "/",
4881                                          Resolve_Links =>
4882                                            Opt.Follow_Links_For_Files);
4883                      begin
4884                         if Symb_Path = Ref_Path then
4885                            Error_Msg
4886                              (Data.Flags,
4887                               "library reference symbol file and library" &
4888                               " symbol file cannot be the same file",
4889                               Lib_Ref_Symbol_File.Location, Project);
4890                         end if;
4891                      end;
4892                   end if;
4893                end if;
4894             end if;
4895          end if;
4896       end if;
4897    end Check_Stand_Alone_Library;
4898
4899    ---------------------
4900    -- Check_Unit_Name --
4901    ---------------------
4902
4903    procedure Check_Unit_Name (Name : String; Unit : out Name_Id) is
4904       The_Name        : String := Name;
4905       Real_Name       : Name_Id;
4906       Need_Letter     : Boolean := True;
4907       Last_Underscore : Boolean := False;
4908       OK              : Boolean := The_Name'Length > 0;
4909       First           : Positive;
4910
4911       function Is_Reserved (Name : Name_Id) return Boolean;
4912       function Is_Reserved (S    : String)  return Boolean;
4913       --  Check that the given name is not an Ada 95 reserved word. The reason
4914       --  for the Ada 95 here is that we do not want to exclude the case of an
4915       --  Ada 95 unit called Interface (for example). In Ada 2005, such a unit
4916       --  name would be rejected anyway by the compiler. That means there is no
4917       --  requirement that the project file parser reject this.
4918
4919       -----------------
4920       -- Is_Reserved --
4921       -----------------
4922
4923       function Is_Reserved (S : String) return Boolean is
4924       begin
4925          Name_Len := 0;
4926          Add_Str_To_Name_Buffer (S);
4927          return Is_Reserved (Name_Find);
4928       end Is_Reserved;
4929
4930       -----------------
4931       -- Is_Reserved --
4932       -----------------
4933
4934       function Is_Reserved (Name : Name_Id) return Boolean is
4935       begin
4936          if Get_Name_Table_Byte (Name) /= 0
4937            and then Name /= Name_Project
4938            and then Name /= Name_Extends
4939            and then Name /= Name_External
4940            and then Name not in Ada_2005_Reserved_Words
4941          then
4942             Unit := No_Name;
4943             Debug_Output ("Ada reserved word: ", Name);
4944             return True;
4945
4946          else
4947             return False;
4948          end if;
4949       end Is_Reserved;
4950
4951    --  Start of processing for Check_Unit_Name
4952
4953    begin
4954       To_Lower (The_Name);
4955
4956       Name_Len := The_Name'Length;
4957       Name_Buffer (1 .. Name_Len) := The_Name;
4958
4959       --  Special cases of children of packages A, G, I and S on VMS
4960
4961       if OpenVMS_On_Target
4962         and then Name_Len > 3
4963         and then Name_Buffer (2 .. 3) = "__"
4964         and then
4965           (Name_Buffer (1) = 'a' or else
4966            Name_Buffer (1) = 'g' or else
4967            Name_Buffer (1) = 'i' or else
4968            Name_Buffer (1) = 's')
4969       then
4970          Name_Buffer (2) := '.';
4971          Name_Buffer (3 .. Name_Len - 1) := Name_Buffer (4 .. Name_Len);
4972          Name_Len := Name_Len - 1;
4973       end if;
4974
4975       Real_Name := Name_Find;
4976
4977       if Is_Reserved (Real_Name) then
4978          return;
4979       end if;
4980
4981       First := The_Name'First;
4982
4983       for Index in The_Name'Range loop
4984          if Need_Letter then
4985
4986             --  We need a letter (at the beginning, and following a dot),
4987             --  but we don't have one.
4988
4989             if Is_Letter (The_Name (Index)) then
4990                Need_Letter := False;
4991
4992             else
4993                OK := False;
4994
4995                if Current_Verbosity = High then
4996                   Debug_Indent;
4997                   Write_Int  (Types.Int (Index));
4998                   Write_Str  (": '");
4999                   Write_Char (The_Name (Index));
5000                   Write_Line ("' is not a letter.");
5001                end if;
5002
5003                exit;
5004             end if;
5005
5006          elsif Last_Underscore
5007            and then (The_Name (Index) = '_' or else The_Name (Index) = '.')
5008          then
5009             --  Two underscores are illegal, and a dot cannot follow
5010             --  an underscore.
5011
5012             OK := False;
5013
5014             if Current_Verbosity = High then
5015                Debug_Indent;
5016                Write_Int  (Types.Int (Index));
5017                Write_Str  (": '");
5018                Write_Char (The_Name (Index));
5019                Write_Line ("' is illegal here.");
5020             end if;
5021
5022             exit;
5023
5024          elsif The_Name (Index) = '.' then
5025
5026             --  First, check if the name before the dot is not a reserved word
5027
5028             if Is_Reserved (The_Name (First .. Index - 1)) then
5029                return;
5030             end if;
5031
5032             First := Index + 1;
5033
5034             --  We need a letter after a dot
5035
5036             Need_Letter := True;
5037
5038          elsif The_Name (Index) = '_' then
5039             Last_Underscore := True;
5040
5041          else
5042             --  We need an letter or a digit
5043
5044             Last_Underscore := False;
5045
5046             if not Is_Alphanumeric (The_Name (Index)) then
5047                OK := False;
5048
5049                if Current_Verbosity = High then
5050                   Debug_Indent;
5051                   Write_Int  (Types.Int (Index));
5052                   Write_Str  (": '");
5053                   Write_Char (The_Name (Index));
5054                   Write_Line ("' is not alphanumeric.");
5055                end if;
5056
5057                exit;
5058             end if;
5059          end if;
5060       end loop;
5061
5062       --  Cannot end with an underscore or a dot
5063
5064       OK := OK and then not Need_Letter and then not Last_Underscore;
5065
5066       if OK then
5067          if First /= Name'First
5068            and then Is_Reserved (The_Name (First .. The_Name'Last))
5069          then
5070             return;
5071          end if;
5072
5073          Unit := Real_Name;
5074
5075       else
5076          --  Signal a problem with No_Name
5077
5078          Unit := No_Name;
5079       end if;
5080    end Check_Unit_Name;
5081
5082    ----------------------------
5083    -- Compute_Directory_Last --
5084    ----------------------------
5085
5086    function Compute_Directory_Last (Dir : String) return Natural is
5087    begin
5088       if Dir'Length > 1
5089         and then (Dir (Dir'Last - 1) = Directory_Separator
5090                     or else
5091                   Dir (Dir'Last - 1) = '/')
5092       then
5093          return Dir'Last - 1;
5094       else
5095          return Dir'Last;
5096       end if;
5097    end Compute_Directory_Last;
5098
5099    ---------------------
5100    -- Get_Directories --
5101    ---------------------
5102
5103    procedure Get_Directories
5104      (Project : Project_Id;
5105       Data    : in out Tree_Processing_Data)
5106    is
5107       Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared;
5108
5109       Object_Dir  : constant Variable_Value :=
5110                       Util.Value_Of
5111                         (Name_Object_Dir, Project.Decl.Attributes, Shared);
5112
5113       Exec_Dir : constant Variable_Value :=
5114                    Util.Value_Of
5115                      (Name_Exec_Dir, Project.Decl.Attributes, Shared);
5116
5117       Source_Dirs : constant Variable_Value :=
5118                       Util.Value_Of
5119                         (Name_Source_Dirs, Project.Decl.Attributes, Shared);
5120
5121       Ignore_Source_Sub_Dirs : constant Variable_Value :=
5122                                  Util.Value_Of
5123                                    (Name_Ignore_Source_Sub_Dirs,
5124                                     Project.Decl.Attributes,
5125                                     Shared);
5126
5127       Excluded_Source_Dirs : constant Variable_Value :=
5128                               Util.Value_Of
5129                                 (Name_Excluded_Source_Dirs,
5130                                  Project.Decl.Attributes,
5131                                  Shared);
5132
5133       Source_Files : constant Variable_Value :=
5134                       Util.Value_Of
5135                         (Name_Source_Files,
5136                          Project.Decl.Attributes, Shared);
5137
5138       Last_Source_Dir   : String_List_Id    := Nil_String;
5139       Last_Src_Dir_Rank : Number_List_Index := No_Number_List;
5140
5141       Languages : constant Variable_Value :=
5142                       Prj.Util.Value_Of
5143                         (Name_Languages, Project.Decl.Attributes, Shared);
5144
5145       Remove_Source_Dirs : Boolean := False;
5146
5147       procedure Add_To_Or_Remove_From_Source_Dirs
5148         (Path : Path_Information;
5149          Rank : Natural);
5150       --  When Removed = False, the directory Path_Id to the list of
5151       --  source_dirs if not already in the list. When Removed = True,
5152       --  removed directory Path_Id if in the list.
5153
5154       procedure Find_Source_Dirs is new Expand_Subdirectory_Pattern
5155         (Add_To_Or_Remove_From_Source_Dirs);
5156
5157       ---------------------------------------
5158       -- Add_To_Or_Remove_From_Source_Dirs --
5159       ---------------------------------------
5160
5161       procedure Add_To_Or_Remove_From_Source_Dirs
5162         (Path : Path_Information;
5163          Rank : Natural)
5164       is
5165          List      : String_List_Id;
5166          Prev      : String_List_Id;
5167          Rank_List : Number_List_Index;
5168          Prev_Rank : Number_List_Index;
5169          Element   : String_Element;
5170
5171       begin
5172          Prev      := Nil_String;
5173          Prev_Rank := No_Number_List;
5174          List      := Project.Source_Dirs;
5175          Rank_List := Project.Source_Dir_Ranks;
5176          while List /= Nil_String loop
5177             Element := Shared.String_Elements.Table (List);
5178             exit when Element.Value = Name_Id (Path.Name);
5179             Prev := List;
5180             List := Element.Next;
5181             Prev_Rank := Rank_List;
5182             Rank_List := Shared.Number_Lists.Table (Prev_Rank).Next;
5183          end loop;
5184
5185          --  The directory is in the list if List is not Nil_String
5186
5187          if not Remove_Source_Dirs and then List = Nil_String then
5188             Debug_Output ("adding source dir=", Name_Id (Path.Display_Name));
5189
5190             String_Element_Table.Increment_Last (Shared.String_Elements);
5191             Element :=
5192               (Value         => Name_Id (Path.Name),
5193                Index         => 0,
5194                Display_Value => Name_Id (Path.Display_Name),
5195                Location      => No_Location,
5196                Flag          => False,
5197                Next          => Nil_String);
5198
5199             Number_List_Table.Increment_Last (Shared.Number_Lists);
5200
5201             if Last_Source_Dir = Nil_String then
5202
5203                --  This is the first source directory
5204
5205                Project.Source_Dirs :=
5206                  String_Element_Table.Last (Shared.String_Elements);
5207                Project.Source_Dir_Ranks :=
5208                  Number_List_Table.Last (Shared.Number_Lists);
5209
5210             else
5211                --  We already have source directories, link the previous
5212                --  last to the new one.
5213
5214                Shared.String_Elements.Table (Last_Source_Dir).Next :=
5215                  String_Element_Table.Last (Shared.String_Elements);
5216                Shared.Number_Lists.Table (Last_Src_Dir_Rank).Next :=
5217                  Number_List_Table.Last (Shared.Number_Lists);
5218             end if;
5219
5220             --  And register this source directory as the new last
5221
5222             Last_Source_Dir :=
5223               String_Element_Table.Last (Shared.String_Elements);
5224             Shared.String_Elements.Table (Last_Source_Dir) := Element;
5225             Last_Src_Dir_Rank := Number_List_Table.Last (Shared.Number_Lists);
5226             Shared.Number_Lists.Table (Last_Src_Dir_Rank) :=
5227               (Number => Rank, Next => No_Number_List);
5228
5229          elsif Remove_Source_Dirs and then List /= Nil_String then
5230
5231             --  Remove source dir if present
5232
5233             if Prev = Nil_String then
5234                Project.Source_Dirs := Shared.String_Elements.Table (List).Next;
5235                Project.Source_Dir_Ranks :=
5236                  Shared.Number_Lists.Table (Rank_List).Next;
5237
5238             else
5239                Shared.String_Elements.Table (Prev).Next :=
5240                  Shared.String_Elements.Table (List).Next;
5241                Shared.Number_Lists.Table (Prev_Rank).Next :=
5242                  Shared.Number_Lists.Table (Rank_List).Next;
5243             end if;
5244          end if;
5245       end Add_To_Or_Remove_From_Source_Dirs;
5246
5247       --  Local declarations
5248
5249       Dir_Exists : Boolean;
5250
5251       No_Sources : constant Boolean :=
5252                      ((not Source_Files.Default
5253                         and then Source_Files.Values = Nil_String)
5254                       or else
5255                         (not Source_Dirs.Default
5256                           and then Source_Dirs.Values = Nil_String)
5257                       or else
5258                         (not Languages.Default
5259                           and then Languages.Values = Nil_String))
5260                      and then Project.Extends = No_Project;
5261
5262    --  Start of processing for Get_Directories
5263
5264    begin
5265       Debug_Output ("starting to look for directories");
5266
5267       --  Set the object directory to its default which may be nil, if there
5268       --  is no sources in the project.
5269
5270       if No_Sources then
5271          Project.Object_Directory := No_Path_Information;
5272       else
5273          Project.Object_Directory := Project.Directory;
5274       end if;
5275
5276       --  Check the object directory
5277
5278       if Object_Dir.Value /= Empty_String then
5279          Get_Name_String (Object_Dir.Value);
5280
5281          if Name_Len = 0 then
5282             Error_Msg
5283               (Data.Flags,
5284                "Object_Dir cannot be empty",
5285                Object_Dir.Location, Project);
5286
5287          elsif not No_Sources then
5288
5289             --  We check that the specified object directory does exist.
5290             --  However, even when it doesn't exist, we set it to a default
5291             --  value. This is for the benefit of tools that recover from
5292             --  errors; for example, these tools could create the non existent
5293             --  directory. We always return an absolute directory name though.
5294
5295             Locate_Directory
5296               (Project,
5297                File_Name_Type (Object_Dir.Value),
5298                Path             => Project.Object_Directory,
5299                Create           => "object",
5300                Dir_Exists       => Dir_Exists,
5301                Data             => Data,
5302                Location         => Object_Dir.Location,
5303                Must_Exist       => False,
5304                Externally_Built => Project.Externally_Built);
5305
5306             if not Dir_Exists and then not Project.Externally_Built then
5307
5308                --  The object directory does not exist, report an error if the
5309                --  project is not externally built.
5310
5311                Err_Vars.Error_Msg_File_1 :=
5312                  File_Name_Type (Object_Dir.Value);
5313                Error_Or_Warning
5314                  (Data.Flags, Data.Flags.Require_Obj_Dirs,
5315                   "object directory { not found", Project.Location, Project);
5316             end if;
5317          end if;
5318
5319       elsif not No_Sources and then Subdirs /= null then
5320          Name_Len := 1;
5321          Name_Buffer (1) := '.';
5322          Locate_Directory
5323            (Project,
5324             Name_Find,
5325             Path             => Project.Object_Directory,
5326             Create           => "object",
5327             Dir_Exists       => Dir_Exists,
5328             Data             => Data,
5329             Location         => Object_Dir.Location,
5330             Externally_Built => Project.Externally_Built);
5331       end if;
5332
5333       if Current_Verbosity = High then
5334          if Project.Object_Directory = No_Path_Information then
5335             Debug_Output ("no object directory");
5336          else
5337             Write_Attr
5338               ("Object directory",
5339                Get_Name_String (Project.Object_Directory.Display_Name));
5340          end if;
5341       end if;
5342
5343       --  Check the exec directory
5344
5345       --  We set the object directory to its default
5346
5347       Project.Exec_Directory := Project.Object_Directory;
5348
5349       if Exec_Dir.Value /= Empty_String then
5350          Get_Name_String (Exec_Dir.Value);
5351
5352          if Name_Len = 0 then
5353             Error_Msg
5354               (Data.Flags,
5355                "Exec_Dir cannot be empty",
5356                Exec_Dir.Location, Project);
5357
5358          elsif not No_Sources then
5359
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       procedure Recursive_Check
8147         (Project  : Project_Id;
8148          Prj_Tree : Project_Tree_Ref;
8149          Data     : in out Tree_Processing_Data);
8150       --  Check_Naming_Scheme for the project
8151
8152       ---------------------
8153       -- Recursive_Check --
8154       ---------------------
8155
8156       procedure Recursive_Check
8157         (Project  : Project_Id;
8158          Prj_Tree : Project_Tree_Ref;
8159          Data     : in out Tree_Processing_Data) is
8160       begin
8161          if Current_Verbosity = High then
8162             Debug_Increase_Indent
8163               ("Processing_Naming_Scheme for project", Project.Name);
8164          end if;
8165
8166          Data.Tree := Prj_Tree;
8167          Prj.Nmsc.Check (Project, Data);
8168
8169          if Current_Verbosity = High then
8170             Debug_Decrease_Indent ("done Processing_Naming_Scheme");
8171          end if;
8172       end Recursive_Check;
8173
8174       procedure Check_All_Projects is new
8175         For_Every_Project_Imported (Tree_Processing_Data, Recursive_Check);
8176
8177       Data : Tree_Processing_Data;
8178
8179    --  Start of processing for Process_Naming_Scheme
8180    begin
8181       Lib_Data_Table.Init;
8182       Initialize (Data, Tree => Tree, Node_Tree => Node_Tree, Flags => Flags);
8183       Check_All_Projects (Root_Project, Tree, Data, Imported_First => True);
8184       Free (Data);
8185
8186       --  Adjust language configs for projects that are extended
8187
8188       declare
8189          List : Project_List;
8190          Proj : Project_Id;
8191          Exte : Project_Id;
8192          Lang : Language_Ptr;
8193          Elng : Language_Ptr;
8194
8195       begin
8196          List := Tree.Projects;
8197          while List /= null loop
8198             Proj := List.Project;
8199             Exte := Proj;
8200             while Exte.Extended_By /= No_Project loop
8201                Exte := Exte.Extended_By;
8202             end loop;
8203
8204             if Exte /= Proj then
8205                Lang := Proj.Languages;
8206
8207                if Lang /= No_Language_Index then
8208                   loop
8209                      Elng := Get_Language_From_Name
8210                        (Exte, Get_Name_String (Lang.Name));
8211                      exit when Elng /= No_Language_Index;
8212                      Exte := Exte.Extends;
8213                   end loop;
8214
8215                   if Elng /= Lang then
8216                      Lang.Config := Elng.Config;
8217                   end if;
8218                end if;
8219             end if;
8220
8221             List := List.Next;
8222          end loop;
8223       end;
8224    end Process_Naming_Scheme;
8225
8226 end Prj.Nmsc;