OSDN Git Service

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