OSDN Git Service

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