| ------------------------------------------------------------------------------ |
| -- -- |
| -- GNAT COMPILER COMPONENTS -- |
| -- -- |
| -- P R J . N M S C -- |
| -- -- |
| -- B o d y -- |
| -- -- |
| -- Copyright (C) 2000-2012, Free Software Foundation, Inc. -- |
| -- -- |
| -- GNAT is free software; you can redistribute it and/or modify it under -- |
| -- terms of the GNU General Public License as published by the Free Soft- -- |
| -- ware Foundation; either version 3, or (at your option) any later ver- -- |
| -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- |
| -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- |
| -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- |
| -- for more details. You should have received a copy of the GNU General -- |
| -- Public License distributed with GNAT; see file COPYING3. If not, go to -- |
| -- http://www.gnu.org/licenses for a complete copy of the license. -- |
| -- -- |
| -- GNAT was originally developed by the GNAT team at New York University. -- |
| -- Extensive contributions were provided by Ada Core Technologies Inc. -- |
| -- -- |
| ------------------------------------------------------------------------------ |
| |
| with Err_Vars; use Err_Vars; |
| with Opt; use Opt; |
| with Osint; use Osint; |
| with Output; use Output; |
| with Prj.Com; |
| with Prj.Env; use Prj.Env; |
| with Prj.Err; use Prj.Err; |
| with Prj.Tree; use Prj.Tree; |
| with Prj.Util; use Prj.Util; |
| with Sinput.P; |
| with Snames; use Snames; |
| with Targparm; use Targparm; |
| |
| with Ada; use Ada; |
| with Ada.Characters.Handling; use Ada.Characters.Handling; |
| with Ada.Directories; use Ada.Directories; |
| with Ada.Strings; use Ada.Strings; |
| with Ada.Strings.Fixed; use Ada.Strings.Fixed; |
| with Ada.Strings.Maps.Constants; use Ada.Strings.Maps.Constants; |
| |
| with GNAT.Case_Util; use GNAT.Case_Util; |
| with GNAT.Directory_Operations; use GNAT.Directory_Operations; |
| with GNAT.Dynamic_HTables; |
| with GNAT.Regexp; use GNAT.Regexp; |
| with GNAT.Table; |
| |
| package body Prj.Nmsc is |
| |
| No_Continuation_String : aliased String := ""; |
| Continuation_String : aliased String := "\"; |
| -- Used in Check_Library for continuation error messages at the same |
| -- location. |
| |
| type Name_Location is record |
| Name : File_Name_Type; |
| -- Key is duplicated, so that it is known when using functions Get_First |
| -- and Get_Next, as these functions only return an Element. |
| |
| Location : Source_Ptr; |
| Source : Source_Id := No_Source; |
| Listed : Boolean := False; |
| Found : Boolean := False; |
| end record; |
| |
| No_Name_Location : constant Name_Location := |
| (Name => No_File, |
| Location => No_Location, |
| Source => No_Source, |
| Listed => False, |
| Found => False); |
| |
| package Source_Names_Htable is new GNAT.Dynamic_HTables.Simple_HTable |
| (Header_Num => Header_Num, |
| Element => Name_Location, |
| No_Element => No_Name_Location, |
| Key => File_Name_Type, |
| Hash => Hash, |
| Equal => "="); |
| -- File name information found in string list attribute (Source_Files or |
| -- Source_List_File). Used to check that all referenced files were indeed |
| -- found on the disk. |
| |
| type Unit_Exception is record |
| Name : Name_Id; |
| -- Key is duplicated, so that it is known when using functions Get_First |
| -- and Get_Next, as these functions only return an Element. |
| |
| Spec : File_Name_Type; |
| Impl : File_Name_Type; |
| end record; |
| |
| No_Unit_Exception : constant Unit_Exception := (No_Name, No_File, No_File); |
| |
| package Unit_Exceptions_Htable is new GNAT.Dynamic_HTables.Simple_HTable |
| (Header_Num => Header_Num, |
| Element => Unit_Exception, |
| No_Element => No_Unit_Exception, |
| Key => Name_Id, |
| Hash => Hash, |
| Equal => "="); |
| -- Record special naming schemes for Ada units (name of spec file and name |
| -- of implementation file). The elements in this list come from the naming |
| -- exceptions specified in the project files. |
| |
| type File_Found is record |
| File : File_Name_Type := No_File; |
| Excl_File : File_Name_Type := No_File; |
| Excl_Line : Natural := 0; |
| Found : Boolean := False; |
| Location : Source_Ptr := No_Location; |
| end record; |
| |
| No_File_Found : constant File_Found := |
| (No_File, No_File, 0, False, No_Location); |
| |
| package Excluded_Sources_Htable is new GNAT.Dynamic_HTables.Simple_HTable |
| (Header_Num => Header_Num, |
| Element => File_Found, |
| No_Element => No_File_Found, |
| Key => File_Name_Type, |
| Hash => Hash, |
| Equal => "="); |
| -- A hash table to store the base names of excluded files, if any |
| |
| package Object_File_Names_Htable is new GNAT.Dynamic_HTables.Simple_HTable |
| (Header_Num => Header_Num, |
| Element => Source_Id, |
| No_Element => No_Source, |
| Key => File_Name_Type, |
| Hash => Hash, |
| Equal => "="); |
| -- A hash table to store the object file names for a project, to check that |
| -- two different sources have different object file names. |
| |
| type Project_Processing_Data is record |
| Project : Project_Id; |
| Source_Names : Source_Names_Htable.Instance; |
| Unit_Exceptions : Unit_Exceptions_Htable.Instance; |
| Excluded : Excluded_Sources_Htable.Instance; |
| |
| Source_List_File_Location : Source_Ptr; |
| -- Location of the Source_List_File attribute, for error messages |
| end record; |
| -- This is similar to Tree_Processing_Data, but contains project-specific |
| -- information which is only useful while processing the project, and can |
| -- be discarded as soon as we have finished processing the project |
| |
| type Tree_Processing_Data is record |
| Tree : Project_Tree_Ref; |
| Node_Tree : Prj.Tree.Project_Node_Tree_Ref; |
| Flags : Prj.Processing_Flags; |
| In_Aggregate_Lib : Boolean; |
| end record; |
| -- Temporary data which is needed while parsing a project. It does not need |
| -- to be kept in memory once a project has been fully loaded, but is |
| -- necessary while performing consistency checks (duplicate sources,...) |
| -- This data must be initialized before processing any project, and the |
| -- same data is used for processing all projects in the tree. |
| |
| type Lib_Data is record |
| Name : Name_Id; |
| Proj : Project_Id; |
| Tree : Project_Tree_Ref; |
| end record; |
| |
| package Lib_Data_Table is new GNAT.Table |
| (Table_Component_Type => Lib_Data, |
| Table_Index_Type => Natural, |
| Table_Low_Bound => 1, |
| Table_Initial => 10, |
| Table_Increment => 100); |
| -- A table to record library names in order to check that two library |
| -- projects do not have the same library names. |
| |
| procedure Initialize |
| (Data : out Tree_Processing_Data; |
| Tree : Project_Tree_Ref; |
| Node_Tree : Prj.Tree.Project_Node_Tree_Ref; |
| Flags : Prj.Processing_Flags); |
| -- Initialize Data |
| |
| procedure Free (Data : in out Tree_Processing_Data); |
| -- Free the memory occupied by Data |
| |
| procedure Initialize |
| (Data : in out Project_Processing_Data; |
| Project : Project_Id); |
| procedure Free (Data : in out Project_Processing_Data); |
| -- Initialize or free memory for a project-specific data |
| |
| procedure Find_Excluded_Sources |
| (Project : in out Project_Processing_Data; |
| Data : in out Tree_Processing_Data); |
| -- Find the list of files that should not be considered as source files |
| -- for this project. Sets the list in the Project.Excluded_Sources_Htable. |
| |
| procedure Override_Kind (Source : Source_Id; Kind : Source_Kind); |
| -- Override the reference kind for a source file. This properly updates |
| -- the unit data if necessary. |
| |
| procedure Load_Naming_Exceptions |
| (Project : in out Project_Processing_Data; |
| Data : in out Tree_Processing_Data); |
| -- All source files in Data.First_Source are considered as naming |
| -- exceptions, and copied into the Source_Names and Unit_Exceptions tables |
| -- as appropriate. |
| |
| type Search_Type is (Search_Files, Search_Directories); |
| |
| generic |
| with procedure Callback |
| (Path : Path_Information; |
| Pattern_Index : Natural); |
| procedure Expand_Subdirectory_Pattern |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data; |
| Patterns : String_List_Id; |
| Ignore : String_List_Id; |
| Search_For : Search_Type; |
| Resolve_Links : Boolean); |
| -- Search the subdirectories of Project's directory for files or |
| -- directories that match the globbing patterns found in Patterns (for |
| -- instance "**/*.adb"). Typically, Patterns will be the value of the |
| -- Source_Dirs or Excluded_Source_Dirs attributes. |
| -- |
| -- Every time such a file or directory is found, the callback is called. |
| -- Resolve_Links indicates whether we should resolve links while |
| -- normalizing names. |
| -- |
| -- In the callback, Pattern_Index is the index within Patterns where the |
| -- expanded pattern was found (1 for the first element of Patterns and |
| -- all its matching directories, then 2,...). |
| -- |
| -- We use a generic and not an access-to-subprogram because in some cases |
| -- this code is compiled with the restriction No_Implicit_Dynamic_Code. |
| -- An error message is raised if a pattern does not match any file. |
| |
| procedure Add_Source |
| (Id : out Source_Id; |
| Data : in out Tree_Processing_Data; |
| Project : Project_Id; |
| Source_Dir_Rank : Natural; |
| Lang_Id : Language_Ptr; |
| Kind : Source_Kind; |
| File_Name : File_Name_Type; |
| Display_File : File_Name_Type; |
| Naming_Exception : Naming_Exception_Type := No; |
| Path : Path_Information := No_Path_Information; |
| Alternate_Languages : Language_List := null; |
| Unit : Name_Id := No_Name; |
| Index : Int := 0; |
| Locally_Removed : Boolean := False; |
| Location : Source_Ptr := No_Location); |
| -- Add a new source to the different lists: list of all sources in the |
| -- project tree, list of source of a project and list of sources of a |
| -- language. If Path is specified, the file is also added to |
| -- Source_Paths_HT. Location is used for error messages |
| |
| function Canonical_Case_File_Name (Name : Name_Id) return File_Name_Type; |
| -- Same as Osint.Canonical_Case_File_Name but applies to Name_Id. |
| -- This alters Name_Buffer. |
| |
| function Suffix_Matches |
| (Filename : String; |
| Suffix : File_Name_Type) return Boolean; |
| -- True if the file name ends with the given suffix. Always returns False |
| -- if Suffix is No_Name. |
| |
| procedure Replace_Into_Name_Buffer |
| (Str : String; |
| Pattern : String; |
| Replacement : Character); |
| -- Copy Str into Name_Buffer, replacing Pattern with Replacement. Str is |
| -- converted to lower-case at the same time. |
| |
| procedure Check_Abstract_Project |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data); |
| -- Check abstract projects attributes |
| |
| procedure Check_Configuration |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data); |
| -- Check the configuration attributes for the project |
| |
| procedure Check_If_Externally_Built |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data); |
| -- Check attribute Externally_Built of project Project in project tree |
| -- Data.Tree and modify its data Data if it has the value "true". |
| |
| procedure Check_Interfaces |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data); |
| -- If a list of sources is specified in attribute Interfaces, set |
| -- In_Interfaces only for the sources specified in the list. |
| |
| procedure Check_Library_Attributes |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data); |
| -- Check the library attributes of project Project in project tree |
| -- and modify its data Data accordingly. |
| |
| procedure Check_Package_Naming |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data); |
| -- Check the naming scheme part of Data, and initialize the naming scheme |
| -- data in the config of the various languages. |
| |
| procedure Check_Programming_Languages |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data); |
| -- Check attribute Languages for the project with data Data in project |
| -- tree Data.Tree and set the components of Data for all the programming |
| -- languages indicated in attribute Languages, if any. |
| |
| procedure Check_Stand_Alone_Library |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data); |
| -- Check if project Project in project tree Data.Tree is a Stand-Alone |
| -- Library project, and modify its data Data accordingly if it is one. |
| |
| procedure Check_Unit_Name (Name : String; Unit : out Name_Id); |
| -- Check that a name is a valid unit name |
| |
| function Compute_Directory_Last (Dir : String) return Natural; |
| -- Return the index of the last significant character in Dir. This is used |
| -- to avoid duplicate '/' (slash) characters at the end of directory names. |
| |
| procedure Search_Directories |
| (Project : in out Project_Processing_Data; |
| Data : in out Tree_Processing_Data; |
| For_All_Sources : Boolean); |
| -- Search the source directories to find the sources. If For_All_Sources is |
| -- True, check each regular file name against the naming schemes of the |
| -- various languages. Otherwise consider only the file names in hash table |
| -- Source_Names. If Allow_Duplicate_Basenames then files with identical |
| -- base names are permitted within a project for source-based languages |
| -- (never for unit based languages). |
| |
| procedure Check_File |
| (Project : in out Project_Processing_Data; |
| Data : in out Tree_Processing_Data; |
| Source_Dir_Rank : Natural; |
| Path : Path_Name_Type; |
| Display_Path : Path_Name_Type; |
| File_Name : File_Name_Type; |
| Display_File_Name : File_Name_Type; |
| Locally_Removed : Boolean; |
| For_All_Sources : Boolean); |
| -- Check if file File_Name is a valid source of the project. This is used |
| -- in multi-language mode only. When the file matches one of the naming |
| -- schemes, it is added to various htables through Add_Source and to |
| -- Source_Paths_Htable. |
| -- |
| -- File_Name is the same as Display_File_Name, but has been normalized. |
| -- They do not include the directory information. |
| -- |
| -- Path and Display_Path on the other hand are the full path to the file. |
| -- Path must have been normalized (canonical casing and possibly links |
| -- resolved). |
| -- |
| -- Source_Directory is the directory in which the file was found. It is |
| -- neither normalized nor has had links resolved, and must not end with a |
| -- a directory separator, to avoid duplicates later on. |
| -- |
| -- If For_All_Sources is True, then all possible file names are analyzed |
| -- otherwise only those currently set in the Source_Names hash table. |
| |
| procedure Check_File_Naming_Schemes |
| (Project : Project_Processing_Data; |
| File_Name : File_Name_Type; |
| Alternate_Languages : out Language_List; |
| Language : out Language_Ptr; |
| Display_Language_Name : out Name_Id; |
| Unit : out Name_Id; |
| Lang_Kind : out Language_Kind; |
| Kind : out Source_Kind); |
| -- Check if the file name File_Name conforms to one of the naming schemes |
| -- of the project. If the file does not match one of the naming schemes, |
| -- set Language to No_Language_Index. Filename is the name of the file |
| -- being investigated. It has been normalized (case-folded). File_Name is |
| -- the same value. |
| |
| procedure Get_Directories |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data); |
| -- Get the object directory, the exec directory and the source directories |
| -- of a project. |
| |
| procedure Get_Mains |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data); |
| -- Get the mains of a project from attribute Main, if it exists, and put |
| -- them in the project data. |
| |
| procedure Get_Sources_From_File |
| (Path : String; |
| Location : Source_Ptr; |
| Project : in out Project_Processing_Data; |
| Data : in out Tree_Processing_Data); |
| -- Get the list of sources from a text file and put them in hash table |
| -- Source_Names. |
| |
| procedure Find_Sources |
| (Project : in out Project_Processing_Data; |
| Data : in out Tree_Processing_Data); |
| -- Process the Source_Files and Source_List_File attributes, and store the |
| -- list of source files into the Source_Names htable. When these attributes |
| -- are not defined, find all files matching the naming schemes in the |
| -- source directories. If Allow_Duplicate_Basenames, then files with the |
| -- same base names are authorized within a project for source-based |
| -- languages (never for unit based languages) |
| |
| procedure Compute_Unit_Name |
| (File_Name : File_Name_Type; |
| Naming : Lang_Naming_Data; |
| Kind : out Source_Kind; |
| Unit : out Name_Id; |
| Project : Project_Processing_Data); |
| -- Check whether the file matches the naming scheme. If it does, |
| -- compute its unit name. If Unit is set to No_Name on exit, none of the |
| -- other out parameters are relevant. |
| |
| procedure Check_Illegal_Suffix |
| (Project : Project_Id; |
| Suffix : File_Name_Type; |
| Dot_Replacement : File_Name_Type; |
| Attribute_Name : String; |
| Location : Source_Ptr; |
| Data : in out Tree_Processing_Data); |
| -- Display an error message if the given suffix is illegal for some reason. |
| -- The name of the attribute we are testing is specified in Attribute_Name, |
| -- which is used in the error message. Location is the location where the |
| -- suffix is defined. |
| |
| procedure Locate_Directory |
| (Project : Project_Id; |
| Name : File_Name_Type; |
| Path : out Path_Information; |
| Dir_Exists : out Boolean; |
| Data : in out Tree_Processing_Data; |
| Create : String := ""; |
| Location : Source_Ptr := No_Location; |
| Must_Exist : Boolean := True; |
| Externally_Built : Boolean := False); |
| -- Locate a directory. Name is the directory name. Relative paths are |
| -- resolved relative to the project's directory. If the directory does not |
| -- exist and Setup_Projects is True and Create is a non null string, an |
| -- attempt is made to create the directory. If the directory does not |
| -- exist, it is either created if Setup_Projects is False (and then |
| -- returned), or simply returned without checking for its existence (if |
| -- Must_Exist is False) or No_Path_Information is returned. In all cases, |
| -- Dir_Exists indicates whether the directory now exists. Create is also |
| -- used for debugging traces to show which path we are computing. |
| |
| procedure Look_For_Sources |
| (Project : in out Project_Processing_Data; |
| Data : in out Tree_Processing_Data); |
| -- Find all the sources of project Project in project tree Data.Tree and |
| -- update its Data accordingly. This assumes that the special naming |
| -- exceptions have already been processed. |
| |
| function Path_Name_Of |
| (File_Name : File_Name_Type; |
| Directory : Path_Name_Type) return String; |
| -- Returns the path name of a (non project) file. Returns an empty string |
| -- if file cannot be found. |
| |
| procedure Remove_Source |
| (Tree : Project_Tree_Ref; |
| Id : Source_Id; |
| Replaced_By : Source_Id); |
| -- Remove a file from the list of sources of a project. This might be |
| -- because the file is replaced by another one in an extending project, |
| -- or because a file was added as a naming exception but was not found |
| -- in the end. |
| |
| procedure Report_No_Sources |
| (Project : Project_Id; |
| Lang_Name : String; |
| Data : Tree_Processing_Data; |
| Location : Source_Ptr; |
| Continuation : Boolean := False); |
| -- Report an error or a warning depending on the value of When_No_Sources |
| -- when there are no sources for language Lang_Name. |
| |
| procedure Show_Source_Dirs |
| (Project : Project_Id; |
| Shared : Shared_Project_Tree_Data_Access); |
| -- List all the source directories of a project |
| |
| procedure Write_Attr (Name, Value : String); |
| -- Debug print a value for a specific property. Does nothing when not in |
| -- debug mode |
| |
| procedure Error_Or_Warning |
| (Flags : Processing_Flags; |
| Kind : Error_Warning; |
| Msg : String; |
| Location : Source_Ptr; |
| Project : Project_Id); |
| -- Emits either an error or warning message (or nothing), depending on Kind |
| |
| function No_Space_Img (N : Natural) return String; |
| -- Image of a Natural without the initial space |
| |
| ---------------------- |
| -- Error_Or_Warning -- |
| ---------------------- |
| |
| procedure Error_Or_Warning |
| (Flags : Processing_Flags; |
| Kind : Error_Warning; |
| Msg : String; |
| Location : Source_Ptr; |
| Project : Project_Id) is |
| begin |
| case Kind is |
| when Error => Error_Msg (Flags, Msg, Location, Project); |
| when Warning => Error_Msg (Flags, "?" & Msg, Location, Project); |
| when Silent => null; |
| end case; |
| end Error_Or_Warning; |
| |
| ------------------------------ |
| -- Replace_Into_Name_Buffer -- |
| ------------------------------ |
| |
| procedure Replace_Into_Name_Buffer |
| (Str : String; |
| Pattern : String; |
| Replacement : Character) |
| is |
| Max : constant Integer := Str'Last - Pattern'Length + 1; |
| J : Positive; |
| |
| begin |
| Name_Len := 0; |
| |
| J := Str'First; |
| while J <= Str'Last loop |
| Name_Len := Name_Len + 1; |
| |
| if J <= Max |
| and then Str (J .. J + Pattern'Length - 1) = Pattern |
| then |
| Name_Buffer (Name_Len) := Replacement; |
| J := J + Pattern'Length; |
| |
| else |
| Name_Buffer (Name_Len) := GNAT.Case_Util.To_Lower (Str (J)); |
| J := J + 1; |
| end if; |
| end loop; |
| end Replace_Into_Name_Buffer; |
| |
| -------------------- |
| -- Suffix_Matches -- |
| -------------------- |
| |
| function Suffix_Matches |
| (Filename : String; |
| Suffix : File_Name_Type) return Boolean |
| is |
| Min_Prefix_Length : Natural := 0; |
| |
| begin |
| if Suffix = No_File or else Suffix = Empty_File then |
| return False; |
| end if; |
| |
| declare |
| Suf : String := Get_Name_String (Suffix); |
| |
| begin |
| -- On non case-sensitive systems, use proper suffix casing |
| |
| Canonical_Case_File_Name (Suf); |
| |
| -- The file name must end with the suffix (which is not an extension) |
| -- For instance a suffix "configure.in" must match a file with the |
| -- same name. To avoid dummy cases, though, a suffix starting with |
| -- '.' requires a file that is at least one character longer ('.cpp' |
| -- should not match a file with the same name). |
| |
| if Suf (Suf'First) = '.' then |
| Min_Prefix_Length := 1; |
| end if; |
| |
| return Filename'Length >= Suf'Length + Min_Prefix_Length |
| and then |
| Filename (Filename'Last - Suf'Length + 1 .. Filename'Last) = Suf; |
| end; |
| end Suffix_Matches; |
| |
| ---------------- |
| -- Write_Attr -- |
| ---------------- |
| |
| procedure Write_Attr (Name, Value : String) is |
| begin |
| if Current_Verbosity = High then |
| Debug_Output (Name & " = """ & Value & '"'); |
| end if; |
| end Write_Attr; |
| |
| ---------------- |
| -- Add_Source -- |
| ---------------- |
| |
| procedure Add_Source |
| (Id : out Source_Id; |
| Data : in out Tree_Processing_Data; |
| Project : Project_Id; |
| Source_Dir_Rank : Natural; |
| Lang_Id : Language_Ptr; |
| Kind : Source_Kind; |
| File_Name : File_Name_Type; |
| Display_File : File_Name_Type; |
| Naming_Exception : Naming_Exception_Type := No; |
| Path : Path_Information := No_Path_Information; |
| Alternate_Languages : Language_List := null; |
| Unit : Name_Id := No_Name; |
| Index : Int := 0; |
| Locally_Removed : Boolean := False; |
| Location : Source_Ptr := No_Location) |
| is |
| Config : constant Language_Config := Lang_Id.Config; |
| UData : Unit_Index; |
| Add_Src : Boolean; |
| Source : Source_Id; |
| Prev_Unit : Unit_Index := No_Unit_Index; |
| Source_To_Replace : Source_Id := No_Source; |
| |
| begin |
| -- Check if the same file name or unit is used in the prj tree |
| |
| Add_Src := True; |
| |
| if Unit /= No_Name then |
| Prev_Unit := Units_Htable.Get (Data.Tree.Units_HT, Unit); |
| end if; |
| |
| if Prev_Unit /= No_Unit_Index |
| and then (Kind = Impl or else Kind = Spec) |
| and then Prev_Unit.File_Names (Kind) /= null |
| then |
| -- Suspicious, we need to check later whether this is authorized |
| |
| Add_Src := False; |
| Source := Prev_Unit.File_Names (Kind); |
| |
| else |
| Source := Source_Files_Htable.Get |
| (Data.Tree.Source_Files_HT, File_Name); |
| |
| if Source /= No_Source and then Source.Index = Index then |
| Add_Src := False; |
| end if; |
| end if; |
| |
| -- Always add the source if it is locally removed, to avoid incorrect |
| -- duplicate checks. |
| |
| if Locally_Removed then |
| Add_Src := True; |
| |
| -- A locally removed source may first replace a source in a project |
| -- being extended. |
| |
| if Source /= No_Source |
| and then Is_Extending (Project, Source.Project) |
| and then Naming_Exception /= Inherited |
| then |
| Source_To_Replace := Source; |
| end if; |
| |
| else |
| -- Duplication of file/unit in same project is allowed if order of |
| -- source directories is known, or if there is no compiler for the |
| -- language. |
| |
| if Add_Src = False then |
| Add_Src := True; |
| |
| if Project = Source.Project then |
| if Prev_Unit = No_Unit_Index then |
| if Data.Flags.Allow_Duplicate_Basenames then |
| Add_Src := True; |
| |
| elsif Lang_Id.Config.Compiler_Driver = Empty_File then |
| Add_Src := True; |
| |
| elsif Source_Dir_Rank /= Source.Source_Dir_Rank then |
| Add_Src := False; |
| |
| else |
| Error_Msg_File_1 := File_Name; |
| Error_Msg |
| (Data.Flags, "duplicate source file name {", |
| Location, Project); |
| Add_Src := False; |
| end if; |
| |
| else |
| if Source_Dir_Rank /= Source.Source_Dir_Rank then |
| Add_Src := False; |
| |
| -- We might be seeing the same file through a different |
| -- path (for instance because of symbolic links). |
| |
| elsif Source.Path.Name /= Path.Name then |
| if not Source.Duplicate_Unit then |
| Error_Msg_Name_1 := Unit; |
| Error_Msg |
| (Data.Flags, |
| "\duplicate unit %%", |
| Location, |
| Project); |
| Source.Duplicate_Unit := True; |
| end if; |
| |
| Add_Src := False; |
| end if; |
| end if; |
| |
| -- Do not allow the same unit name in different projects, |
| -- except if one is extending the other. |
| |
| -- For a file based language, the same file name replaces a |
| -- file in a project being extended, but it is allowed to have |
| -- the same file name in unrelated projects. |
| |
| elsif Is_Extending (Project, Source.Project) then |
| if not Locally_Removed |
| and then Naming_Exception /= Inherited |
| then |
| Source_To_Replace := Source; |
| end if; |
| |
| elsif Prev_Unit /= No_Unit_Index |
| and then Prev_Unit.File_Names (Kind) /= null |
| and then not Source.Locally_Removed |
| and then Source.Replaced_By = No_Source |
| and then not Data.In_Aggregate_Lib |
| then |
| -- Path is set if this is a source we found on the disk, in |
| -- which case we can provide more explicit error message. Path |
| -- is unset when the source is added from one of the naming |
| -- exceptions in the project. |
| |
| if Path /= No_Path_Information then |
| Error_Msg_Name_1 := Unit; |
| Error_Msg |
| (Data.Flags, |
| "unit %% cannot belong to several projects", |
| Location, Project); |
| |
| Error_Msg_Name_1 := Project.Name; |
| Error_Msg_Name_2 := Name_Id (Path.Display_Name); |
| Error_Msg |
| (Data.Flags, "\ project %%, %%", Location, Project); |
| |
| Error_Msg_Name_1 := Source.Project.Name; |
| Error_Msg_Name_2 := Name_Id (Source.Path.Display_Name); |
| Error_Msg |
| (Data.Flags, "\ project %%, %%", Location, Project); |
| |
| else |
| Error_Msg_Name_1 := Unit; |
| Error_Msg_Name_2 := Source.Project.Name; |
| Error_Msg |
| (Data.Flags, "unit %% already belongs to project %%", |
| Location, Project); |
| end if; |
| |
| Add_Src := False; |
| |
| elsif not Source.Locally_Removed |
| and then Source.Replaced_By /= No_Source |
| and then not Data.Flags.Allow_Duplicate_Basenames |
| and then Lang_Id.Config.Kind = Unit_Based |
| and then Source.Language.Config.Kind = Unit_Based |
| and then not Data.In_Aggregate_Lib |
| then |
| Error_Msg_File_1 := File_Name; |
| Error_Msg_File_2 := File_Name_Type (Source.Project.Name); |
| Error_Msg |
| (Data.Flags, |
| "{ is already a source of project {", Location, Project); |
| |
| -- Add the file anyway, to avoid further warnings like |
| -- "language unknown". |
| |
| Add_Src := True; |
| end if; |
| end if; |
| end if; |
| |
| if not Add_Src then |
| return; |
| end if; |
| |
| -- Add the new file |
| |
| Id := new Source_Data; |
| |
| if Current_Verbosity = High then |
| Debug_Indent; |
| Write_Str ("adding source File: "); |
| Write_Str (Get_Name_String (Display_File)); |
| |
| if Index /= 0 then |
| Write_Str (" at" & Index'Img); |
| end if; |
| |
| if Lang_Id.Config.Kind = Unit_Based then |
| Write_Str (" Unit: "); |
| |
| -- ??? in gprclean, it seems we sometimes pass an empty Unit name |
| -- (see test extended_projects). |
| |
| if Unit /= No_Name then |
| Write_Str (Get_Name_String (Unit)); |
| end if; |
| |
| Write_Str (" Kind: "); |
| Write_Str (Source_Kind'Image (Kind)); |
| end if; |
| |
| Write_Eol; |
| end if; |
| |
| Id.Project := Project; |
| Id.Location := Location; |
| Id.Source_Dir_Rank := Source_Dir_Rank; |
| Id.Language := Lang_Id; |
| Id.Kind := Kind; |
| Id.Alternate_Languages := Alternate_Languages; |
| Id.Locally_Removed := Locally_Removed; |
| Id.Index := Index; |
| Id.File := File_Name; |
| Id.Display_File := Display_File; |
| Id.Dep_Name := Dependency_Name |
| (File_Name, Lang_Id.Config.Dependency_Kind); |
| Id.Naming_Exception := Naming_Exception; |
| Id.Object := Object_Name |
| (File_Name, Config.Object_File_Suffix); |
| Id.Switches := Switches_Name (File_Name); |
| |
| -- Add the source id to the Unit_Sources_HT hash table, if the unit name |
| -- is not null. |
| |
| if Unit /= No_Name then |
| |
| -- Note: we might be creating a dummy unit here, when we in fact have |
| -- a separate. For instance, file file-bar.adb will initially be |
| -- assumed to be the IMPL of unit "file.bar". Only later on (in |
| -- Check_Object_Files) will we parse those units that only have an |
| -- impl and no spec to make sure whether we have a Separate in fact |
| -- (that significantly reduces the number of times we need to parse |
| -- the files, since we are then only interested in those with no |
| -- spec). We still need those dummy units in the table, since that's |
| -- the name we find in the ALI file |
| |
| UData := Units_Htable.Get (Data.Tree.Units_HT, Unit); |
| |
| if UData = No_Unit_Index then |
| UData := new Unit_Data; |
| UData.Name := Unit; |
| |
| if Naming_Exception /= Inherited then |
| Units_Htable.Set (Data.Tree.Units_HT, Unit, UData); |
| end if; |
| end if; |
| |
| Id.Unit := UData; |
| |
| -- Note that this updates Unit information as well |
| |
| if Naming_Exception /= Inherited and then not Locally_Removed then |
| Override_Kind (Id, Kind); |
| end if; |
| end if; |
| |
| if Path /= No_Path_Information then |
| Id.Path := Path; |
| Source_Paths_Htable.Set (Data.Tree.Source_Paths_HT, Path.Name, Id); |
| end if; |
| |
| Id.Next_With_File_Name := |
| Source_Files_Htable.Get (Data.Tree.Source_Files_HT, File_Name); |
| Source_Files_Htable.Set (Data.Tree.Source_Files_HT, File_Name, Id); |
| |
| if Index /= 0 then |
| Project.Has_Multi_Unit_Sources := True; |
| end if; |
| |
| -- Add the source to the language list |
| |
| Id.Next_In_Lang := Lang_Id.First_Source; |
| Lang_Id.First_Source := Id; |
| |
| if Source_To_Replace /= No_Source then |
| Remove_Source (Data.Tree, Source_To_Replace, Id); |
| end if; |
| |
| if Data.Tree.Replaced_Source_Number > 0 |
| and then |
| Replaced_Source_HTable.Get |
| (Data.Tree.Replaced_Sources, Id.File) /= No_File |
| then |
| Replaced_Source_HTable.Remove (Data.Tree.Replaced_Sources, Id.File); |
| Data.Tree.Replaced_Source_Number := |
| Data.Tree.Replaced_Source_Number - 1; |
| end if; |
| end Add_Source; |
| |
| ------------------------------ |
| -- Canonical_Case_File_Name -- |
| ------------------------------ |
| |
| function Canonical_Case_File_Name (Name : Name_Id) return File_Name_Type is |
| begin |
| if Osint.File_Names_Case_Sensitive then |
| return File_Name_Type (Name); |
| else |
| Get_Name_String (Name); |
| Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); |
| return Name_Find; |
| end if; |
| end Canonical_Case_File_Name; |
| |
| --------------------------------- |
| -- Process_Aggregated_Projects -- |
| --------------------------------- |
| |
| procedure Process_Aggregated_Projects |
| (Tree : Project_Tree_Ref; |
| Project : Project_Id; |
| Node_Tree : Prj.Tree.Project_Node_Tree_Ref; |
| Flags : Processing_Flags) |
| is |
| Data : Tree_Processing_Data := |
| (Tree => Tree, |
| Node_Tree => Node_Tree, |
| Flags => Flags, |
| In_Aggregate_Lib => False); |
| |
| Project_Files : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Project_Files, |
| Project.Decl.Attributes, |
| Tree.Shared); |
| |
| Project_Path_For_Aggregate : Prj.Env.Project_Search_Path; |
| |
| procedure Found_Project_File (Path : Path_Information; Rank : Natural); |
| -- Called for each project file aggregated by Project |
| |
| procedure Expand_Project_Files is |
| new Expand_Subdirectory_Pattern (Callback => Found_Project_File); |
| -- Search for all project files referenced by the patterns given in |
| -- parameter. Calls Found_Project_File for each of them. |
| |
| ------------------------ |
| -- Found_Project_File -- |
| ------------------------ |
| |
| procedure Found_Project_File (Path : Path_Information; Rank : Natural) is |
| pragma Unreferenced (Rank); |
| |
| begin |
| if Path.Name /= Project.Path.Name then |
| Debug_Output ("aggregates: ", Name_Id (Path.Display_Name)); |
| |
| -- For usual "with" statement, this phase will have been done when |
| -- parsing the project itself. However, for aggregate projects, we |
| -- can only do this when processing the aggregate project, since |
| -- the exact list of project files or project directories can |
| -- depend on scenario variables. |
| -- |
| -- We only load the projects explicitly here, but do not process |
| -- them. For the processing, Prj.Proc will take care of processing |
| -- them, within the same call to Recursive_Process (thus avoiding |
| -- the processing of a given project multiple times). |
| -- |
| -- ??? We might already have loaded the project |
| |
| Add_Aggregated_Project (Project, Path => Path.Name); |
| |
| else |
| Debug_Output ("pattern returned the aggregate itself, ignored"); |
| end if; |
| end Found_Project_File; |
| |
| -- Start of processing for Check_Aggregate_Project |
| |
| begin |
| pragma Assert (Project.Qualifier in Aggregate_Project); |
| |
| if Project_Files.Default then |
| Error_Msg_Name_1 := Snames.Name_Project_Files; |
| Error_Msg |
| (Flags, |
| "Attribute %% must be specified in aggregate project", |
| Project.Location, Project); |
| return; |
| end if; |
| |
| -- The aggregated projects are only searched relative to the directory |
| -- of the aggregate project, not in the default project path. |
| |
| Initialize_Empty (Project_Path_For_Aggregate); |
| |
| Free (Project.Aggregated_Projects); |
| |
| -- Look for aggregated projects. For similarity with source files and |
| -- dirs, the aggregated project files are not searched for on the |
| -- project path, and are only found through the path specified in |
| -- the Project_Files attribute. |
| |
| Expand_Project_Files |
| (Project => Project, |
| Data => Data, |
| Patterns => Project_Files.Values, |
| Ignore => Nil_String, |
| Search_For => Search_Files, |
| Resolve_Links => Opt.Follow_Links_For_Files); |
| |
| Free (Project_Path_For_Aggregate); |
| end Process_Aggregated_Projects; |
| |
| ---------------------------- |
| -- Check_Abstract_Project -- |
| ---------------------------- |
| |
| procedure Check_Abstract_Project |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data) |
| is |
| Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared; |
| |
| Source_Dirs : constant Variable_Value := |
| Util.Value_Of |
| (Name_Source_Dirs, |
| Project.Decl.Attributes, Shared); |
| Source_Files : constant Variable_Value := |
| Util.Value_Of |
| (Name_Source_Files, |
| Project.Decl.Attributes, Shared); |
| Source_List_File : constant Variable_Value := |
| Util.Value_Of |
| (Name_Source_List_File, |
| Project.Decl.Attributes, Shared); |
| Languages : constant Variable_Value := |
| Util.Value_Of |
| (Name_Languages, |
| Project.Decl.Attributes, Shared); |
| |
| begin |
| if Project.Source_Dirs /= Nil_String then |
| if Source_Dirs.Values = Nil_String |
| and then Source_Files.Values = Nil_String |
| and then Languages.Values = Nil_String |
| and then Source_List_File.Default |
| then |
| Project.Source_Dirs := Nil_String; |
| |
| else |
| Error_Msg |
| (Data.Flags, |
| "at least one of Source_Files, Source_Dirs or Languages " |
| & "must be declared empty for an abstract project", |
| Project.Location, Project); |
| end if; |
| end if; |
| end Check_Abstract_Project; |
| |
| ------------------------- |
| -- Check_Configuration -- |
| ------------------------- |
| |
| procedure Check_Configuration |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data) |
| is |
| Shared : constant Shared_Project_Tree_Data_Access := |
| Data.Tree.Shared; |
| |
| Dot_Replacement : File_Name_Type := No_File; |
| Casing : Casing_Type := All_Lower_Case; |
| Separate_Suffix : File_Name_Type := No_File; |
| |
| Lang_Index : Language_Ptr := No_Language_Index; |
| -- The index of the language data being checked |
| |
| Prev_Index : Language_Ptr := No_Language_Index; |
| -- The index of the previous language |
| |
| procedure Process_Project_Level_Simple_Attributes; |
| -- Process the simple attributes at the project level |
| |
| procedure Process_Project_Level_Array_Attributes; |
| -- Process the associate array attributes at the project level |
| |
| procedure Process_Packages; |
| -- Read the packages of the project |
| |
| ---------------------- |
| -- Process_Packages -- |
| ---------------------- |
| |
| procedure Process_Packages is |
| Packages : Package_Id; |
| Element : Package_Element; |
| |
| procedure Process_Binder (Arrays : Array_Id); |
| -- Process the associated array attributes of package Binder |
| |
| procedure Process_Builder (Attributes : Variable_Id); |
| -- Process the simple attributes of package Builder |
| |
| procedure Process_Clean (Arrays : Array_Id); |
| -- Process the associated array attributes of package Clean |
| |
| procedure Process_Compiler (Arrays : Array_Id); |
| -- Process the associated array attributes of package Compiler |
| |
| procedure Process_Naming (Attributes : Variable_Id); |
| -- Process the simple attributes of package Naming |
| |
| procedure Process_Naming (Arrays : Array_Id); |
| -- Process the associated array attributes of package Naming |
| |
| procedure Process_Linker (Attributes : Variable_Id); |
| -- Process the simple attributes of package Linker of a |
| -- configuration project. |
| |
| -------------------- |
| -- Process_Binder -- |
| -------------------- |
| |
| procedure Process_Binder (Arrays : Array_Id) is |
| Current_Array_Id : Array_Id; |
| Current_Array : Array_Data; |
| Element_Id : Array_Element_Id; |
| Element : Array_Element; |
| |
| begin |
| -- Process the associative array attribute of package Binder |
| |
| Current_Array_Id := Arrays; |
| while Current_Array_Id /= No_Array loop |
| Current_Array := Shared.Arrays.Table (Current_Array_Id); |
| |
| Element_Id := Current_Array.Value; |
| while Element_Id /= No_Array_Element loop |
| Element := Shared.Array_Elements.Table (Element_Id); |
| |
| if Element.Index /= All_Other_Names then |
| |
| -- Get the name of the language |
| |
| Lang_Index := |
| Get_Language_From_Name |
| (Project, Get_Name_String (Element.Index)); |
| |
| if Lang_Index /= No_Language_Index then |
| case Current_Array.Name is |
| when Name_Driver => |
| |
| -- Attribute Driver (<language>) |
| |
| Lang_Index.Config.Binder_Driver := |
| File_Name_Type (Element.Value.Value); |
| |
| when Name_Required_Switches => |
| Put |
| (Into_List => |
| Lang_Index.Config.Binder_Required_Switches, |
| From_List => Element.Value.Values, |
| In_Tree => Data.Tree); |
| |
| when Name_Prefix => |
| |
| -- Attribute Prefix (<language>) |
| |
| Lang_Index.Config.Binder_Prefix := |
| Element.Value.Value; |
| |
| when Name_Objects_Path => |
| |
| -- Attribute Objects_Path (<language>) |
| |
| Lang_Index.Config.Objects_Path := |
| Element.Value.Value; |
| |
| when Name_Objects_Path_File => |
| |
| -- Attribute Objects_Path (<language>) |
| |
| Lang_Index.Config.Objects_Path_File := |
| Element.Value.Value; |
| |
| when others => |
| null; |
| end case; |
| end if; |
| end if; |
| |
| Element_Id := Element.Next; |
| end loop; |
| |
| Current_Array_Id := Current_Array.Next; |
| end loop; |
| end Process_Binder; |
| |
| --------------------- |
| -- Process_Builder -- |
| --------------------- |
| |
| procedure Process_Builder (Attributes : Variable_Id) is |
| Attribute_Id : Variable_Id; |
| Attribute : Variable; |
| |
| begin |
| -- Process non associated array attribute from package Builder |
| |
| Attribute_Id := Attributes; |
| while Attribute_Id /= No_Variable loop |
| Attribute := Shared.Variable_Elements.Table (Attribute_Id); |
| |
| if not Attribute.Value.Default then |
| if Attribute.Name = Name_Executable_Suffix then |
| |
| -- Attribute Executable_Suffix: the suffix of the |
| -- executables. |
| |
| Project.Config.Executable_Suffix := |
| Attribute.Value.Value; |
| end if; |
| end if; |
| |
| Attribute_Id := Attribute.Next; |
| end loop; |
| end Process_Builder; |
| |
| ------------------- |
| -- Process_Clean -- |
| ------------------- |
| |
| procedure Process_Clean (Arrays : Array_Id) is |
| Current_Array_Id : Array_Id; |
| Current_Array : Array_Data; |
| Element_Id : Array_Element_Id; |
| Element : Array_Element; |
| List : String_List_Id; |
| |
| begin |
| -- Process the associated array attributes of package Clean |
| |
| Current_Array_Id := Arrays; |
| while Current_Array_Id /= No_Array loop |
| Current_Array := Shared.Arrays.Table (Current_Array_Id); |
| |
| Element_Id := Current_Array.Value; |
| while Element_Id /= No_Array_Element loop |
| Element := Shared.Array_Elements.Table (Element_Id); |
| |
| -- Get the name of the language |
| |
| Lang_Index := |
| Get_Language_From_Name |
| (Project, Get_Name_String (Element.Index)); |
| |
| if Lang_Index /= No_Language_Index then |
| case Current_Array.Name is |
| |
| -- Attribute Object_Artifact_Extensions (<language>) |
| |
| when Name_Object_Artifact_Extensions => |
| List := Element.Value.Values; |
| |
| if List /= Nil_String then |
| Put (Into_List => |
| Lang_Index.Config.Clean_Object_Artifacts, |
| From_List => List, |
| In_Tree => Data.Tree); |
| end if; |
| |
| -- Attribute Source_Artifact_Extensions (<language>) |
| |
| when Name_Source_Artifact_Extensions => |
| List := Element.Value.Values; |
| |
| if List /= Nil_String then |
| Put (Into_List => |
| Lang_Index.Config.Clean_Source_Artifacts, |
| From_List => List, |
| In_Tree => Data.Tree); |
| end if; |
| |
| when others => |
| null; |
| end case; |
| end if; |
| |
| Element_Id := Element.Next; |
| end loop; |
| |
| Current_Array_Id := Current_Array.Next; |
| end loop; |
| end Process_Clean; |
| |
| ---------------------- |
| -- Process_Compiler -- |
| ---------------------- |
| |
| procedure Process_Compiler (Arrays : Array_Id) is |
| Current_Array_Id : Array_Id; |
| Current_Array : Array_Data; |
| Element_Id : Array_Element_Id; |
| Element : Array_Element; |
| List : String_List_Id; |
| |
| begin |
| -- Process the associative array attribute of package Compiler |
| |
| Current_Array_Id := Arrays; |
| while Current_Array_Id /= No_Array loop |
| Current_Array := Shared.Arrays.Table (Current_Array_Id); |
| |
| Element_Id := Current_Array.Value; |
| while Element_Id /= No_Array_Element loop |
| Element := Shared.Array_Elements.Table (Element_Id); |
| |
| if Element.Index /= All_Other_Names then |
| |
| -- Get the name of the language |
| |
| Lang_Index := Get_Language_From_Name |
| (Project, Get_Name_String (Element.Index)); |
| |
| if Lang_Index /= No_Language_Index then |
| case Current_Array.Name is |
| |
| -- Attribute Dependency_Kind (<language>) |
| |
| when Name_Dependency_Kind => |
| Get_Name_String (Element.Value.Value); |
| |
| begin |
| Lang_Index.Config.Dependency_Kind := |
| Dependency_File_Kind'Value |
| (Name_Buffer (1 .. Name_Len)); |
| |
| exception |
| when Constraint_Error => |
| Error_Msg |
| (Data.Flags, |
| "illegal value for Dependency_Kind", |
| Element.Value.Location, |
| Project); |
| end; |
| |
| -- Attribute Dependency_Switches (<language>) |
| |
| when Name_Dependency_Switches => |
| if Lang_Index.Config.Dependency_Kind = None then |
| Lang_Index.Config.Dependency_Kind := Makefile; |
| end if; |
| |
| List := Element.Value.Values; |
| |
| if List /= Nil_String then |
| Put (Into_List => |
| Lang_Index.Config.Dependency_Option, |
| From_List => List, |
| In_Tree => Data.Tree); |
| end if; |
| |
| -- Attribute Dependency_Driver (<language>) |
| |
| when Name_Dependency_Driver => |
| if Lang_Index.Config.Dependency_Kind = None then |
| Lang_Index.Config.Dependency_Kind := Makefile; |
| end if; |
| |
| List := Element.Value.Values; |
| |
| if List /= Nil_String then |
| Put (Into_List => |
| Lang_Index.Config.Compute_Dependency, |
| From_List => List, |
| In_Tree => Data.Tree); |
| end if; |
| |
| -- Attribute Language_Kind (<language>) |
| |
| when Name_Language_Kind => |
| Get_Name_String (Element.Value.Value); |
| |
| begin |
| Lang_Index.Config.Kind := |
| Language_Kind'Value |
| (Name_Buffer (1 .. Name_Len)); |
| |
| exception |
| when Constraint_Error => |
| Error_Msg |
| (Data.Flags, |
| "illegal value for Language_Kind", |
| Element.Value.Location, |
| Project); |
| end; |
| |
| -- Attribute Include_Switches (<language>) |
| |
| when Name_Include_Switches => |
| List := Element.Value.Values; |
| |
| if List = Nil_String then |
| Error_Msg |
| (Data.Flags, "include option cannot be null", |
| Element.Value.Location, Project); |
| end if; |
| |
| Put (Into_List => Lang_Index.Config.Include_Option, |
| From_List => List, |
| In_Tree => Data.Tree); |
| |
| -- Attribute Include_Path (<language>) |
| |
| when Name_Include_Path => |
| Lang_Index.Config.Include_Path := |
| Element.Value.Value; |
| |
| -- Attribute Include_Path_File (<language>) |
| |
| when Name_Include_Path_File => |
| Lang_Index.Config.Include_Path_File := |
| Element.Value.Value; |
| |
| -- Attribute Driver (<language>) |
| |
| when Name_Driver => |
| Lang_Index.Config.Compiler_Driver := |
| File_Name_Type (Element.Value.Value); |
| |
| when Name_Required_Switches |
| | Name_Leading_Required_Switches |
| => |
| Put (Into_List => |
| Lang_Index.Config. |
| Compiler_Leading_Required_Switches, |
| From_List => Element.Value.Values, |
| In_Tree => Data.Tree); |
| |
| when Name_Trailing_Required_Switches => |
| Put (Into_List => |
| Lang_Index.Config. |
| Compiler_Trailing_Required_Switches, |
| From_List => Element.Value.Values, |
| In_Tree => Data.Tree); |
| |
| when Name_Multi_Unit_Switches => |
| Put (Into_List => |
| Lang_Index.Config.Multi_Unit_Switches, |
| From_List => Element.Value.Values, |
| In_Tree => Data.Tree); |
| |
| when Name_Multi_Unit_Object_Separator => |
| Get_Name_String (Element.Value.Value); |
| |
| if Name_Len /= 1 then |
| Error_Msg |
| (Data.Flags, |
| "multi-unit object separator must have " & |
| "a single character", |
| Element.Value.Location, Project); |
| |
| elsif Name_Buffer (1) = ' ' then |
| Error_Msg |
| (Data.Flags, |
| "multi-unit object separator cannot be " & |
| "a space", |
| Element.Value.Location, Project); |
| |
| else |
| Lang_Index.Config.Multi_Unit_Object_Separator := |
| Name_Buffer (1); |
| end if; |
| |
| when Name_Path_Syntax => |
| begin |
| Lang_Index.Config.Path_Syntax := |
| Path_Syntax_Kind'Value |
| (Get_Name_String (Element.Value.Value)); |
| |
| exception |
| when Constraint_Error => |
| Error_Msg |
| (Data.Flags, |
| "invalid value for Path_Syntax", |
| Element.Value.Location, Project); |
| end; |
| |
| when Name_Source_File_Switches => |
| Put (Into_List => |
| Lang_Index.Config.Source_File_Switches, |
| From_List => Element.Value.Values, |
| In_Tree => Data.Tree); |
| |
| when Name_Object_File_Suffix => |
| if Get_Name_String (Element.Value.Value) = "" then |
| Error_Msg |
| (Data.Flags, |
| "object file suffix cannot be empty", |
| Element.Value.Location, Project); |
| |
| else |
| Lang_Index.Config.Object_File_Suffix := |
| Element.Value.Value; |
| end if; |
| |
| when Name_Object_File_Switches => |
| Put (Into_List => |
| Lang_Index.Config.Object_File_Switches, |
| From_List => Element.Value.Values, |
| In_Tree => Data.Tree); |
| |
| when Name_Object_Path_Switches => |
| Put (Into_List => |
| Lang_Index.Config.Object_Path_Switches, |
| From_List => Element.Value.Values, |
| In_Tree => Data.Tree); |
| |
| -- Attribute Compiler_Pic_Option (<language>) |
| |
| when Name_Pic_Option => |
| List := Element.Value.Values; |
| |
| if List = Nil_String then |
| Error_Msg |
| (Data.Flags, |
| "compiler PIC option cannot be null", |
| Element.Value.Location, Project); |
| end if; |
| |
| Put (Into_List => |
| Lang_Index.Config.Compilation_PIC_Option, |
| From_List => List, |
| In_Tree => Data.Tree); |
| |
| -- Attribute Mapping_File_Switches (<language>) |
| |
| when Name_Mapping_File_Switches => |
| List := Element.Value.Values; |
| |
| if List = Nil_String then |
| Error_Msg |
| (Data.Flags, |
| "mapping file switches cannot be null", |
| Element.Value.Location, Project); |
| end if; |
| |
| Put (Into_List => |
| Lang_Index.Config.Mapping_File_Switches, |
| From_List => List, |
| In_Tree => Data.Tree); |
| |
| -- Attribute Mapping_Spec_Suffix (<language>) |
| |
| when Name_Mapping_Spec_Suffix => |
| Lang_Index.Config.Mapping_Spec_Suffix := |
| File_Name_Type (Element.Value.Value); |
| |
| -- Attribute Mapping_Body_Suffix (<language>) |
| |
| when Name_Mapping_Body_Suffix => |
| Lang_Index.Config.Mapping_Body_Suffix := |
| File_Name_Type (Element.Value.Value); |
| |
| -- Attribute Config_File_Switches (<language>) |
| |
| when Name_Config_File_Switches => |
| List := Element.Value.Values; |
| |
| if List = Nil_String then |
| Error_Msg |
| (Data.Flags, |
| "config file switches cannot be null", |
| Element.Value.Location, Project); |
| end if; |
| |
| Put (Into_List => |
| Lang_Index.Config.Config_File_Switches, |
| From_List => List, |
| In_Tree => Data.Tree); |
| |
| -- Attribute Objects_Path (<language>) |
| |
| when Name_Objects_Path => |
| Lang_Index.Config.Objects_Path := |
| Element.Value.Value; |
| |
| -- Attribute Objects_Path_File (<language>) |
| |
| when Name_Objects_Path_File => |
| Lang_Index.Config.Objects_Path_File := |
| Element.Value.Value; |
| |
| -- Attribute Config_Body_File_Name (<language>) |
| |
| when Name_Config_Body_File_Name => |
| Lang_Index.Config.Config_Body := |
| Element.Value.Value; |
| |
| -- Attribute Config_Body_File_Name_Index (< Language>) |
| |
| when Name_Config_Body_File_Name_Index => |
| Lang_Index.Config.Config_Body_Index := |
| Element.Value.Value; |
| |
| -- Attribute Config_Body_File_Name_Pattern(<language>) |
| |
| when Name_Config_Body_File_Name_Pattern => |
| Lang_Index.Config.Config_Body_Pattern := |
| Element.Value.Value; |
| |
| -- Attribute Config_Spec_File_Name (<language>) |
| |
| when Name_Config_Spec_File_Name => |
| Lang_Index.Config.Config_Spec := |
| Element.Value.Value; |
| |
| -- Attribute Config_Spec_File_Name_Index (<language>) |
| |
| when Name_Config_Spec_File_Name_Index => |
| Lang_Index.Config.Config_Spec_Index := |
| Element.Value.Value; |
| |
| -- Attribute Config_Spec_File_Name_Pattern(<language>) |
| |
| when Name_Config_Spec_File_Name_Pattern => |
| Lang_Index.Config.Config_Spec_Pattern := |
| Element.Value.Value; |
| |
| -- Attribute Config_File_Unique (<language>) |
| |
| when Name_Config_File_Unique => |
| begin |
| Lang_Index.Config.Config_File_Unique := |
| Boolean'Value |
| (Get_Name_String (Element.Value.Value)); |
| exception |
| when Constraint_Error => |
| Error_Msg |
| (Data.Flags, |
| "illegal value for Config_File_Unique", |
| Element.Value.Location, Project); |
| end; |
| |
| when others => |
| null; |
| end case; |
| end if; |
| end if; |
| |
| Element_Id := Element.Next; |
| end loop; |
| |
| Current_Array_Id := Current_Array.Next; |
| end loop; |
| end Process_Compiler; |
| |
| -------------------- |
| -- Process_Naming -- |
| -------------------- |
| |
| procedure Process_Naming (Attributes : Variable_Id) is |
| Attribute_Id : Variable_Id; |
| Attribute : Variable; |
| |
| begin |
| -- Process non associated array attribute from package Naming |
| |
| Attribute_Id := Attributes; |
| while Attribute_Id /= No_Variable loop |
| Attribute := Shared.Variable_Elements.Table (Attribute_Id); |
| |
| if not Attribute.Value.Default then |
| if Attribute.Name = Name_Separate_Suffix then |
| |
| -- Attribute Separate_Suffix |
| |
| Get_Name_String (Attribute.Value.Value); |
| Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); |
| Separate_Suffix := Name_Find; |
| |
| elsif Attribute.Name = Name_Casing then |
| |
| -- Attribute Casing |
| |
| begin |
| Casing := |
| Value (Get_Name_String (Attribute.Value.Value)); |
| |
| exception |
| when Constraint_Error => |
| Error_Msg |
| (Data.Flags, |
| "invalid value for Casing", |
| Attribute.Value.Location, Project); |
| end; |
| |
| elsif Attribute.Name = Name_Dot_Replacement then |
| |
| -- Attribute Dot_Replacement |
| |
| Dot_Replacement := File_Name_Type (Attribute.Value.Value); |
| |
| end if; |
| end if; |
| |
| Attribute_Id := Attribute.Next; |
| end loop; |
| end Process_Naming; |
| |
| procedure Process_Naming (Arrays : Array_Id) is |
| Current_Array_Id : Array_Id; |
| Current_Array : Array_Data; |
| Element_Id : Array_Element_Id; |
| Element : Array_Element; |
| |
| begin |
| -- Process the associative array attribute of package Naming |
| |
| Current_Array_Id := Arrays; |
| while Current_Array_Id /= No_Array loop |
| Current_Array := Shared.Arrays.Table (Current_Array_Id); |
| |
| Element_Id := Current_Array.Value; |
| while Element_Id /= No_Array_Element loop |
| Element := Shared.Array_Elements.Table (Element_Id); |
| |
| -- Get the name of the language |
| |
| Lang_Index := Get_Language_From_Name |
| (Project, Get_Name_String (Element.Index)); |
| |
| if Lang_Index /= No_Language_Index then |
| case Current_Array.Name is |
| when Name_Spec_Suffix | Name_Specification_Suffix => |
| |
| -- Attribute Spec_Suffix (<language>) |
| |
| Get_Name_String (Element.Value.Value); |
| Canonical_Case_File_Name |
| (Name_Buffer (1 .. Name_Len)); |
| Lang_Index.Config.Naming_Data.Spec_Suffix := |
| Name_Find; |
| |
| when Name_Implementation_Suffix | Name_Body_Suffix => |
| |
| Get_Name_String (Element.Value.Value); |
| Canonical_Case_File_Name |
| (Name_Buffer (1 .. Name_Len)); |
| |
| -- Attribute Body_Suffix (<language>) |
| |
| Lang_Index.Config.Naming_Data.Body_Suffix := |
| Name_Find; |
| Lang_Index.Config.Naming_Data.Separate_Suffix := |
| Lang_Index.Config.Naming_Data.Body_Suffix; |
| |
| when others => |
| null; |
| end case; |
| end if; |
| |
| Element_Id := Element.Next; |
| end loop; |
| |
| Current_Array_Id := Current_Array.Next; |
| end loop; |
| end Process_Naming; |
| |
| -------------------- |
| -- Process_Linker -- |
| -------------------- |
| |
| procedure Process_Linker (Attributes : Variable_Id) is |
| Attribute_Id : Variable_Id; |
| Attribute : Variable; |
| |
| begin |
| -- Process non associated array attribute from package Linker |
| |
| Attribute_Id := Attributes; |
| while Attribute_Id /= No_Variable loop |
| Attribute := Shared.Variable_Elements.Table (Attribute_Id); |
| |
| if not Attribute.Value.Default then |
| if Attribute.Name = Name_Driver then |
| |
| -- Attribute Linker'Driver: the default linker to use |
| |
| Project.Config.Linker := |
| Path_Name_Type (Attribute.Value.Value); |
| |
| -- Linker'Driver is also used to link shared libraries |
| -- if the obsolescent attribute Library_GCC has not been |
| -- specified. |
| |
| if Project.Config.Shared_Lib_Driver = No_File then |
| Project.Config.Shared_Lib_Driver := |
| File_Name_Type (Attribute.Value.Value); |
| end if; |
| |
| elsif Attribute.Name = Name_Required_Switches then |
| |
| -- Attribute Required_Switches: the minimum trailing |
| -- options to use when invoking the linker |
| |
| Put (Into_List => |
| Project.Config.Trailing_Linker_Required_Switches, |
| From_List => Attribute.Value.Values, |
| In_Tree => Data.Tree); |
| |
| elsif Attribute.Name = Name_Map_File_Option then |
| Project.Config.Map_File_Option := Attribute.Value.Value; |
| |
| elsif Attribute.Name = Name_Max_Command_Line_Length then |
| begin |
| Project.Config.Max_Command_Line_Length := |
| Natural'Value (Get_Name_String |
| (Attribute.Value.Value)); |
| |
| exception |
| when Constraint_Error => |
| Error_Msg |
| (Data.Flags, |
| "value must be positive or equal to 0", |
| Attribute.Value.Location, Project); |
| end; |
| |
| elsif Attribute.Name = Name_Response_File_Format then |
| declare |
| Name : Name_Id; |
| |
| begin |
| Get_Name_String (Attribute.Value.Value); |
| To_Lower (Name_Buffer (1 .. Name_Len)); |
| Name := Name_Find; |
| |
| if Name = Name_None then |
| Project.Config.Resp_File_Format := None; |
| |
| elsif Name = Name_Gnu then |
| Project.Config.Resp_File_Format := GNU; |
| |
| elsif Name = Name_Object_List then |
| Project.Config.Resp_File_Format := Object_List; |
| |
| elsif Name = Name_Option_List then |
| Project.Config.Resp_File_Format := Option_List; |
| |
| elsif Name_Buffer (1 .. Name_Len) = "gcc" then |
| Project.Config.Resp_File_Format := GCC; |
| |
| elsif Name_Buffer (1 .. Name_Len) = "gcc_gnu" then |
| Project.Config.Resp_File_Format := GCC_GNU; |
| |
| elsif |
| Name_Buffer (1 .. Name_Len) = "gcc_option_list" |
| then |
| Project.Config.Resp_File_Format := GCC_Option_List; |
| |
| elsif |
| Name_Buffer (1 .. Name_Len) = "gcc_object_list" |
| then |
| Project.Config.Resp_File_Format := GCC_Object_List; |
| |
| else |
| Error_Msg |
| (Data.Flags, |
| "illegal response file format", |
| Attribute.Value.Location, Project); |
| end if; |
| end; |
| |
| elsif Attribute.Name = Name_Response_File_Switches then |
| Put (Into_List => Project.Config.Resp_File_Options, |
| From_List => Attribute.Value.Values, |
| In_Tree => Data.Tree); |
| end if; |
| end if; |
| |
| Attribute_Id := Attribute.Next; |
| end loop; |
| end Process_Linker; |
| |
| -- Start of processing for Process_Packages |
| |
| begin |
| Packages := Project.Decl.Packages; |
| while Packages /= No_Package loop |
| Element := Shared.Packages.Table (Packages); |
| |
| case Element.Name is |
| when Name_Binder => |
| |
| -- Process attributes of package Binder |
| |
| Process_Binder (Element.Decl.Arrays); |
| |
| when Name_Builder => |
| |
| -- Process attributes of package Builder |
| |
| Process_Builder (Element.Decl.Attributes); |
| |
| when Name_Clean => |
| |
| -- Process attributes of package Clean |
| |
| Process_Clean (Element.Decl.Arrays); |
| |
| when Name_Compiler => |
| |
| -- Process attributes of package Compiler |
| |
| Process_Compiler (Element.Decl.Arrays); |
| |
| when Name_Linker => |
| |
| -- Process attributes of package Linker |
| |
| Process_Linker (Element.Decl.Attributes); |
| |
| when Name_Naming => |
| |
| -- Process attributes of package Naming |
| |
| Process_Naming (Element.Decl.Attributes); |
| Process_Naming (Element.Decl.Arrays); |
| |
| when others => |
| null; |
| end case; |
| |
| Packages := Element.Next; |
| end loop; |
| end Process_Packages; |
| |
| --------------------------------------------- |
| -- Process_Project_Level_Simple_Attributes -- |
| --------------------------------------------- |
| |
| procedure Process_Project_Level_Simple_Attributes is |
| Attribute_Id : Variable_Id; |
| Attribute : Variable; |
| List : String_List_Id; |
| |
| begin |
| -- Process non associated array attribute at project level |
| |
| Attribute_Id := Project.Decl.Attributes; |
| while Attribute_Id /= No_Variable loop |
| Attribute := Shared.Variable_Elements.Table (Attribute_Id); |
| |
| if not Attribute.Value.Default then |
| if Attribute.Name = Name_Target then |
| |
| -- Attribute Target: the target specified |
| |
| Project.Config.Target := Attribute.Value.Value; |
| |
| elsif Attribute.Name = Name_Library_Builder then |
| |
| -- Attribute Library_Builder: the application to invoke |
| -- to build libraries. |
| |
| Project.Config.Library_Builder := |
| Path_Name_Type (Attribute.Value.Value); |
| |
| elsif Attribute.Name = Name_Archive_Builder then |
| |
| -- Attribute Archive_Builder: the archive builder |
| -- (usually "ar") and its minimum options (usually "cr"). |
| |
| List := Attribute.Value.Values; |
| |
| if List = Nil_String then |
| Error_Msg |
| (Data.Flags, |
| "archive builder cannot be null", |
| Attribute.Value.Location, Project); |
| end if; |
| |
| Put (Into_List => Project.Config.Archive_Builder, |
| From_List => List, |
| In_Tree => Data.Tree); |
| |
| elsif Attribute.Name = Name_Archive_Builder_Append_Option then |
| |
| -- Attribute Archive_Builder: the archive builder |
| -- (usually "ar") and its minimum options (usually "cr"). |
| |
| List := Attribute.Value.Values; |
| |
| if List /= Nil_String then |
| Put |
| (Into_List => |
| Project.Config.Archive_Builder_Append_Option, |
| From_List => List, |
| In_Tree => Data.Tree); |
| end if; |
| |
| elsif Attribute.Name = Name_Archive_Indexer then |
| |
| -- Attribute Archive_Indexer: the optional archive |
| -- indexer (usually "ranlib") with its minimum options |
| -- (usually none). |
| |
| List := Attribute.Value.Values; |
| |
| if List = Nil_String then |
| Error_Msg |
| (Data.Flags, |
| "archive indexer cannot be null", |
| Attribute.Value.Location, Project); |
| end if; |
| |
| Put (Into_List => Project.Config.Archive_Indexer, |
| From_List => List, |
| In_Tree => Data.Tree); |
| |
| elsif Attribute.Name = Name_Library_Partial_Linker then |
| |
| -- Attribute Library_Partial_Linker: the optional linker |
| -- driver with its minimum options, to partially link |
| -- archives. |
| |
| List := Attribute.Value.Values; |
| |
| if List = Nil_String then |
| Error_Msg |
| (Data.Flags, |
| "partial linker cannot be null", |
| Attribute.Value.Location, Project); |
| end if; |
| |
| Put (Into_List => Project.Config.Lib_Partial_Linker, |
| From_List => List, |
| In_Tree => Data.Tree); |
| |
| elsif Attribute.Name = Name_Library_GCC then |
| Project.Config.Shared_Lib_Driver := |
| File_Name_Type (Attribute.Value.Value); |
| Error_Msg |
| (Data.Flags, |
| "?Library_'G'C'C is an obsolescent attribute, " & |
| "use Linker''Driver instead", |
| Attribute.Value.Location, Project); |
| |
| elsif Attribute.Name = Name_Archive_Suffix then |
| Project.Config.Archive_Suffix := |
| File_Name_Type (Attribute.Value.Value); |
| |
| elsif Attribute.Name = Name_Linker_Executable_Option then |
| |
| -- Attribute Linker_Executable_Option: optional options |
| -- to specify an executable name. Defaults to "-o". |
| |
| List := Attribute.Value.Values; |
| |
| if List = Nil_String then |
| Error_Msg |
| (Data.Flags, |
| "linker executable option cannot be null", |
| Attribute.Value.Location, Project); |
| end if; |
| |
| Put (Into_List => Project.Config.Linker_Executable_Option, |
| From_List => List, |
| In_Tree => Data.Tree); |
| |
| elsif Attribute.Name = Name_Linker_Lib_Dir_Option then |
| |
| -- Attribute Linker_Lib_Dir_Option: optional options |
| -- to specify a library search directory. Defaults to |
| -- "-L". |
| |
| Get_Name_String (Attribute.Value.Value); |
| |
| if Name_Len = 0 then |
| Error_Msg |
| (Data.Flags, |
| "linker library directory option cannot be empty", |
| Attribute.Value.Location, Project); |
| end if; |
| |
| Project.Config.Linker_Lib_Dir_Option := |
| Attribute.Value.Value; |
| |
| elsif Attribute.Name = Name_Linker_Lib_Name_Option then |
| |
| -- Attribute Linker_Lib_Name_Option: optional options |
| -- to specify the name of a library to be linked in. |
| -- Defaults to "-l". |
| |
| Get_Name_String (Attribute.Value.Value); |
| |
| if Name_Len = 0 then |
| Error_Msg |
| (Data.Flags, |
| "linker library name option cannot be empty", |
| Attribute.Value.Location, Project); |
| end if; |
| |
| Project.Config.Linker_Lib_Name_Option := |
| Attribute.Value.Value; |
| |
| elsif Attribute.Name = Name_Run_Path_Option then |
| |
| -- Attribute Run_Path_Option: optional options to |
| -- specify a path for libraries. |
| |
| List := Attribute.Value.Values; |
| |
| if List /= Nil_String then |
| Put (Into_List => Project.Config.Run_Path_Option, |
| From_List => List, |
| In_Tree => Data.Tree); |
| end if; |
| |
| elsif Attribute.Name = Name_Run_Path_Origin then |
| Get_Name_String (Attribute.Value.Value); |
| |
| if Name_Len = 0 then |
| Error_Msg |
| (Data.Flags, |
| "run path origin cannot be empty", |
| Attribute.Value.Location, Project); |
| end if; |
| |
| Project.Config.Run_Path_Origin := Attribute.Value.Value; |
| |
| elsif Attribute.Name = Name_Library_Install_Name_Option then |
| Project.Config.Library_Install_Name_Option := |
| Attribute.Value.Value; |
| |
| elsif Attribute.Name = Name_Separate_Run_Path_Options then |
| declare |
| pragma Unsuppress (All_Checks); |
| begin |
| Project.Config.Separate_Run_Path_Options := |
| Boolean'Value (Get_Name_String (Attribute.Value.Value)); |
| exception |
| when Constraint_Error => |
| Error_Msg |
| (Data.Flags, |
| "invalid value """ & |
| Get_Name_String (Attribute.Value.Value) & |
| """ for Separate_Run_Path_Options", |
| Attribute.Value.Location, Project); |
| end; |
| |
| elsif Attribute.Name = Name_Library_Support then |
| declare |
| pragma Unsuppress (All_Checks); |
| begin |
| Project.Config.Lib_Support := |
| Library_Support'Value (Get_Name_String |
| (Attribute.Value.Value)); |
| exception |
| when Constraint_Error => |
| Error_Msg |
| (Data.Flags, |
| "invalid value """ & |
| Get_Name_String (Attribute.Value.Value) & |
| """ for Library_Support", |
| Attribute.Value.Location, Project); |
| end; |
| |
| elsif |
| Attribute.Name = Name_Library_Encapsulated_Supported |
| then |
| declare |
| pragma Unsuppress (All_Checks); |
| begin |
| Project.Config.Lib_Encapsulated_Supported := |
| Boolean'Value (Get_Name_String (Attribute.Value.Value)); |
| exception |
| when Constraint_Error => |
| Error_Msg |
| (Data.Flags, |
| "invalid value """ |
| & Get_Name_String (Attribute.Value.Value) |
| & """ for Library_Encapsulated_Supported", |
| Attribute.Value.Location, Project); |
| end; |
| |
| elsif Attribute.Name = Name_Shared_Library_Prefix then |
| Project.Config.Shared_Lib_Prefix := |
| File_Name_Type (Attribute.Value.Value); |
| |
| elsif Attribute.Name = Name_Shared_Library_Suffix then |
| Project.Config.Shared_Lib_Suffix := |
| File_Name_Type (Attribute.Value.Value); |
| |
| elsif Attribute.Name = Name_Symbolic_Link_Supported then |
| declare |
| pragma Unsuppress (All_Checks); |
| begin |
| Project.Config.Symbolic_Link_Supported := |
| Boolean'Value (Get_Name_String |
| (Attribute.Value.Value)); |
| exception |
| when Constraint_Error => |
| Error_Msg |
| (Data.Flags, |
| "invalid value """ |
| & Get_Name_String (Attribute.Value.Value) |
| & """ for Symbolic_Link_Supported", |
| Attribute.Value.Location, Project); |
| end; |
| |
| elsif |
| Attribute.Name = Name_Library_Major_Minor_Id_Supported |
| then |
| declare |
| pragma Unsuppress (All_Checks); |
| begin |
| Project.Config.Lib_Maj_Min_Id_Supported := |
| Boolean'Value (Get_Name_String |
| (Attribute.Value.Value)); |
| exception |
| when Constraint_Error => |
| Error_Msg |
| (Data.Flags, |
| "invalid value """ & |
| Get_Name_String (Attribute.Value.Value) & |
| """ for Library_Major_Minor_Id_Supported", |
| Attribute.Value.Location, Project); |
| end; |
| |
| elsif Attribute.Name = Name_Library_Auto_Init_Supported then |
| declare |
| pragma Unsuppress (All_Checks); |
| begin |
| Project.Config.Auto_Init_Supported := |
| Boolean'Value (Get_Name_String (Attribute.Value.Value)); |
| exception |
| when Constraint_Error => |
| Error_Msg |
| (Data.Flags, |
| "invalid value """ |
| & Get_Name_String (Attribute.Value.Value) |
| & """ for Library_Auto_Init_Supported", |
| Attribute.Value.Location, Project); |
| end; |
| |
| elsif Attribute.Name = Name_Shared_Library_Minimum_Switches then |
| List := Attribute.Value.Values; |
| |
| if List /= Nil_String then |
| Put (Into_List => Project.Config.Shared_Lib_Min_Options, |
| From_List => List, |
| In_Tree => Data.Tree); |
| end if; |
| |
| elsif Attribute.Name = Name_Library_Version_Switches then |
| List := Attribute.Value.Values; |
| |
| if List /= Nil_String then |
| Put (Into_List => Project.Config.Lib_Version_Options, |
| From_List => List, |
| In_Tree => Data.Tree); |
| end if; |
| end if; |
| end if; |
| |
| Attribute_Id := Attribute.Next; |
| end loop; |
| end Process_Project_Level_Simple_Attributes; |
| |
| -------------------------------------------- |
| -- Process_Project_Level_Array_Attributes -- |
| -------------------------------------------- |
| |
| procedure Process_Project_Level_Array_Attributes is |
| Current_Array_Id : Array_Id; |
| Current_Array : Array_Data; |
| Element_Id : Array_Element_Id; |
| Element : Array_Element; |
| List : String_List_Id; |
| |
| begin |
| -- Process the associative array attributes at project level |
| |
| Current_Array_Id := Project.Decl.Arrays; |
| while Current_Array_Id /= No_Array loop |
| Current_Array := Shared.Arrays.Table (Current_Array_Id); |
| |
| Element_Id := Current_Array.Value; |
| while Element_Id /= No_Array_Element loop |
| Element := Shared.Array_Elements.Table (Element_Id); |
| |
| -- Get the name of the language |
| |
| Lang_Index := |
| Get_Language_From_Name |
| (Project, Get_Name_String (Element.Index)); |
| |
| if Lang_Index /= No_Language_Index then |
| case Current_Array.Name is |
| when Name_Inherit_Source_Path => |
| List := Element.Value.Values; |
| |
| if List /= Nil_String then |
| Put |
| (Into_List => |
| Lang_Index.Config.Include_Compatible_Languages, |
| From_List => List, |
| In_Tree => Data.Tree, |
| Lower_Case => True); |
| end if; |
| |
| when Name_Toolchain_Description => |
| |
| -- Attribute Toolchain_Description (<language>) |
| |
| Lang_Index.Config.Toolchain_Description := |
| Element.Value.Value; |
| |
| when Name_Toolchain_Version => |
| |
| -- Attribute Toolchain_Version (<language>) |
| |
| Lang_Index.Config.Toolchain_Version := |
| Element.Value.Value; |
| |
| -- For Ada, set proper checksum computation mode |
| |
| if Lang_Index.Name = Name_Ada then |
| declare |
| Vers : constant String := |
| Get_Name_String (Element.Value.Value); |
| pragma Assert (Vers'First = 1); |
| |
| begin |
| -- Version 6.3 or earlier |
| |
| if Vers'Length >= 8 |
| and then Vers (1 .. 5) = "GNAT " |
| and then Vers (7) = '.' |
| and then |
| (Vers (6) < '6' |
| or else |
| (Vers (6) = '6' and then Vers (8) < '4')) |
| then |
| Checksum_GNAT_6_3 := True; |
| |
| -- Version 5.03 or earlier |
| |
| if Vers (6) < '5' |
| or else (Vers (6) = '5' |
| and then Vers (Vers'Last) < '4') |
| then |
| Checksum_GNAT_5_03 := True; |
| |
| -- Version 5.02 or earlier |
| |
| if Vers (6) /= '5' |
| or else Vers (Vers'Last) < '3' |
| then |
| Checksum_Accumulate_Token_Checksum := |
| False; |
| end if; |
| end if; |
| end if; |
| end; |
| end if; |
| |
| when Name_Runtime_Library_Dir => |
| |
| -- Attribute Runtime_Library_Dir (<language>) |
| |
| Lang_Index.Config.Runtime_Library_Dir := |
| Element.Value.Value; |
| |
| when Name_Runtime_Source_Dir => |
| |
| -- Attribute Runtime_Source_Dir (<language>) |
| |
| Lang_Index.Config.Runtime_Source_Dir := |
| Element.Value.Value; |
| |
| when Name_Object_Generated => |
| declare |
| pragma Unsuppress (All_Checks); |
| Value : Boolean; |
| |
| begin |
| Value := |
| Boolean'Value |
| (Get_Name_String (Element.Value.Value)); |
| |
| Lang_Index.Config.Object_Generated := Value; |
| |
| -- If no object is generated, no object may be |
| -- linked. |
| |
| if not Value then |
| Lang_Index.Config.Objects_Linked := False; |
| end if; |
| |
| exception |
| when Constraint_Error => |
| Error_Msg |
| (Data.Flags, |
| "invalid value """ |
| & Get_Name_String (Element.Value.Value) |
| & """ for Object_Generated", |
| Element.Value.Location, Project); |
| end; |
| |
| when Name_Objects_Linked => |
| declare |
| pragma Unsuppress (All_Checks); |
| Value : Boolean; |
| |
| begin |
| Value := |
| Boolean'Value |
| (Get_Name_String (Element.Value.Value)); |
| |
| -- No change if Object_Generated is False, as this |
| -- forces Objects_Linked to be False too. |
| |
| if Lang_Index.Config.Object_Generated then |
| Lang_Index.Config.Objects_Linked := Value; |
| end if; |
| |
| exception |
| when Constraint_Error => |
| Error_Msg |
| (Data.Flags, |
| "invalid value """ |
| & Get_Name_String (Element.Value.Value) |
| & """ for Objects_Linked", |
| Element.Value.Location, Project); |
| end; |
| when others => |
| null; |
| end case; |
| end if; |
| |
| Element_Id := Element.Next; |
| end loop; |
| |
| Current_Array_Id := Current_Array.Next; |
| end loop; |
| end Process_Project_Level_Array_Attributes; |
| |
| -- Start of processing for Check_Configuration |
| |
| begin |
| Process_Project_Level_Simple_Attributes; |
| Process_Project_Level_Array_Attributes; |
| Process_Packages; |
| |
| -- For unit based languages, set Casing, Dot_Replacement and |
| -- Separate_Suffix in Naming_Data. |
| |
| Lang_Index := Project.Languages; |
| while Lang_Index /= No_Language_Index loop |
| if Lang_Index.Config.Kind = Unit_Based then |
| Lang_Index.Config.Naming_Data.Casing := Casing; |
| Lang_Index.Config.Naming_Data.Dot_Replacement := Dot_Replacement; |
| |
| if Separate_Suffix /= No_File then |
| Lang_Index.Config.Naming_Data.Separate_Suffix := |
| Separate_Suffix; |
| end if; |
| |
| exit; |
| end if; |
| |
| Lang_Index := Lang_Index.Next; |
| end loop; |
| |
| -- Give empty names to various prefixes/suffixes, if they have not |
| -- been specified in the configuration. |
| |
| if Project.Config.Archive_Suffix = No_File then |
| Project.Config.Archive_Suffix := Empty_File; |
| end if; |
| |
| if Project.Config.Shared_Lib_Prefix = No_File then |
| Project.Config.Shared_Lib_Prefix := Empty_File; |
| end if; |
| |
| if Project.Config.Shared_Lib_Suffix = No_File then |
| Project.Config.Shared_Lib_Suffix := Empty_File; |
| end if; |
| |
| Lang_Index := Project.Languages; |
| while Lang_Index /= No_Language_Index loop |
| |
| -- For all languages, Compiler_Driver needs to be specified. This is |
| -- only needed if we do intend to compile (not in GPS for instance). |
| |
| if Data.Flags.Compiler_Driver_Mandatory |
| and then Lang_Index.Config.Compiler_Driver = No_File |
| then |
| Error_Msg_Name_1 := Lang_Index.Display_Name; |
| Error_Msg |
| (Data.Flags, |
| "?no compiler specified for language %%" & |
| ", ignoring all its sources", |
| No_Location, Project); |
| |
| if Lang_Index = Project.Languages then |
| Project.Languages := Lang_Index.Next; |
| else |
| Prev_Index.Next := Lang_Index.Next; |
| end if; |
| |
| elsif Lang_Index.Config.Kind = Unit_Based then |
| Prev_Index := Lang_Index; |
| |
| -- For unit based languages, Dot_Replacement, Spec_Suffix and |
| -- Body_Suffix need to be specified. |
| |
| if Lang_Index.Config.Naming_Data.Dot_Replacement = No_File then |
| Error_Msg |
| (Data.Flags, |
| "Dot_Replacement not specified for " & |
| Get_Name_String (Lang_Index.Name), |
| No_Location, Project); |
| end if; |
| |
| if Lang_Index.Config.Naming_Data.Spec_Suffix = No_File then |
| Error_Msg |
| (Data.Flags, |
| "Spec_Suffix not specified for " & |
| Get_Name_String (Lang_Index.Name), |
| No_Location, Project); |
| end if; |
| |
| if Lang_Index.Config.Naming_Data.Body_Suffix = No_File then |
| Error_Msg |
| (Data.Flags, |
| "Body_Suffix not specified for " & |
| Get_Name_String (Lang_Index.Name), |
| No_Location, Project); |
| end if; |
| |
| else |
| Prev_Index := Lang_Index; |
| |
| -- For file based languages, either Spec_Suffix or Body_Suffix |
| -- need to be specified. |
| |
| if Data.Flags.Require_Sources_Other_Lang |
| and then Lang_Index.Config.Naming_Data.Spec_Suffix = No_File |
| and then Lang_Index.Config.Naming_Data.Body_Suffix = No_File |
| then |
| Error_Msg_Name_1 := Lang_Index.Display_Name; |
| Error_Msg |
| (Data.Flags, |
| "no suffixes specified for %%", |
| No_Location, Project); |
| end if; |
| end if; |
| |
| Lang_Index := Lang_Index.Next; |
| end loop; |
| end Check_Configuration; |
| |
| ------------------------------- |
| -- Check_If_Externally_Built -- |
| ------------------------------- |
| |
| procedure Check_If_Externally_Built |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data) |
| is |
| Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared; |
| Externally_Built : constant Variable_Value := |
| Util.Value_Of |
| (Name_Externally_Built, |
| Project.Decl.Attributes, Shared); |
| |
| begin |
| if not Externally_Built.Default then |
| Get_Name_String (Externally_Built.Value); |
| To_Lower (Name_Buffer (1 .. Name_Len)); |
| |
| if Name_Buffer (1 .. Name_Len) = "true" then |
| Project.Externally_Built := True; |
| |
| elsif Name_Buffer (1 .. Name_Len) /= "false" then |
| Error_Msg (Data.Flags, |
| "Externally_Built may only be true or false", |
| Externally_Built.Location, Project); |
| end if; |
| end if; |
| |
| -- A virtual project extending an externally built project is itself |
| -- externally built. |
| |
| if Project.Virtual and then Project.Extends /= No_Project then |
| Project.Externally_Built := Project.Extends.Externally_Built; |
| end if; |
| |
| if Project.Externally_Built then |
| Debug_Output ("project is externally built"); |
| else |
| Debug_Output ("project is not externally built"); |
| end if; |
| end Check_If_Externally_Built; |
| |
| ---------------------- |
| -- Check_Interfaces -- |
| ---------------------- |
| |
| procedure Check_Interfaces |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data) |
| is |
| Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared; |
| |
| Interfaces : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Interfaces, |
| Project.Decl.Attributes, |
| Shared); |
| |
| Library_Interface : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Library_Interface, |
| Project.Decl.Attributes, |
| Shared); |
| |
| List : String_List_Id; |
| Element : String_Element; |
| Name : File_Name_Type; |
| Iter : Source_Iterator; |
| Source : Source_Id; |
| Project_2 : Project_Id; |
| Other : Source_Id; |
| Unit_Found : Boolean; |
| |
| Interface_ALIs : String_List_Id := Nil_String; |
| |
| begin |
| if not Interfaces.Default then |
| |
| -- Set In_Interfaces to False for all sources. It will be set to True |
| -- later for the sources in the Interfaces list. |
| |
| Project_2 := Project; |
| while Project_2 /= No_Project loop |
| Iter := For_Each_Source (Data.Tree, Project_2); |
| loop |
| Source := Prj.Element (Iter); |
| exit when Source = No_Source; |
| Source.In_Interfaces := False; |
| Next (Iter); |
| end loop; |
| |
| Project_2 := Project_2.Extends; |
| end loop; |
| |
| List := Interfaces.Values; |
| while List /= Nil_String loop |
| Element := Shared.String_Elements.Table (List); |
| Name := Canonical_Case_File_Name (Element.Value); |
| |
| Project_2 := Project; |
| Big_Loop : while Project_2 /= No_Project loop |
| if Project.Qualifier = Aggregate_Library then |
| |
| -- For an aggregate library we want to consider sources of |
| -- all aggregated projects. |
| |
| Iter := For_Each_Source (Data.Tree); |
| |
| else |
| Iter := For_Each_Source (Data.Tree, Project_2); |
| end if; |
| |
| loop |
| Source := Prj.Element (Iter); |
| exit when Source = No_Source; |
| |
| if Source.File = Name then |
| if not Source.Locally_Removed then |
| Source.In_Interfaces := True; |
| Source.Declared_In_Interfaces := True; |
| |
| Other := Other_Part (Source); |
| |
| if Other /= No_Source then |
| Other.In_Interfaces := True; |
| Other.Declared_In_Interfaces := True; |
| end if; |
| |
| if Source.Language.Config.Kind = Unit_Based then |
| if Source.Kind = Spec |
| and then Other_Part (Source) /= No_Source |
| then |
| Source := Other_Part (Source); |
| end if; |
| |
| String_Element_Table.Increment_Last |
| (Shared.String_Elements); |
| |
| Shared.String_Elements.Table |
| (String_Element_Table.Last |
| (Shared.String_Elements)) := |
| (Value => Name_Id (Source.Dep_Name), |
| Index => 0, |
| Display_Value => Name_Id (Source.Dep_Name), |
| Location => No_Location, |
| Flag => False, |
| Next => Interface_ALIs); |
| |
| Interface_ALIs := |
| String_Element_Table.Last |
| (Shared.String_Elements); |
| end if; |
| |
| Debug_Output |
| ("interface: ", Name_Id (Source.Path.Name)); |
| end if; |
| |
| exit Big_Loop; |
| end if; |
| |
| Next (Iter); |
| end loop; |
| |
| Project_2 := Project_2.Extends; |
| end loop Big_Loop; |
| |
| if Source = No_Source then |
| Error_Msg_File_1 := File_Name_Type (Element.Value); |
| Error_Msg_Name_1 := Project.Name; |
| |
| Error_Msg |
| (Data.Flags, |
| "{ cannot be an interface of project %% " |
| & "as it is not one of its sources", |
| Element.Location, Project); |
| end if; |
| |
| List := Element.Next; |
| end loop; |
| |
| Project.Interfaces_Defined := True; |
| Project.Lib_Interface_ALIs := Interface_ALIs; |
| |
| elsif Project.Library and then not Library_Interface.Default then |
| |
| -- Set In_Interfaces to False for all sources. It will be set to True |
| -- later for the sources in the Library_Interface list. |
| |
| Project_2 := Project; |
| while Project_2 /= No_Project loop |
| Iter := For_Each_Source (Data.Tree, Project_2); |
| loop |
| Source := Prj.Element (Iter); |
| exit when Source = No_Source; |
| Source.In_Interfaces := False; |
| Next (Iter); |
| end loop; |
| |
| Project_2 := Project_2.Extends; |
| end loop; |
| |
| List := Library_Interface.Values; |
| while List /= Nil_String loop |
| Element := Shared.String_Elements.Table (List); |
| Get_Name_String (Element.Value); |
| To_Lower (Name_Buffer (1 .. Name_Len)); |
| Name := Name_Find; |
| Unit_Found := False; |
| |
| Project_2 := Project; |
| Big_Loop_2 : while Project_2 /= No_Project loop |
| if Project.Qualifier = Aggregate_Library then |
| |
| -- For an aggregate library we want to consider sources of |
| -- all aggregated projects. |
| |
| Iter := For_Each_Source (Data.Tree); |
| |
| else |
| Iter := For_Each_Source (Data.Tree, Project_2); |
| end if; |
| |
| loop |
| Source := Prj.Element (Iter); |
| exit when Source = No_Source; |
| |
| if Source.Unit /= No_Unit_Index |
| and then Source.Unit.Name = Name_Id (Name) |
| then |
| if not Source.Locally_Removed then |
| Source.In_Interfaces := True; |
| Source.Declared_In_Interfaces := True; |
| Project.Interfaces_Defined := True; |
| |
| Other := Other_Part (Source); |
| |
| if Other /= No_Source then |
| Other.In_Interfaces := True; |
| Other.Declared_In_Interfaces := True; |
| end if; |
| |
| Debug_Output |
| ("interface: ", Name_Id (Source.Path.Name)); |
| |
| if Source.Kind = Spec |
| and then Other_Part (Source) /= No_Source |
| then |
| Source := Other_Part (Source); |
| end if; |
| |
| String_Element_Table.Increment_Last |
| (Shared.String_Elements); |
| |
| Shared.String_Elements.Table |
| (String_Element_Table.Last |
| (Shared.String_Elements)) := |
| (Value => Name_Id (Source.Dep_Name), |
| Index => 0, |
| Display_Value => Name_Id (Source.Dep_Name), |
| Location => No_Location, |
| Flag => False, |
| Next => Interface_ALIs); |
| |
| Interface_ALIs := |
| String_Element_Table.Last (Shared.String_Elements); |
| end if; |
| |
| Unit_Found := True; |
| exit Big_Loop_2; |
| end if; |
| |
| Next (Iter); |
| end loop; |
| |
| Project_2 := Project_2.Extends; |
| end loop Big_Loop_2; |
| |
| if not Unit_Found then |
| Error_Msg_Name_1 := Name_Id (Name); |
| |
| Error_Msg |
| (Data.Flags, |
| "%% is not a unit of this project", |
| Element.Location, Project); |
| end if; |
| |
| List := Element.Next; |
| end loop; |
| |
| Project.Lib_Interface_ALIs := Interface_ALIs; |
| |
| elsif Project.Extends /= No_Project |
| and then Project.Extends.Interfaces_Defined |
| then |
| Project.Interfaces_Defined := True; |
| |
| Iter := For_Each_Source (Data.Tree, Project); |
| loop |
| Source := Prj.Element (Iter); |
| exit when Source = No_Source; |
| |
| if not Source.Declared_In_Interfaces then |
| Source.In_Interfaces := False; |
| end if; |
| |
| Next (Iter); |
| end loop; |
| |
| Project.Lib_Interface_ALIs := Project.Extends.Lib_Interface_ALIs; |
| end if; |
| end Check_Interfaces; |
| |
| ------------------------------ |
| -- Check_Library_Attributes -- |
| ------------------------------ |
| |
| -- This procedure is awfully long (over 700 lines) should be broken up??? |
| |
| procedure Check_Library_Attributes |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data) |
| is |
| Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared; |
| |
| Attributes : constant Prj.Variable_Id := Project.Decl.Attributes; |
| |
| Lib_Dir : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Library_Dir, Attributes, Shared); |
| |
| Lib_Name : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Library_Name, Attributes, Shared); |
| |
| Lib_Standalone : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Library_Standalone, |
| Attributes, Shared); |
| |
| Lib_Version : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Library_Version, Attributes, Shared); |
| |
| Lib_ALI_Dir : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Library_Ali_Dir, Attributes, Shared); |
| |
| Lib_GCC : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Library_GCC, Attributes, Shared); |
| |
| The_Lib_Kind : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Library_Kind, Attributes, Shared); |
| |
| Imported_Project_List : Project_List; |
| Continuation : String_Access := No_Continuation_String'Access; |
| Support_For_Libraries : Library_Support; |
| |
| Library_Directory_Present : Boolean; |
| |
| procedure Check_Library (Proj : Project_Id; Extends : Boolean); |
| -- Check if an imported or extended project if also a library project |
| |
| ------------------- |
| -- Check_Library -- |
| ------------------- |
| |
| procedure Check_Library (Proj : Project_Id; Extends : Boolean) is |
| Src_Id : Source_Id; |
| Iter : Source_Iterator; |
| |
| begin |
| if Proj /= No_Project then |
| if not Proj.Library then |
| |
| -- The only not library projects that are OK are those that |
| -- have no sources. However, header files from non-Ada |
| -- languages are OK, as there is nothing to compile. |
| |
| Iter := For_Each_Source (Data.Tree, Proj); |
| loop |
| Src_Id := Prj.Element (Iter); |
| exit when Src_Id = No_Source |
| or else Src_Id.Language.Config.Kind /= File_Based |
| or else Src_Id.Kind /= Spec; |
| Next (Iter); |
| end loop; |
| |
| if Src_Id /= No_Source then |
| Error_Msg_Name_1 := Project.Name; |
| Error_Msg_Name_2 := Proj.Name; |
| |
| if Extends then |
| if Project.Library_Kind /= Static then |
| Error_Msg |
| (Data.Flags, |
| Continuation.all & |
| "shared library project %% cannot extend " & |
| "project %% that is not a library project", |
| Project.Location, Project); |
| Continuation := Continuation_String'Access; |
| end if; |
| |
| elsif not Unchecked_Shared_Lib_Imports |
| and then Project.Library_Kind /= Static |
| then |
| Error_Msg |
| (Data.Flags, |
| Continuation.all & |
| "shared library project %% cannot import project %% " & |
| "that is not a shared library project", |
| Project.Location, Project); |
| Continuation := Continuation_String'Access; |
| end if; |
| end if; |
| |
| elsif Project.Library_Kind /= Static |
| and then not Lib_Standalone.Default |
| and then Get_Name_String (Lib_Standalone.Value) = "encapsulated" |
| and then Proj.Library_Kind /= Static |
| then |
| -- An encapsulated library must depend only on static libraries |
| |
| Error_Msg_Name_1 := Project.Name; |
| Error_Msg_Name_2 := Proj.Name; |
| |
| Error_Msg |
| (Data.Flags, |
| Continuation.all & |
| "encapsulated library project %% cannot import shared " & |
| "library project %%", |
| Project.Location, Project); |
| Continuation := Continuation_String'Access; |
| |
| elsif Project.Library_Kind /= Static |
| and then Proj.Library_Kind = Static |
| and then |
| (Lib_Standalone.Default |
| or else |
| Get_Name_String (Lib_Standalone.Value) /= "encapsulated") |
| then |
| Error_Msg_Name_1 := Project.Name; |
| Error_Msg_Name_2 := Proj.Name; |
| |
| if Extends then |
| Error_Msg |
| (Data.Flags, |
| Continuation.all & |
| "shared library project %% cannot extend static " & |
| "library project %%", |
| Project.Location, Project); |
| Continuation := Continuation_String'Access; |
| |
| elsif not Unchecked_Shared_Lib_Imports then |
| Error_Msg |
| (Data.Flags, |
| Continuation.all & |
| "shared library project %% cannot import static " & |
| "library project %%", |
| Project.Location, Project); |
| Continuation := Continuation_String'Access; |
| end if; |
| |
| end if; |
| end if; |
| end Check_Library; |
| |
| Dir_Exists : Boolean; |
| |
| -- Start of processing for Check_Library_Attributes |
| |
| begin |
| Library_Directory_Present := Lib_Dir.Value /= Empty_String; |
| |
| -- Special case of extending project |
| |
| if Project.Extends /= No_Project then |
| |
| -- If the project extended is a library project, we inherit the |
| -- library name, if it is not redefined; we check that the library |
| -- directory is specified. |
| |
| if Project.Extends.Library then |
| if Project.Qualifier = Standard then |
| Error_Msg |
| (Data.Flags, |
| "a standard project cannot extend a library project", |
| Project.Location, Project); |
| |
| else |
| if Lib_Name.Default then |
| Project.Library_Name := Project.Extends.Library_Name; |
| end if; |
| |
| if Lib_Dir.Default then |
| if not Project.Virtual then |
| Error_Msg |
| (Data.Flags, |
| "a project extending a library project must " & |
| "specify an attribute Library_Dir", |
| Project.Location, Project); |
| |
| else |
| -- For a virtual project extending a library project, |
| -- inherit library directory and library kind. |
| |
| Project.Library_Dir := Project.Extends.Library_Dir; |
| Library_Directory_Present := True; |
| Project.Library_Kind := Project.Extends.Library_Kind; |
| end if; |
| end if; |
| end if; |
| end if; |
| end if; |
| |
| pragma Assert (Lib_Name.Kind = Single); |
| |
| if Lib_Name.Value = Empty_String then |
| if Current_Verbosity = High |
| and then Project.Library_Name = No_Name |
| then |
| Debug_Indent; |
| Write_Line ("no library name"); |
| end if; |
| |
| else |
| -- There is no restriction on the syntax of library names |
| |
| Project.Library_Name := Lib_Name.Value; |
| end if; |
| |
| if Project.Library_Name /= No_Name then |
| if Current_Verbosity = High then |
| Write_Attr |
| ("Library name: ", Get_Name_String (Project.Library_Name)); |
| end if; |
| |
| pragma Assert (Lib_Dir.Kind = Single); |
| |
| if not Library_Directory_Present then |
| Debug_Output ("no library directory"); |
| |
| else |
| -- Find path name (unless inherited), check that it is a directory |
| |
| if Project.Library_Dir = No_Path_Information then |
| Locate_Directory |
| (Project, |
| File_Name_Type (Lib_Dir.Value), |
| Path => Project.Library_Dir, |
| Dir_Exists => Dir_Exists, |
| Data => Data, |
| Create => "library", |
| Must_Exist => False, |
| Location => Lib_Dir.Location, |
| Externally_Built => Project.Externally_Built); |
| |
| else |
| Dir_Exists := |
| Is_Directory |
| (Get_Name_String (Project.Library_Dir.Display_Name)); |
| end if; |
| |
| if not Dir_Exists then |
| |
| -- Get the absolute name of the library directory that |
| -- does not exist, to report an error. |
| |
| Err_Vars.Error_Msg_File_1 := |
| File_Name_Type (Project.Library_Dir.Display_Name); |
| Error_Msg |
| (Data.Flags, |
| "library directory { does not exist", |
| Lib_Dir.Location, Project); |
| |
| -- Checks for object/source directories |
| |
| elsif not Project.Externally_Built |
| |
| -- An aggregate library does not have sources or objects, so |
| -- these tests are not required in this case. |
| |
| and then Project.Qualifier /= Aggregate_Library |
| then |
| -- Library directory cannot be the same as Object directory |
| |
| if Project.Library_Dir.Name = Project.Object_Directory.Name then |
| Error_Msg |
| (Data.Flags, |
| "library directory cannot be the same " & |
| "as object directory", |
| Lib_Dir.Location, Project); |
| Project.Library_Dir := No_Path_Information; |
| |
| else |
| declare |
| OK : Boolean := True; |
| Dirs_Id : String_List_Id; |
| Dir_Elem : String_Element; |
| Pid : Project_List; |
| |
| begin |
| -- The library directory cannot be the same as a source |
| -- directory of the current project. |
| |
| Dirs_Id := Project.Source_Dirs; |
| while Dirs_Id /= Nil_String loop |
| Dir_Elem := Shared.String_Elements.Table (Dirs_Id); |
| Dirs_Id := Dir_Elem.Next; |
| |
| if Project.Library_Dir.Name = |
| Path_Name_Type (Dir_Elem.Value) |
| then |
| Err_Vars.Error_Msg_File_1 := |
| File_Name_Type (Dir_Elem.Value); |
| Error_Msg |
| (Data.Flags, |
| "library directory cannot be the same " & |
| "as source directory {", |
| Lib_Dir.Location, Project); |
| OK := False; |
| exit; |
| end if; |
| end loop; |
| |
| if OK then |
| |
| -- The library directory cannot be the same as a |
| -- source directory of another project either. |
| |
| Pid := Data.Tree.Projects; |
| Project_Loop : loop |
| exit Project_Loop when Pid = null; |
| |
| if Pid.Project /= Project then |
| Dirs_Id := Pid.Project.Source_Dirs; |
| |
| Dir_Loop : while Dirs_Id /= Nil_String loop |
| Dir_Elem := |
| Shared.String_Elements.Table (Dirs_Id); |
| Dirs_Id := Dir_Elem.Next; |
| |
| if Project.Library_Dir.Name = |
| Path_Name_Type (Dir_Elem.Value) |
| then |
| Err_Vars.Error_Msg_File_1 := |
| File_Name_Type (Dir_Elem.Value); |
| Err_Vars.Error_Msg_Name_1 := |
| Pid.Project.Name; |
| |
| Error_Msg |
| (Data.Flags, |
| "library directory cannot be the same" & |
| " as source directory { of project %%", |
| Lib_Dir.Location, Project); |
| OK := False; |
| exit Project_Loop; |
| end if; |
| end loop Dir_Loop; |
| end if; |
| |
| Pid := Pid.Next; |
| end loop Project_Loop; |
| end if; |
| |
| if not OK then |
| Project.Library_Dir := No_Path_Information; |
| |
| elsif Current_Verbosity = High then |
| |
| -- Display the Library directory in high verbosity |
| |
| Write_Attr |
| ("Library directory", |
| Get_Name_String (Project.Library_Dir.Display_Name)); |
| end if; |
| end; |
| end if; |
| end if; |
| end if; |
| |
| end if; |
| |
| Project.Library := |
| Project.Library_Dir /= No_Path_Information |
| and then Project.Library_Name /= No_Name; |
| |
| if Project.Extends = No_Project then |
| case Project.Qualifier is |
| when Standard => |
| if Project.Library then |
| Error_Msg |
| (Data.Flags, |
| "a standard project cannot be a library project", |
| Lib_Name.Location, Project); |
| end if; |
| |
| when Library | Aggregate_Library => |
| if not Project.Library then |
| if Project.Library_Name = No_Name then |
| Error_Msg |
| (Data.Flags, |
| "attribute Library_Name not declared", |
| Project.Location, Project); |
| |
| if not Library_Directory_Present then |
| Error_Msg |
| (Data.Flags, |
| "\attribute Library_Dir not declared", |
| Project.Location, Project); |
| end if; |
| |
| elsif Project.Library_Dir = No_Path_Information then |
| Error_Msg |
| (Data.Flags, |
| "attribute Library_Dir not declared", |
| Project.Location, Project); |
| end if; |
| end if; |
| |
| when others => |
| null; |
| end case; |
| end if; |
| |
| if Project.Library then |
| Support_For_Libraries := Project.Config.Lib_Support; |
| |
| if not Project.Externally_Built |
| and then Support_For_Libraries = Prj.None |
| then |
| Error_Msg |
| (Data.Flags, |
| "?libraries are not supported on this platform", |
| Lib_Name.Location, Project); |
| Project.Library := False; |
| |
| else |
| if Lib_ALI_Dir.Value = Empty_String then |
| Debug_Output ("no library ALI directory specified"); |
| Project.Library_ALI_Dir := Project.Library_Dir; |
| |
| else |
| -- Find path name, check that it is a directory |
| |
| Locate_Directory |
| (Project, |
| File_Name_Type (Lib_ALI_Dir.Value), |
| Path => Project.Library_ALI_Dir, |
| Create => "library ALI", |
| Dir_Exists => Dir_Exists, |
| Data => Data, |
| Must_Exist => False, |
| Location => Lib_ALI_Dir.Location, |
| Externally_Built => Project.Externally_Built); |
| |
| if not Dir_Exists then |
| |
| -- Get the absolute name of the library ALI directory that |
| -- does not exist, to report an error. |
| |
| Err_Vars.Error_Msg_File_1 := |
| File_Name_Type (Project.Library_ALI_Dir.Display_Name); |
| Error_Msg |
| (Data.Flags, |
| "library 'A'L'I directory { does not exist", |
| Lib_ALI_Dir.Location, Project); |
| end if; |
| |
| if not Project.Externally_Built |
| and then Project.Library_ALI_Dir /= Project.Library_Dir |
| then |
| -- The library ALI directory cannot be the same as the |
| -- Object directory. |
| |
| if Project.Library_ALI_Dir = Project.Object_Directory then |
| Error_Msg |
| (Data.Flags, |
| "library 'A'L'I directory cannot be the same " & |
| "as object directory", |
| Lib_ALI_Dir.Location, Project); |
| Project.Library_ALI_Dir := No_Path_Information; |
| |
| else |
| declare |
| OK : Boolean := True; |
| Dirs_Id : String_List_Id; |
| Dir_Elem : String_Element; |
| Pid : Project_List; |
| |
| begin |
| -- The library ALI directory cannot be the same as |
| -- a source directory of the current project. |
| |
| Dirs_Id := Project.Source_Dirs; |
| while Dirs_Id /= Nil_String loop |
| Dir_Elem := Shared.String_Elements.Table (Dirs_Id); |
| Dirs_Id := Dir_Elem.Next; |
| |
| if Project.Library_ALI_Dir.Name = |
| Path_Name_Type (Dir_Elem.Value) |
| then |
| Err_Vars.Error_Msg_File_1 := |
| File_Name_Type (Dir_Elem.Value); |
| Error_Msg |
| (Data.Flags, |
| "library 'A'L'I directory cannot be " & |
| "the same as source directory {", |
| Lib_ALI_Dir.Location, Project); |
| OK := False; |
| exit; |
| end if; |
| end loop; |
| |
| if OK then |
| |
| -- The library ALI directory cannot be the same as |
| -- a source directory of another project either. |
| |
| Pid := Data.Tree.Projects; |
| ALI_Project_Loop : loop |
| exit ALI_Project_Loop when Pid = null; |
| |
| if Pid.Project /= Project then |
| Dirs_Id := Pid.Project.Source_Dirs; |
| |
| ALI_Dir_Loop : |
| while Dirs_Id /= Nil_String loop |
| Dir_Elem := |
| Shared.String_Elements.Table (Dirs_Id); |
| Dirs_Id := Dir_Elem.Next; |
| |
| if Project.Library_ALI_Dir.Name = |
| Path_Name_Type (Dir_Elem.Value) |
| then |
| Err_Vars.Error_Msg_File_1 := |
| File_Name_Type (Dir_Elem.Value); |
| Err_Vars.Error_Msg_Name_1 := |
| Pid.Project.Name; |
| |
| Error_Msg |
| (Data.Flags, |
| "library 'A'L'I directory cannot " & |
| "be the same as source directory " & |
| "{ of project %%", |
| Lib_ALI_Dir.Location, Project); |
| OK := False; |
| exit ALI_Project_Loop; |
| end if; |
| end loop ALI_Dir_Loop; |
| end if; |
| Pid := Pid.Next; |
| end loop ALI_Project_Loop; |
| end if; |
| |
| if not OK then |
| Project.Library_ALI_Dir := No_Path_Information; |
| |
| elsif Current_Verbosity = High then |
| |
| -- Display Library ALI directory in high verbosity |
| |
| Write_Attr |
| ("Library ALI dir", |
| Get_Name_String |
| (Project.Library_ALI_Dir.Display_Name)); |
| end if; |
| end; |
| end if; |
| end if; |
| end if; |
| |
| pragma Assert (Lib_Version.Kind = Single); |
| |
| if Lib_Version.Value = Empty_String then |
| Debug_Output ("no library version specified"); |
| |
| else |
| Project.Lib_Internal_Name := Lib_Version.Value; |
| end if; |
| |
| pragma Assert (The_Lib_Kind.Kind = Single); |
| |
| if The_Lib_Kind.Value = Empty_String then |
| Debug_Output ("no library kind specified"); |
| |
| else |
| Get_Name_String (The_Lib_Kind.Value); |
| |
| declare |
| Kind_Name : constant String := |
| To_Lower (Name_Buffer (1 .. Name_Len)); |
| |
| OK : Boolean := True; |
| |
| begin |
| if Kind_Name = "static" then |
| Project.Library_Kind := Static; |
| |
| elsif Kind_Name = "dynamic" then |
| Project.Library_Kind := Dynamic; |
| |
| elsif Kind_Name = "relocatable" then |
| Project.Library_Kind := Relocatable; |
| |
| else |
| Error_Msg |
| (Data.Flags, |
| "illegal value for Library_Kind", |
| The_Lib_Kind.Location, Project); |
| OK := False; |
| end if; |
| |
| if Current_Verbosity = High and then OK then |
| Write_Attr ("Library kind", Kind_Name); |
| end if; |
| |
| if Project.Library_Kind /= Static then |
| if not Project.Externally_Built |
| and then Support_For_Libraries = Prj.Static_Only |
| then |
| Error_Msg |
| (Data.Flags, |
| "only static libraries are supported " & |
| "on this platform", |
| The_Lib_Kind.Location, Project); |
| Project.Library := False; |
| |
| else |
| -- Check if (obsolescent) attribute Library_GCC or |
| -- Linker'Driver is declared. |
| |
| if Lib_GCC.Value /= Empty_String then |
| Error_Msg |
| (Data.Flags, |
| "?Library_'G'C'C is an obsolescent attribute, " & |
| "use Linker''Driver instead", |
| Lib_GCC.Location, Project); |
| Project.Config.Shared_Lib_Driver := |
| File_Name_Type (Lib_GCC.Value); |
| |
| else |
| declare |
| Linker : constant Package_Id := |
| Value_Of |
| (Name_Linker, |
| Project.Decl.Packages, |
| Shared); |
| Driver : constant Variable_Value := |
| Value_Of |
| (Name => No_Name, |
| Attribute_Or_Array_Name => |
| Name_Driver, |
| In_Package => Linker, |
| Shared => Shared); |
| |
| begin |
| if Driver /= Nil_Variable_Value |
| and then Driver.Value /= Empty_String |
| then |
| Project.Config.Shared_Lib_Driver := |
| File_Name_Type (Driver.Value); |
| end if; |
| end; |
| end if; |
| end if; |
| end if; |
| end; |
| end if; |
| |
| if Project.Library |
| and then Project.Qualifier /= Aggregate_Library |
| then |
| Debug_Output ("this is a library project file"); |
| |
| Check_Library (Project.Extends, Extends => True); |
| |
| Imported_Project_List := Project.Imported_Projects; |
| while Imported_Project_List /= null loop |
| Check_Library |
| (Imported_Project_List.Project, |
| Extends => False); |
| Imported_Project_List := Imported_Project_List.Next; |
| end loop; |
| end if; |
| end if; |
| end if; |
| |
| -- Check if Linker'Switches or Linker'Default_Switches are declared. |
| -- Warn if they are declared, as it is a common error to think that |
| -- library are "linked" with Linker switches. |
| |
| if Project.Library then |
| declare |
| Linker_Package_Id : constant Package_Id := |
| Util.Value_Of |
| (Name_Linker, |
| Project.Decl.Packages, Shared); |
| Linker_Package : Package_Element; |
| Switches : Array_Element_Id := No_Array_Element; |
| |
| begin |
| if Linker_Package_Id /= No_Package then |
| Linker_Package := Shared.Packages.Table (Linker_Package_Id); |
| |
| Switches := |
| Value_Of |
| (Name => Name_Switches, |
| In_Arrays => Linker_Package.Decl.Arrays, |
| Shared => Shared); |
| |
| if Switches = No_Array_Element then |
| Switches := |
| Value_Of |
| (Name => Name_Default_Switches, |
| In_Arrays => Linker_Package.Decl.Arrays, |
| Shared => Shared); |
| end if; |
| |
| if Switches /= No_Array_Element then |
| Error_Msg |
| (Data.Flags, |
| "?Linker switches not taken into account in library " & |
| "projects", |
| No_Location, Project); |
| end if; |
| end if; |
| end; |
| end if; |
| |
| if Project.Extends /= No_Project and then Project.Extends.Library then |
| |
| -- Remove the library name from Lib_Data_Table |
| |
| for J in 1 .. Lib_Data_Table.Last loop |
| if Lib_Data_Table.Table (J).Proj = Project.Extends then |
| Lib_Data_Table.Table (J) := |
| Lib_Data_Table.Table (Lib_Data_Table.Last); |
| Lib_Data_Table.Set_Last (Lib_Data_Table.Last - 1); |
| exit; |
| end if; |
| end loop; |
| end if; |
| |
| if Project.Library and then not Lib_Name.Default then |
| |
| -- Check if the same library name is used in an other library project |
| |
| for J in 1 .. Lib_Data_Table.Last loop |
| if Lib_Data_Table.Table (J).Name = Project.Library_Name |
| and then Lib_Data_Table.Table (J).Tree = Data.Tree |
| then |
| Error_Msg_Name_1 := Lib_Data_Table.Table (J).Proj.Name; |
| Error_Msg |
| (Data.Flags, |
| "Library name cannot be the same as in project %%", |
| Lib_Name.Location, Project); |
| Project.Library := False; |
| exit; |
| end if; |
| end loop; |
| end if; |
| |
| if Project.Library and not Data.In_Aggregate_Lib then |
| |
| -- Record the library name |
| |
| Lib_Data_Table.Append |
| ((Name => Project.Library_Name, |
| Proj => Project, |
| Tree => Data.Tree)); |
| end if; |
| end Check_Library_Attributes; |
| |
| -------------------------- |
| -- Check_Package_Naming -- |
| -------------------------- |
| |
| procedure Check_Package_Naming |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data) |
| is |
| Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared; |
| Naming_Id : constant Package_Id := |
| Util.Value_Of |
| (Name_Naming, Project.Decl.Packages, Shared); |
| Naming : Package_Element; |
| |
| Ada_Body_Suffix_Loc : Source_Ptr := No_Location; |
| |
| procedure Check_Naming; |
| -- Check the validity of the Naming package (suffixes valid, ...) |
| |
| procedure Check_Common |
| (Dot_Replacement : in out File_Name_Type; |
| Casing : in out Casing_Type; |
| Casing_Defined : out Boolean; |
| Separate_Suffix : in out File_Name_Type; |
| Sep_Suffix_Loc : out Source_Ptr); |
| -- Check attributes common |
| |
| procedure Process_Exceptions_File_Based |
| (Lang_Id : Language_Ptr; |
| Kind : Source_Kind); |
| procedure Process_Exceptions_Unit_Based |
| (Lang_Id : Language_Ptr; |
| Kind : Source_Kind); |
| -- Process the naming exceptions for the two types of languages |
| |
| procedure Initialize_Naming_Data; |
| -- Initialize internal naming data for the various languages |
| |
| ------------------ |
| -- Check_Common -- |
| ------------------ |
| |
| procedure Check_Common |
| (Dot_Replacement : in out File_Name_Type; |
| Casing : in out Casing_Type; |
| Casing_Defined : out Boolean; |
| Separate_Suffix : in out File_Name_Type; |
| Sep_Suffix_Loc : out Source_Ptr) |
| is |
| Dot_Repl : constant Variable_Value := |
| Util.Value_Of |
| (Name_Dot_Replacement, |
| Naming.Decl.Attributes, |
| Shared); |
| Casing_String : constant Variable_Value := |
| Util.Value_Of |
| (Name_Casing, |
| Naming.Decl.Attributes, |
| Shared); |
| Sep_Suffix : constant Variable_Value := |
| Util.Value_Of |
| (Name_Separate_Suffix, |
| Naming.Decl.Attributes, |
| Shared); |
| Dot_Repl_Loc : Source_Ptr; |
| |
| begin |
| Sep_Suffix_Loc := No_Location; |
| |
| if not Dot_Repl.Default then |
| pragma Assert |
| (Dot_Repl.Kind = Single, "Dot_Replacement is not a string"); |
| |
| if Length_Of_Name (Dot_Repl.Value) = 0 then |
| Error_Msg |
| (Data.Flags, "Dot_Replacement cannot be empty", |
| Dot_Repl.Location, Project); |
| end if; |
| |
| Dot_Replacement := Canonical_Case_File_Name (Dot_Repl.Value); |
| Dot_Repl_Loc := Dot_Repl.Location; |
| |
| declare |
| Repl : constant String := Get_Name_String (Dot_Replacement); |
| |
| begin |
| -- Dot_Replacement cannot |
| -- - be empty |
| -- - start or end with an alphanumeric |
| -- - be a single '_' |
| -- - start with an '_' followed by an alphanumeric |
| -- - contain a '.' except if it is "." |
| |
| if Repl'Length = 0 |
| or else Is_Alphanumeric (Repl (Repl'First)) |
| or else Is_Alphanumeric (Repl (Repl'Last)) |
| or else (Repl (Repl'First) = '_' |
| and then |
| (Repl'Length = 1 |
| or else |
| Is_Alphanumeric (Repl (Repl'First + 1)))) |
| or else (Repl'Length > 1 |
| and then |
| Index (Source => Repl, Pattern => ".") /= 0) |
| then |
| Error_Msg |
| (Data.Flags, |
| '"' & Repl & |
| """ is illegal for Dot_Replacement.", |
| Dot_Repl_Loc, Project); |
| end if; |
| end; |
| end if; |
| |
| if Dot_Replacement /= No_File then |
| Write_Attr |
| ("Dot_Replacement", Get_Name_String (Dot_Replacement)); |
| end if; |
| |
| Casing_Defined := False; |
| |
| if not Casing_String.Default then |
| pragma Assert |
| (Casing_String.Kind = Single, "Casing is not a string"); |
| |
| declare |
| Casing_Image : constant String := |
| Get_Name_String (Casing_String.Value); |
| |
| begin |
| if Casing_Image'Length = 0 then |
| Error_Msg |
| (Data.Flags, |
| "Casing cannot be an empty string", |
| Casing_String.Location, Project); |
| end if; |
| |
| Casing := Value (Casing_Image); |
| Casing_Defined := True; |
| |
| exception |
| when Constraint_Error => |
| Name_Len := Casing_Image'Length; |
| Name_Buffer (1 .. Name_Len) := Casing_Image; |
| Err_Vars.Error_Msg_Name_1 := Name_Find; |
| Error_Msg |
| (Data.Flags, |
| "%% is not a correct Casing", |
| Casing_String.Location, Project); |
| end; |
| end if; |
| |
| Write_Attr ("Casing", Image (Casing)); |
| |
| if not Sep_Suffix.Default then |
| if Length_Of_Name (Sep_Suffix.Value) = 0 then |
| Error_Msg |
| (Data.Flags, |
| "Separate_Suffix cannot be empty", |
| Sep_Suffix.Location, Project); |
| |
| else |
| Separate_Suffix := Canonical_Case_File_Name (Sep_Suffix.Value); |
| Sep_Suffix_Loc := Sep_Suffix.Location; |
| |
| Check_Illegal_Suffix |
| (Project, Separate_Suffix, |
| Dot_Replacement, "Separate_Suffix", Sep_Suffix.Location, |
| Data); |
| end if; |
| end if; |
| |
| if Separate_Suffix /= No_File then |
| Write_Attr |
| ("Separate_Suffix", Get_Name_String (Separate_Suffix)); |
| end if; |
| end Check_Common; |
| |
| ----------------------------------- |
| -- Process_Exceptions_File_Based -- |
| ----------------------------------- |
| |
| procedure Process_Exceptions_File_Based |
| (Lang_Id : Language_Ptr; |
| Kind : Source_Kind) |
| is |
| Lang : constant Name_Id := Lang_Id.Name; |
| Exceptions : Array_Element_Id; |
| Exception_List : Variable_Value; |
| Element_Id : String_List_Id; |
| Element : String_Element; |
| File_Name : File_Name_Type; |
| Source : Source_Id; |
| |
| begin |
| case Kind is |
| when Impl | Sep => |
| Exceptions := |
| Value_Of |
| (Name_Implementation_Exceptions, |
| In_Arrays => Naming.Decl.Arrays, |
| Shared => Shared); |
| |
| when Spec => |
| Exceptions := |
| Value_Of |
| (Name_Specification_Exceptions, |
| In_Arrays => Naming.Decl.Arrays, |
| Shared => Shared); |
| end case; |
| |
| Exception_List := |
| Value_Of |
| (Index => Lang, |
| In_Array => Exceptions, |
| Shared => Shared); |
| |
| if Exception_List /= Nil_Variable_Value then |
| Element_Id := Exception_List.Values; |
| while Element_Id /= Nil_String loop |
| Element := Shared.String_Elements.Table (Element_Id); |
| File_Name := Canonical_Case_File_Name (Element.Value); |
| |
| Source := |
| Source_Files_Htable.Get |
| (Data.Tree.Source_Files_HT, File_Name); |
| while Source /= No_Source |
| and then Source.Project /= Project |
| loop |
| Source := Source.Next_With_File_Name; |
| end loop; |
| |
| if Source = No_Source then |
| Add_Source |
| (Id => Source, |
| Data => Data, |
| Project => Project, |
| Source_Dir_Rank => 0, |
| Lang_Id => Lang_Id, |
| Kind => Kind, |
| File_Name => File_Name, |
| Display_File => File_Name_Type (Element.Value), |
| Naming_Exception => Yes, |
| Location => Element.Location); |
| |
| else |
| -- Check if the file name is already recorded for another |
| -- language or another kind. |
| |
| if Source.Language /= Lang_Id then |
| Error_Msg |
| (Data.Flags, |
| "the same file cannot be a source of two languages", |
| Element.Location, Project); |
| |
| elsif Source.Kind /= Kind then |
| Error_Msg |
| (Data.Flags, |
| "the same file cannot be a source and a template", |
| Element.Location, Project); |
| end if; |
| |
| -- If the file is already recorded for the same |
| -- language and the same kind, it means that the file |
| -- name appears several times in the *_Exceptions |
| -- attribute; so there is nothing to do. |
| end if; |
| |
| Element_Id := Element.Next; |
| end loop; |
| end if; |
| end Process_Exceptions_File_Based; |
| |
| ----------------------------------- |
| -- Process_Exceptions_Unit_Based -- |
| ----------------------------------- |
| |
| procedure Process_Exceptions_Unit_Based |
| (Lang_Id : Language_Ptr; |
| Kind : Source_Kind) |
| is |
| Exceptions : Array_Element_Id; |
| Element : Array_Element; |
| Unit : Name_Id; |
| Index : Int; |
| File_Name : File_Name_Type; |
| Source : Source_Id; |
| |
| Naming_Exception : Naming_Exception_Type; |
| |
| begin |
| case Kind is |
| when Impl | Sep => |
| Exceptions := |
| Value_Of |
| (Name_Body, |
| In_Arrays => Naming.Decl.Arrays, |
| Shared => Shared); |
| |
| if Exceptions = No_Array_Element then |
| Exceptions := |
| Value_Of |
| (Name_Implementation, |
| In_Arrays => Naming.Decl.Arrays, |
| Shared => Shared); |
| end if; |
| |
| when Spec => |
| Exceptions := |
| Value_Of |
| (Name_Spec, |
| In_Arrays => Naming.Decl.Arrays, |
| Shared => Shared); |
| |
| if Exceptions = No_Array_Element then |
| Exceptions := |
| Value_Of |
| (Name_Specification, |
| In_Arrays => Naming.Decl.Arrays, |
| Shared => Shared); |
| end if; |
| end case; |
| |
| while Exceptions /= No_Array_Element loop |
| Element := Shared.Array_Elements.Table (Exceptions); |
| |
| if Element.Restricted then |
| Naming_Exception := Inherited; |
| else |
| Naming_Exception := Yes; |
| end if; |
| |
| File_Name := Canonical_Case_File_Name (Element.Value.Value); |
| |
| Get_Name_String (Element.Index); |
| To_Lower (Name_Buffer (1 .. Name_Len)); |
| Index := Element.Value.Index; |
| |
| -- Check if it is a valid unit name |
| |
| Get_Name_String (Element.Index); |
| Check_Unit_Name (Name_Buffer (1 .. Name_Len), Unit); |
| |
| if Unit = No_Name then |
| Err_Vars.Error_Msg_Name_1 := Element.Index; |
| Error_Msg |
| (Data.Flags, |
| "%% is not a valid unit name.", |
| Element.Value.Location, Project); |
| end if; |
| |
| if Unit /= No_Name then |
| Add_Source |
| (Id => Source, |
| Data => Data, |
| Project => Project, |
| Source_Dir_Rank => 0, |
| Lang_Id => Lang_Id, |
| Kind => Kind, |
| File_Name => File_Name, |
| Display_File => File_Name_Type (Element.Value.Value), |
| Unit => Unit, |
| Index => Index, |
| Location => Element.Value.Location, |
| Naming_Exception => Naming_Exception); |
| end if; |
| |
| Exceptions := Element.Next; |
| end loop; |
| end Process_Exceptions_Unit_Based; |
| |
| ------------------ |
| -- Check_Naming -- |
| ------------------ |
| |
| procedure Check_Naming is |
| Dot_Replacement : File_Name_Type := |
| File_Name_Type |
| (First_Name_Id + Character'Pos ('-')); |
| Separate_Suffix : File_Name_Type := No_File; |
| Casing : Casing_Type := All_Lower_Case; |
| Casing_Defined : Boolean; |
| Lang_Id : Language_Ptr; |
| Sep_Suffix_Loc : Source_Ptr; |
| Suffix : Variable_Value; |
| Lang : Name_Id; |
| |
| begin |
| Check_Common |
| (Dot_Replacement => Dot_Replacement, |
| Casing => Casing, |
| Casing_Defined => Casing_Defined, |
| Separate_Suffix => Separate_Suffix, |
| Sep_Suffix_Loc => Sep_Suffix_Loc); |
| |
| -- For all unit based languages, if any, set the specified value |
| -- of Dot_Replacement, Casing and/or Separate_Suffix. Do not |
| -- systematically overwrite, since the defaults come from the |
| -- configuration file. |
| |
| if Dot_Replacement /= No_File |
| or else Casing_Defined |
| or else Separate_Suffix /= No_File |
| then |
| Lang_Id := Project.Languages; |
| while Lang_Id /= No_Language_Index loop |
| if Lang_Id.Config.Kind = Unit_Based then |
| if Dot_Replacement /= No_File then |
| Lang_Id.Config.Naming_Data.Dot_Replacement := |
| Dot_Replacement; |
| end if; |
| |
| if Casing_Defined then |
| Lang_Id.Config.Naming_Data.Casing := Casing; |
| end if; |
| end if; |
| |
| Lang_Id := Lang_Id.Next; |
| end loop; |
| end if; |
| |
| -- Next, get the spec and body suffixes |
| |
| Lang_Id := Project.Languages; |
| while Lang_Id /= No_Language_Index loop |
| Lang := Lang_Id.Name; |
| |
| -- Spec_Suffix |
| |
| Suffix := Value_Of |
| (Name => Lang, |
| Attribute_Or_Array_Name => Name_Spec_Suffix, |
| In_Package => Naming_Id, |
| Shared => Shared); |
| |
| if Suffix = Nil_Variable_Value then |
| Suffix := Value_Of |
| (Name => Lang, |
| Attribute_Or_Array_Name => Name_Specification_Suffix, |
| In_Package => Naming_Id, |
| Shared => Shared); |
| end if; |
| |
| if Suffix /= Nil_Variable_Value then |
| Lang_Id.Config.Naming_Data.Spec_Suffix := |
| File_Name_Type (Suffix.Value); |
| |
| Check_Illegal_Suffix |
| (Project, |
| Lang_Id.Config.Naming_Data.Spec_Suffix, |
| Lang_Id.Config.Naming_Data.Dot_Replacement, |
| "Spec_Suffix", Suffix.Location, Data); |
| |
| Write_Attr |
| ("Spec_Suffix", |
| Get_Name_String (Lang_Id.Config.Naming_Data.Spec_Suffix)); |
| end if; |
| |
| -- Body_Suffix |
| |
| Suffix := |
| Value_Of |
| (Name => Lang, |
| Attribute_Or_Array_Name => Name_Body_Suffix, |
| In_Package => Naming_Id, |
| Shared => Shared); |
| |
| if Suffix = Nil_Variable_Value then |
| Suffix := |
| Value_Of |
| (Name => Lang, |
| Attribute_Or_Array_Name => Name_Implementation_Suffix, |
| In_Package => Naming_Id, |
| Shared => Shared); |
| end if; |
| |
| if Suffix /= Nil_Variable_Value then |
| Lang_Id.Config.Naming_Data.Body_Suffix := |
| File_Name_Type (Suffix.Value); |
| |
| -- The default value of separate suffix should be the same as |
| -- the body suffix, so we need to compute that first. |
| |
| if Separate_Suffix = No_File then |
| Lang_Id.Config.Naming_Data.Separate_Suffix := |
| Lang_Id.Config.Naming_Data.Body_Suffix; |
| Write_Attr |
| ("Sep_Suffix", |
| Get_Name_String |
| (Lang_Id.Config.Naming_Data.Separate_Suffix)); |
| else |
| Lang_Id.Config.Naming_Data.Separate_Suffix := |
| Separate_Suffix; |
| end if; |
| |
| Check_Illegal_Suffix |
| (Project, |
| Lang_Id.Config.Naming_Data.Body_Suffix, |
| Lang_Id.Config.Naming_Data.Dot_Replacement, |
| "Body_Suffix", Suffix.Location, Data); |
| |
| Write_Attr |
| ("Body_Suffix", |
| Get_Name_String (Lang_Id.Config.Naming_Data.Body_Suffix)); |
| |
| elsif Separate_Suffix /= No_File then |
| Lang_Id.Config.Naming_Data.Separate_Suffix := Separate_Suffix; |
| end if; |
| |
| -- Spec_Suffix cannot be equal to Body_Suffix or Separate_Suffix, |
| -- since that would cause a clear ambiguity. Note that we do allow |
| -- a Spec_Suffix to have the same termination as one of these, |
| -- which causes a potential ambiguity, but we resolve that by |
| -- matching the longest possible suffix. |
| |
| if Lang_Id.Config.Naming_Data.Spec_Suffix /= No_File |
| and then Lang_Id.Config.Naming_Data.Spec_Suffix = |
| Lang_Id.Config.Naming_Data.Body_Suffix |
| then |
| Error_Msg |
| (Data.Flags, |
| "Body_Suffix (""" |
| & Get_Name_String (Lang_Id.Config.Naming_Data.Body_Suffix) |
| & """) cannot be the same as Spec_Suffix.", |
| Ada_Body_Suffix_Loc, Project); |
| end if; |
| |
| if Lang_Id.Config.Naming_Data.Body_Suffix /= |
| Lang_Id.Config.Naming_Data.Separate_Suffix |
| and then Lang_Id.Config.Naming_Data.Spec_Suffix = |
| Lang_Id.Config.Naming_Data.Separate_Suffix |
| then |
| Error_Msg |
| (Data.Flags, |
| "Separate_Suffix (""" |
| & Get_Name_String |
| (Lang_Id.Config.Naming_Data.Separate_Suffix) |
| & """) cannot be the same as Spec_Suffix.", |
| Sep_Suffix_Loc, Project); |
| end if; |
| |
| Lang_Id := Lang_Id.Next; |
| end loop; |
| |
| -- Get the naming exceptions for all languages, but not for virtual |
| -- projects. |
| |
| if not Project.Virtual then |
| for Kind in Spec_Or_Body loop |
| Lang_Id := Project.Languages; |
| while Lang_Id /= No_Language_Index loop |
| case Lang_Id.Config.Kind is |
| when File_Based => |
| Process_Exceptions_File_Based (Lang_Id, Kind); |
| |
| when Unit_Based => |
| Process_Exceptions_Unit_Based (Lang_Id, Kind); |
| end case; |
| |
| Lang_Id := Lang_Id.Next; |
| end loop; |
| end loop; |
| end if; |
| end Check_Naming; |
| |
| ---------------------------- |
| -- Initialize_Naming_Data -- |
| ---------------------------- |
| |
| procedure Initialize_Naming_Data is |
| Specs : Array_Element_Id := |
| Util.Value_Of |
| (Name_Spec_Suffix, |
| Naming.Decl.Arrays, |
| Shared); |
| |
| Impls : Array_Element_Id := |
| Util.Value_Of |
| (Name_Body_Suffix, |
| Naming.Decl.Arrays, |
| Shared); |
| |
| Lang : Language_Ptr; |
| Lang_Name : Name_Id; |
| Value : Variable_Value; |
| Extended : Project_Id; |
| |
| begin |
| -- At this stage, the project already contains the default extensions |
| -- for the various languages. We now merge those suffixes read in the |
| -- user project, and they override the default. |
| |
| while Specs /= No_Array_Element loop |
| Lang_Name := Shared.Array_Elements.Table (Specs).Index; |
| Lang := |
| Get_Language_From_Name |
| (Project, Name => Get_Name_String (Lang_Name)); |
| |
| -- An extending project inherits its parent projects' languages |
| -- so if needed we should create entries for those languages |
| |
| if Lang = null then |
| Extended := Project.Extends; |
| while Extended /= null loop |
| Lang := Get_Language_From_Name |
| (Extended, Name => Get_Name_String (Lang_Name)); |
| exit when Lang /= null; |
| |
| Extended := Extended.Extends; |
| end loop; |
| |
| if Lang /= null then |
| Lang := new Language_Data'(Lang.all); |
| Lang.First_Source := null; |
| Lang.Next := Project.Languages; |
| Project.Languages := Lang; |
| end if; |
| end if; |
| |
| -- If language was not found in project or the projects it extends |
| |
| if Lang = null then |
| Debug_Output |
| ("ignoring spec naming data (lang. not in project): ", |
| Lang_Name); |
| |
| else |
| Value := Shared.Array_Elements.Table (Specs).Value; |
| |
| if Value.Kind = Single then |
| Lang.Config.Naming_Data.Spec_Suffix := |
| Canonical_Case_File_Name (Value.Value); |
| end if; |
| end if; |
| |
| Specs := Shared.Array_Elements.Table (Specs).Next; |
| end loop; |
| |
| while Impls /= No_Array_Element loop |
| Lang_Name := Shared.Array_Elements.Table (Impls).Index; |
| Lang := |
| Get_Language_From_Name |
| (Project, Name => Get_Name_String (Lang_Name)); |
| |
| if Lang = null then |
| Debug_Output |
| ("ignoring impl naming data (lang. not in project): ", |
| Lang_Name); |
| else |
| Value := Shared.Array_Elements.Table (Impls).Value; |
| |
| if Lang.Name = Name_Ada then |
| Ada_Body_Suffix_Loc := Value.Location; |
| end if; |
| |
| if Value.Kind = Single then |
| Lang.Config.Naming_Data.Body_Suffix := |
| Canonical_Case_File_Name (Value.Value); |
| end if; |
| end if; |
| |
| Impls := Shared.Array_Elements.Table (Impls).Next; |
| end loop; |
| end Initialize_Naming_Data; |
| |
| -- Start of processing for Check_Naming_Schemes |
| |
| begin |
| -- No Naming package or parsing a configuration file? nothing to do |
| |
| if Naming_Id /= No_Package |
| and then Project.Qualifier /= Configuration |
| then |
| Naming := Shared.Packages.Table (Naming_Id); |
| Debug_Increase_Indent ("checking package Naming for ", Project.Name); |
| Initialize_Naming_Data; |
| Check_Naming; |
| Debug_Decrease_Indent ("done checking package naming"); |
| end if; |
| end Check_Package_Naming; |
| |
| --------------------------------- |
| -- Check_Programming_Languages -- |
| --------------------------------- |
| |
| procedure Check_Programming_Languages |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data) |
| is |
| Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared; |
| |
| Languages : Variable_Value := Nil_Variable_Value; |
| Def_Lang : Variable_Value := Nil_Variable_Value; |
| Def_Lang_Id : Name_Id; |
| |
| procedure Add_Language (Name, Display_Name : Name_Id); |
| -- Add a new language to the list of languages for the project. |
| -- Nothing is done if the language has already been defined |
| |
| ------------------ |
| -- Add_Language -- |
| ------------------ |
| |
| procedure Add_Language (Name, Display_Name : Name_Id) is |
| Lang : Language_Ptr; |
| |
| begin |
| Lang := Project.Languages; |
| while Lang /= No_Language_Index loop |
| if Name = Lang.Name then |
| return; |
| end if; |
| |
| Lang := Lang.Next; |
| end loop; |
| |
| Lang := new Language_Data'(No_Language_Data); |
| Lang.Next := Project.Languages; |
| Project.Languages := Lang; |
| Lang.Name := Name; |
| Lang.Display_Name := Display_Name; |
| end Add_Language; |
| |
| -- Start of processing for Check_Programming_Languages |
| |
| begin |
| Project.Languages := null; |
| Languages := |
| Prj.Util.Value_Of (Name_Languages, Project.Decl.Attributes, Shared); |
| Def_Lang := |
| Prj.Util.Value_Of |
| (Name_Default_Language, Project.Decl.Attributes, Shared); |
| |
| if Project.Source_Dirs /= Nil_String then |
| |
| -- Check if languages are specified in this project |
| |
| if Languages.Default then |
| |
| -- Fail if there is no default language defined |
| |
| if Def_Lang.Default then |
| Error_Msg |
| (Data.Flags, |
| "no languages defined for this project", |
| Project.Location, Project); |
| Def_Lang_Id := No_Name; |
| |
| else |
| Get_Name_String (Def_Lang.Value); |
| To_Lower (Name_Buffer (1 .. Name_Len)); |
| Def_Lang_Id := Name_Find; |
| end if; |
| |
| if Def_Lang_Id /= No_Name then |
| Get_Name_String (Def_Lang_Id); |
| Name_Buffer (1) := GNAT.Case_Util.To_Upper (Name_Buffer (1)); |
| Add_Language |
| (Name => Def_Lang_Id, |
| Display_Name => Name_Find); |
| end if; |
| |
| else |
| declare |
| Current : String_List_Id := Languages.Values; |
| Element : String_Element; |
| |
| begin |
| -- If there are no languages declared, there are no sources |
| |
| if Current = Nil_String then |
| Project.Source_Dirs := Nil_String; |
| |
| if Project.Qualifier = Standard then |
| Error_Msg |
| (Data.Flags, |
| "a standard project must have at least one language", |
| Languages.Location, Project); |
| end if; |
| |
| else |
| -- Look through all the languages specified in attribute |
| -- Languages. |
| |
| while Current /= Nil_String loop |
| Element := Shared.String_Elements.Table (Current); |
| Get_Name_String (Element.Value); |
| To_Lower (Name_Buffer (1 .. Name_Len)); |
| |
| Add_Language |
| (Name => Name_Find, |
| Display_Name => Element.Value); |
| |
| Current := Element.Next; |
| end loop; |
| end if; |
| end; |
| end if; |
| end if; |
| end Check_Programming_Languages; |
| |
| ------------------------------- |
| -- Check_Stand_Alone_Library -- |
| ------------------------------- |
| |
| procedure Check_Stand_Alone_Library |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data) |
| is |
| Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared; |
| |
| Lib_Name : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Library_Name, |
| Project.Decl.Attributes, |
| Shared); |
| |
| Lib_Standalone : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Library_Standalone, |
| Project.Decl.Attributes, |
| Shared); |
| |
| Lib_Auto_Init : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Library_Auto_Init, |
| Project.Decl.Attributes, |
| Shared); |
| |
| Lib_Src_Dir : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Library_Src_Dir, |
| Project.Decl.Attributes, |
| Shared); |
| |
| Lib_Symbol_File : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Library_Symbol_File, |
| Project.Decl.Attributes, |
| Shared); |
| |
| Lib_Symbol_Policy : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Library_Symbol_Policy, |
| Project.Decl.Attributes, |
| Shared); |
| |
| Lib_Ref_Symbol_File : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Library_Reference_Symbol_File, |
| Project.Decl.Attributes, |
| Shared); |
| |
| Auto_Init_Supported : Boolean; |
| OK : Boolean := True; |
| |
| begin |
| Auto_Init_Supported := Project.Config.Auto_Init_Supported; |
| |
| -- It is a stand-alone library project file if there is at least one |
| -- unit in the declared or inherited interface. |
| |
| if Project.Lib_Interface_ALIs = Nil_String then |
| if not Lib_Standalone.Default |
| and then Get_Name_String (Lib_Standalone.Value) /= "no" |
| then |
| Error_Msg |
| (Data.Flags, |
| "Library_Standalone valid only if Library_Interface is set", |
| Lib_Standalone.Location, Project); |
| end if; |
| |
| else |
| if Project.Standalone_Library = No then |
| Project.Standalone_Library := Standard; |
| end if; |
| |
| -- The name of a stand-alone library needs to have the syntax of an |
| -- Ada identifier. |
| |
| declare |
| Name : constant String := Get_Name_String (Project.Library_Name); |
| OK : Boolean := Is_Letter (Name (Name'First)); |
| |
| Underline : Boolean := False; |
| |
| begin |
| for J in Name'First + 1 .. Name'Last loop |
| exit when not OK; |
| |
| if Is_Alphanumeric (Name (J)) then |
| Underline := False; |
| |
| elsif Name (J) = '_' then |
| if Underline then |
| OK := False; |
| else |
| Underline := True; |
| end if; |
| |
| else |
| OK := False; |
| end if; |
| end loop; |
| |
| OK := OK and not Underline; |
| |
| if not OK then |
| Error_Msg |
| (Data.Flags, |
| "Incorrect library name for a Stand-Alone Library", |
| Lib_Name.Location, Project); |
| return; |
| end if; |
| end; |
| |
| if Lib_Standalone.Default then |
| Project.Standalone_Library := Standard; |
| |
| else |
| Get_Name_String (Lib_Standalone.Value); |
| To_Lower (Name_Buffer (1 .. Name_Len)); |
| |
| if Name_Buffer (1 .. Name_Len) = "standard" then |
| Project.Standalone_Library := Standard; |
| |
| elsif Name_Buffer (1 .. Name_Len) = "encapsulated" then |
| Project.Standalone_Library := Encapsulated; |
| |
| elsif Name_Buffer (1 .. Name_Len) = "no" then |
| Project.Standalone_Library := No; |
| Error_Msg |
| (Data.Flags, |
| "wrong value for Library_Standalone " |
| & "when Library_Interface defined", |
| Lib_Standalone.Location, Project); |
| |
| else |
| Error_Msg |
| (Data.Flags, |
| "invalid value for attribute Library_Standalone", |
| Lib_Standalone.Location, Project); |
| end if; |
| end if; |
| |
| -- Check value of attribute Library_Auto_Init and set Lib_Auto_Init |
| -- accordingly. |
| |
| if Lib_Auto_Init.Default then |
| |
| -- If no attribute Library_Auto_Init is declared, then set auto |
| -- init only if it is supported. |
| |
| Project.Lib_Auto_Init := Auto_Init_Supported; |
| |
| else |
| Get_Name_String (Lib_Auto_Init.Value); |
| To_Lower (Name_Buffer (1 .. Name_Len)); |
| |
| if Name_Buffer (1 .. Name_Len) = "false" then |
| Project.Lib_Auto_Init := False; |
| |
| elsif Name_Buffer (1 .. Name_Len) = "true" then |
| if Auto_Init_Supported then |
| Project.Lib_Auto_Init := True; |
| |
| else |
| -- Library_Auto_Init cannot be "true" if auto init is not |
| -- supported. |
| |
| Error_Msg |
| (Data.Flags, |
| "library auto init not supported " & |
| "on this platform", |
| Lib_Auto_Init.Location, Project); |
| end if; |
| |
| else |
| Error_Msg |
| (Data.Flags, |
| "invalid value for attribute Library_Auto_Init", |
| Lib_Auto_Init.Location, Project); |
| end if; |
| end if; |
| |
| -- If attribute Library_Src_Dir is defined and not the empty string, |
| -- check if the directory exist and is not the object directory or |
| -- one of the source directories. This is the directory where copies |
| -- of the interface sources will be copied. Note that this directory |
| -- may be the library directory. |
| |
| if Lib_Src_Dir.Value /= Empty_String then |
| declare |
| Dir_Id : constant File_Name_Type := |
| File_Name_Type (Lib_Src_Dir.Value); |
| Dir_Exists : Boolean; |
| |
| begin |
| Locate_Directory |
| (Project, |
| Dir_Id, |
| Path => Project.Library_Src_Dir, |
| Dir_Exists => Dir_Exists, |
| Data => Data, |
| Must_Exist => False, |
| Create => "library source copy", |
| Location => Lib_Src_Dir.Location, |
| Externally_Built => Project.Externally_Built); |
| |
| -- If directory does not exist, report an error |
| |
| if not Dir_Exists then |
| |
| -- Get the absolute name of the library directory that does |
| -- not exist, to report an error. |
| |
| Err_Vars.Error_Msg_File_1 := |
| File_Name_Type (Project.Library_Src_Dir.Display_Name); |
| Error_Msg |
| (Data.Flags, |
| "Directory { does not exist", |
| Lib_Src_Dir.Location, Project); |
| |
| -- Report error if it is the same as the object directory |
| |
| elsif Project.Library_Src_Dir = Project.Object_Directory then |
| Error_Msg |
| (Data.Flags, |
| "directory to copy interfaces cannot be " & |
| "the object directory", |
| Lib_Src_Dir.Location, Project); |
| Project.Library_Src_Dir := No_Path_Information; |
| |
| else |
| declare |
| Src_Dirs : String_List_Id; |
| Src_Dir : String_Element; |
| Pid : Project_List; |
| |
| begin |
| -- Interface copy directory cannot be one of the source |
| -- directory of the current project. |
| |
| Src_Dirs := Project.Source_Dirs; |
| while Src_Dirs /= Nil_String loop |
| Src_Dir := Shared.String_Elements.Table (Src_Dirs); |
| |
| -- Report error if it is one of the source directories |
| |
| if Project.Library_Src_Dir.Name = |
| Path_Name_Type (Src_Dir.Value) |
| then |
| Error_Msg |
| (Data.Flags, |
| "directory to copy interfaces cannot " & |
| "be one of the source directories", |
| Lib_Src_Dir.Location, Project); |
| Project.Library_Src_Dir := No_Path_Information; |
| exit; |
| end if; |
| |
| Src_Dirs := Src_Dir.Next; |
| end loop; |
| |
| if Project.Library_Src_Dir /= No_Path_Information then |
| |
| -- It cannot be a source directory of any other |
| -- project either. |
| |
| Pid := Data.Tree.Projects; |
| Project_Loop : loop |
| exit Project_Loop when Pid = null; |
| |
| Src_Dirs := Pid.Project.Source_Dirs; |
| Dir_Loop : while Src_Dirs /= Nil_String loop |
| Src_Dir := |
| Shared.String_Elements.Table (Src_Dirs); |
| |
| -- Report error if it is one of the source |
| -- directories. |
| |
| if Project.Library_Src_Dir.Name = |
| Path_Name_Type (Src_Dir.Value) |
| then |
| Error_Msg_File_1 := |
| File_Name_Type (Src_Dir.Value); |
| Error_Msg_Name_1 := Pid.Project.Name; |
| Error_Msg |
| (Data.Flags, |
| "directory to copy interfaces cannot " & |
| "be the same as source directory { of " & |
| "project %%", |
| Lib_Src_Dir.Location, Project); |
| Project.Library_Src_Dir := |
| No_Path_Information; |
| exit Project_Loop; |
| end if; |
| |
| Src_Dirs := Src_Dir.Next; |
| end loop Dir_Loop; |
| |
| Pid := Pid.Next; |
| end loop Project_Loop; |
| end if; |
| end; |
| |
| -- In high verbosity, if there is a valid Library_Src_Dir, |
| -- display its path name. |
| |
| if Project.Library_Src_Dir /= No_Path_Information |
| and then Current_Verbosity = High |
| then |
| Write_Attr |
| ("Directory to copy interfaces", |
| Get_Name_String (Project.Library_Src_Dir.Name)); |
| end if; |
| end if; |
| end; |
| end if; |
| |
| -- Check the symbol related attributes |
| |
| -- First, the symbol policy |
| |
| if not Lib_Symbol_Policy.Default then |
| declare |
| Value : constant String := |
| To_Lower |
| (Get_Name_String (Lib_Symbol_Policy.Value)); |
| |
| begin |
| -- Symbol policy must have one of a limited number of values |
| |
| if Value = "autonomous" or else Value = "default" then |
| Project.Symbol_Data.Symbol_Policy := Autonomous; |
| |
| elsif Value = "compliant" then |
| Project.Symbol_Data.Symbol_Policy := Compliant; |
| |
| elsif Value = "controlled" then |
| Project.Symbol_Data.Symbol_Policy := Controlled; |
| |
| elsif Value = "restricted" then |
| Project.Symbol_Data.Symbol_Policy := Restricted; |
| |
| elsif Value = "direct" then |
| Project.Symbol_Data.Symbol_Policy := Direct; |
| |
| else |
| Error_Msg |
| (Data.Flags, |
| "illegal value for Library_Symbol_Policy", |
| Lib_Symbol_Policy.Location, Project); |
| end if; |
| end; |
| end if; |
| |
| -- If attribute Library_Symbol_File is not specified, symbol policy |
| -- cannot be Restricted. |
| |
| if Lib_Symbol_File.Default then |
| if Project.Symbol_Data.Symbol_Policy = Restricted then |
| Error_Msg |
| (Data.Flags, |
| "Library_Symbol_File needs to be defined when " & |
| "symbol policy is Restricted", |
| Lib_Symbol_Policy.Location, Project); |
| end if; |
| |
| else |
| -- Library_Symbol_File is defined |
| |
| Project.Symbol_Data.Symbol_File := |
| Path_Name_Type (Lib_Symbol_File.Value); |
| |
| Get_Name_String (Lib_Symbol_File.Value); |
| |
| if Name_Len = 0 then |
| Error_Msg |
| (Data.Flags, |
| "symbol file name cannot be an empty string", |
| Lib_Symbol_File.Location, Project); |
| |
| else |
| OK := not Is_Absolute_Path (Name_Buffer (1 .. Name_Len)); |
| |
| if OK then |
| for J in 1 .. Name_Len loop |
| if Name_Buffer (J) = '/' |
| or else Name_Buffer (J) = Directory_Separator |
| then |
| OK := False; |
| exit; |
| end if; |
| end loop; |
| end if; |
| |
| if not OK then |
| Error_Msg_File_1 := File_Name_Type (Lib_Symbol_File.Value); |
| Error_Msg |
| (Data.Flags, |
| "symbol file name { is illegal. " & |
| "Name cannot include directory info.", |
| Lib_Symbol_File.Location, Project); |
| end if; |
| end if; |
| end if; |
| |
| -- If attribute Library_Reference_Symbol_File is not defined, |
| -- symbol policy cannot be Compliant or Controlled. |
| |
| if Lib_Ref_Symbol_File.Default then |
| if Project.Symbol_Data.Symbol_Policy = Compliant |
| or else Project.Symbol_Data.Symbol_Policy = Controlled |
| then |
| Error_Msg |
| (Data.Flags, |
| "a reference symbol file needs to be defined", |
| Lib_Symbol_Policy.Location, Project); |
| end if; |
| |
| else |
| -- Library_Reference_Symbol_File is defined, check file exists |
| |
| Project.Symbol_Data.Reference := |
| Path_Name_Type (Lib_Ref_Symbol_File.Value); |
| |
| Get_Name_String (Lib_Ref_Symbol_File.Value); |
| |
| if Name_Len = 0 then |
| Error_Msg |
| (Data.Flags, |
| "reference symbol file name cannot be an empty string", |
| Lib_Symbol_File.Location, Project); |
| |
| else |
| if not Is_Absolute_Path (Name_Buffer (1 .. Name_Len)) then |
| Name_Len := 0; |
| Add_Str_To_Name_Buffer |
| (Get_Name_String (Project.Directory.Name)); |
| Add_Str_To_Name_Buffer |
| (Get_Name_String (Lib_Ref_Symbol_File.Value)); |
| Project.Symbol_Data.Reference := Name_Find; |
| end if; |
| |
| if not Is_Regular_File |
| (Get_Name_String (Project.Symbol_Data.Reference)) |
| then |
| Error_Msg_File_1 := |
| File_Name_Type (Lib_Ref_Symbol_File.Value); |
| |
| -- For controlled and direct symbol policies, it is an error |
| -- if the reference symbol file does not exist. For other |
| -- symbol policies, this is just a warning |
| |
| Error_Msg_Warn := |
| Project.Symbol_Data.Symbol_Policy /= Controlled |
| and then Project.Symbol_Data.Symbol_Policy /= Direct; |
| |
| Error_Msg |
| (Data.Flags, |
| "<library reference symbol file { does not exist", |
| Lib_Ref_Symbol_File.Location, Project); |
| |
| -- In addition in the non-controlled case, if symbol policy |
| -- is Compliant, it is changed to Autonomous, because there |
| -- is no reference to check against, and we don't want to |
| -- fail in this case. |
| |
| if Project.Symbol_Data.Symbol_Policy /= Controlled then |
| if Project.Symbol_Data.Symbol_Policy = Compliant then |
| Project.Symbol_Data.Symbol_Policy := Autonomous; |
| end if; |
| end if; |
| end if; |
| |
| -- If both the reference symbol file and the symbol file are |
| -- defined, then check that they are not the same file. |
| |
| if Project.Symbol_Data.Symbol_File /= No_Path then |
| Get_Name_String (Project.Symbol_Data.Symbol_File); |
| |
| if Name_Len > 0 then |
| declare |
| -- We do not need to pass a Directory to |
| -- Normalize_Pathname, since the path_information |
| -- already contains absolute information. |
| |
| Symb_Path : constant String := |
| Normalize_Pathname |
| (Get_Name_String |
| (Project.Object_Directory.Name) & |
| Name_Buffer (1 .. Name_Len), |
| Directory => "/", |
| Resolve_Links => |
| Opt.Follow_Links_For_Files); |
| Ref_Path : constant String := |
| Normalize_Pathname |
| (Get_Name_String |
| (Project.Symbol_Data.Reference), |
| Directory => "/", |
| Resolve_Links => |
| Opt.Follow_Links_For_Files); |
| begin |
| if Symb_Path = Ref_Path then |
| Error_Msg |
| (Data.Flags, |
| "library reference symbol file and library" & |
| " symbol file cannot be the same file", |
| Lib_Ref_Symbol_File.Location, Project); |
| end if; |
| end; |
| end if; |
| end if; |
| end if; |
| end if; |
| end if; |
| end Check_Stand_Alone_Library; |
| |
| --------------------- |
| -- Check_Unit_Name -- |
| --------------------- |
| |
| procedure Check_Unit_Name (Name : String; Unit : out Name_Id) is |
| The_Name : String := Name; |
| Real_Name : Name_Id; |
| Need_Letter : Boolean := True; |
| Last_Underscore : Boolean := False; |
| OK : Boolean := The_Name'Length > 0; |
| First : Positive; |
| |
| function Is_Reserved (Name : Name_Id) return Boolean; |
| function Is_Reserved (S : String) return Boolean; |
| -- Check that the given name is not an Ada 95 reserved word. The reason |
| -- for the Ada 95 here is that we do not want to exclude the case of an |
| -- Ada 95 unit called Interface (for example). In Ada 2005, such a unit |
| -- name would be rejected anyway by the compiler. That means there is no |
| -- requirement that the project file parser reject this. |
| |
| ----------------- |
| -- Is_Reserved -- |
| ----------------- |
| |
| function Is_Reserved (S : String) return Boolean is |
| begin |
| Name_Len := 0; |
| Add_Str_To_Name_Buffer (S); |
| return Is_Reserved (Name_Find); |
| end Is_Reserved; |
| |
| ----------------- |
| -- Is_Reserved -- |
| ----------------- |
| |
| function Is_Reserved (Name : Name_Id) return Boolean is |
| begin |
| if Get_Name_Table_Byte (Name) /= 0 |
| and then Name /= Name_Project |
| and then Name /= Name_Extends |
| and then Name /= Name_External |
| and then Name not in Ada_2005_Reserved_Words |
| then |
| Unit := No_Name; |
| Debug_Output ("Ada reserved word: ", Name); |
| return True; |
| |
| else |
| return False; |
| end if; |
| end Is_Reserved; |
| |
| -- Start of processing for Check_Unit_Name |
| |
| begin |
| To_Lower (The_Name); |
| |
| Name_Len := The_Name'Length; |
| Name_Buffer (1 .. Name_Len) := The_Name; |
| |
| -- Special cases of children of packages A, G, I and S on VMS |
| |
| if OpenVMS_On_Target |
| and then Name_Len > 3 |
| and then Name_Buffer (2 .. 3) = "__" |
| and then |
| (Name_Buffer (1) = 'a' or else |
| Name_Buffer (1) = 'g' or else |
| Name_Buffer (1) = 'i' or else |
| Name_Buffer (1) = 's') |
| then |
| Name_Buffer (2) := '.'; |
| Name_Buffer (3 .. Name_Len - 1) := Name_Buffer (4 .. Name_Len); |
| Name_Len := Name_Len - 1; |
| end if; |
| |
| Real_Name := Name_Find; |
| |
| if Is_Reserved (Real_Name) then |
| return; |
| end if; |
| |
| First := The_Name'First; |
| |
| for Index in The_Name'Range loop |
| if Need_Letter then |
| |
| -- We need a letter (at the beginning, and following a dot), |
| -- but we don't have one. |
| |
| if Is_Letter (The_Name (Index)) then |
| Need_Letter := False; |
| |
| else |
| OK := False; |
| |
| if Current_Verbosity = High then |
| Debug_Indent; |
| Write_Int (Types.Int (Index)); |
| Write_Str (": '"); |
| Write_Char (The_Name (Index)); |
| Write_Line ("' is not a letter."); |
| end if; |
| |
| exit; |
| end if; |
| |
| elsif Last_Underscore |
| and then (The_Name (Index) = '_' or else The_Name (Index) = '.') |
| then |
| -- Two underscores are illegal, and a dot cannot follow |
| -- an underscore. |
| |
| OK := False; |
| |
| if Current_Verbosity = High then |
| Debug_Indent; |
| Write_Int (Types.Int (Index)); |
| Write_Str (": '"); |
| Write_Char (The_Name (Index)); |
| Write_Line ("' is illegal here."); |
| end if; |
| |
| exit; |
| |
| elsif The_Name (Index) = '.' then |
| |
| -- First, check if the name before the dot is not a reserved word |
| |
| if Is_Reserved (The_Name (First .. Index - 1)) then |
| return; |
| end if; |
| |
| First := Index + 1; |
| |
| -- We need a letter after a dot |
| |
| Need_Letter := True; |
| |
| elsif The_Name (Index) = '_' then |
| Last_Underscore := True; |
| |
| else |
| -- We need an letter or a digit |
| |
| Last_Underscore := False; |
| |
| if not Is_Alphanumeric (The_Name (Index)) then |
| OK := False; |
| |
| if Current_Verbosity = High then |
| Debug_Indent; |
| Write_Int (Types.Int (Index)); |
| Write_Str (": '"); |
| Write_Char (The_Name (Index)); |
| Write_Line ("' is not alphanumeric."); |
| end if; |
| |
| exit; |
| end if; |
| end if; |
| end loop; |
| |
| -- Cannot end with an underscore or a dot |
| |
| OK := OK and then not Need_Letter and then not Last_Underscore; |
| |
| if OK then |
| if First /= Name'First |
| and then Is_Reserved (The_Name (First .. The_Name'Last)) |
| then |
| return; |
| end if; |
| |
| Unit := Real_Name; |
| |
| else |
| -- Signal a problem with No_Name |
| |
| Unit := No_Name; |
| end if; |
| end Check_Unit_Name; |
| |
| ---------------------------- |
| -- Compute_Directory_Last -- |
| ---------------------------- |
| |
| function Compute_Directory_Last (Dir : String) return Natural is |
| begin |
| if Dir'Length > 1 |
| and then (Dir (Dir'Last - 1) = Directory_Separator |
| or else |
| Dir (Dir'Last - 1) = '/') |
| then |
| return Dir'Last - 1; |
| else |
| return Dir'Last; |
| end if; |
| end Compute_Directory_Last; |
| |
| --------------------- |
| -- Get_Directories -- |
| --------------------- |
| |
| procedure Get_Directories |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data) |
| is |
| Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared; |
| |
| Object_Dir : constant Variable_Value := |
| Util.Value_Of |
| (Name_Object_Dir, Project.Decl.Attributes, Shared); |
| |
| Exec_Dir : constant Variable_Value := |
| Util.Value_Of |
| (Name_Exec_Dir, Project.Decl.Attributes, Shared); |
| |
| Source_Dirs : constant Variable_Value := |
| Util.Value_Of |
| (Name_Source_Dirs, Project.Decl.Attributes, Shared); |
| |
| Ignore_Source_Sub_Dirs : constant Variable_Value := |
| Util.Value_Of |
| (Name_Ignore_Source_Sub_Dirs, |
| Project.Decl.Attributes, |
| Shared); |
| |
| Excluded_Source_Dirs : constant Variable_Value := |
| Util.Value_Of |
| (Name_Excluded_Source_Dirs, |
| Project.Decl.Attributes, |
| Shared); |
| |
| Source_Files : constant Variable_Value := |
| Util.Value_Of |
| (Name_Source_Files, |
| Project.Decl.Attributes, Shared); |
| |
| Last_Source_Dir : String_List_Id := Nil_String; |
| Last_Src_Dir_Rank : Number_List_Index := No_Number_List; |
| |
| Languages : constant Variable_Value := |
| Prj.Util.Value_Of |
| (Name_Languages, Project.Decl.Attributes, Shared); |
| |
| Remove_Source_Dirs : Boolean := False; |
| |
| procedure Add_To_Or_Remove_From_Source_Dirs |
| (Path : Path_Information; |
| Rank : Natural); |
| -- When Removed = False, the directory Path_Id to the list of |
| -- source_dirs if not already in the list. When Removed = True, |
| -- removed directory Path_Id if in the list. |
| |
| procedure Find_Source_Dirs is new Expand_Subdirectory_Pattern |
| (Add_To_Or_Remove_From_Source_Dirs); |
| |
| --------------------------------------- |
| -- Add_To_Or_Remove_From_Source_Dirs -- |
| --------------------------------------- |
| |
| procedure Add_To_Or_Remove_From_Source_Dirs |
| (Path : Path_Information; |
| Rank : Natural) |
| is |
| List : String_List_Id; |
| Prev : String_List_Id; |
| Rank_List : Number_List_Index; |
| Prev_Rank : Number_List_Index; |
| Element : String_Element; |
| |
| begin |
| Prev := Nil_String; |
| Prev_Rank := No_Number_List; |
| List := Project.Source_Dirs; |
| Rank_List := Project.Source_Dir_Ranks; |
| while List /= Nil_String loop |
| Element := Shared.String_Elements.Table (List); |
| exit when Element.Value = Name_Id (Path.Name); |
| Prev := List; |
| List := Element.Next; |
| Prev_Rank := Rank_List; |
| Rank_List := Shared.Number_Lists.Table (Prev_Rank).Next; |
| end loop; |
| |
| -- The directory is in the list if List is not Nil_String |
| |
| if not Remove_Source_Dirs and then List = Nil_String then |
| Debug_Output ("adding source dir=", Name_Id (Path.Display_Name)); |
| |
| String_Element_Table.Increment_Last (Shared.String_Elements); |
| Element := |
| (Value => Name_Id (Path.Name), |
| Index => 0, |
| Display_Value => Name_Id (Path.Display_Name), |
| Location => No_Location, |
| Flag => False, |
| Next => Nil_String); |
| |
| Number_List_Table.Increment_Last (Shared.Number_Lists); |
| |
| if Last_Source_Dir = Nil_String then |
| |
| -- This is the first source directory |
| |
| Project.Source_Dirs := |
| String_Element_Table.Last (Shared.String_Elements); |
| Project.Source_Dir_Ranks := |
| Number_List_Table.Last (Shared.Number_Lists); |
| |
| else |
| -- We already have source directories, link the previous |
| -- last to the new one. |
| |
| Shared.String_Elements.Table (Last_Source_Dir).Next := |
| String_Element_Table.Last (Shared.String_Elements); |
| Shared.Number_Lists.Table (Last_Src_Dir_Rank).Next := |
| Number_List_Table.Last (Shared.Number_Lists); |
| end if; |
| |
| -- And register this source directory as the new last |
| |
| Last_Source_Dir := |
| String_Element_Table.Last (Shared.String_Elements); |
| Shared.String_Elements.Table (Last_Source_Dir) := Element; |
| Last_Src_Dir_Rank := Number_List_Table.Last (Shared.Number_Lists); |
| Shared.Number_Lists.Table (Last_Src_Dir_Rank) := |
| (Number => Rank, Next => No_Number_List); |
| |
| elsif Remove_Source_Dirs and then List /= Nil_String then |
| |
| -- Remove source dir if present |
| |
| if Prev = Nil_String then |
| Project.Source_Dirs := Shared.String_Elements.Table (List).Next; |
| Project.Source_Dir_Ranks := |
| Shared.Number_Lists.Table (Rank_List).Next; |
| |
| else |
| Shared.String_Elements.Table (Prev).Next := |
| Shared.String_Elements.Table (List).Next; |
| Shared.Number_Lists.Table (Prev_Rank).Next := |
| Shared.Number_Lists.Table (Rank_List).Next; |
| end if; |
| end if; |
| end Add_To_Or_Remove_From_Source_Dirs; |
| |
| -- Local declarations |
| |
| Dir_Exists : Boolean; |
| |
| No_Sources : constant Boolean := |
| ((not Source_Files.Default |
| and then Source_Files.Values = Nil_String) |
| or else |
| (not Source_Dirs.Default |
| and then Source_Dirs.Values = Nil_String) |
| or else |
| (not Languages.Default |
| and then Languages.Values = Nil_String)) |
| and then Project.Extends = No_Project; |
| |
| -- Start of processing for Get_Directories |
| |
| begin |
| Debug_Output ("starting to look for directories"); |
| |
| -- Set the object directory to its default which may be nil, if there |
| -- is no sources in the project. |
| |
| if No_Sources then |
| Project.Object_Directory := No_Path_Information; |
| else |
| Project.Object_Directory := Project.Directory; |
| end if; |
| |
| -- Check the object directory |
| |
| if Object_Dir.Value /= Empty_String then |
| Get_Name_String (Object_Dir.Value); |
| |
| if Name_Len = 0 then |
| Error_Msg |
| (Data.Flags, |
| "Object_Dir cannot be empty", |
| Object_Dir.Location, Project); |
| |
| elsif Setup_Projects |
| and then No_Sources |
| and then Project.Extends = No_Project |
| then |
| -- Do not create an object directory for a non extending project |
| -- with no sources. |
| |
| Locate_Directory |
| (Project, |
| File_Name_Type (Object_Dir.Value), |
| Path => Project.Object_Directory, |
| Dir_Exists => Dir_Exists, |
| Data => Data, |
| Location => Object_Dir.Location, |
| Must_Exist => False, |
| Externally_Built => Project.Externally_Built); |
| |
| else |
| -- We check that the specified object directory does exist. |
| -- However, even when it doesn't exist, we set it to a default |
| -- value. This is for the benefit of tools that recover from |
| -- errors; for example, these tools could create the non existent |
| -- directory. We always return an absolute directory name though. |
| |
| Locate_Directory |
| (Project, |
| File_Name_Type (Object_Dir.Value), |
| Path => Project.Object_Directory, |
| Create => "object", |
| Dir_Exists => Dir_Exists, |
| Data => Data, |
| Location => Object_Dir.Location, |
| Must_Exist => False, |
| Externally_Built => Project.Externally_Built); |
| |
| if not Dir_Exists and then not Project.Externally_Built then |
| |
| -- The object directory does not exist, report an error if the |
| -- project is not externally built. |
| |
| Err_Vars.Error_Msg_File_1 := |
| File_Name_Type (Object_Dir.Value); |
| Error_Or_Warning |
| (Data.Flags, Data.Flags.Require_Obj_Dirs, |
| "object directory { not found", Project.Location, Project); |
| end if; |
| end if; |
| |
| elsif not No_Sources and then Subdirs /= null then |
| Name_Len := 1; |
| Name_Buffer (1) := '.'; |
| Locate_Directory |
| (Project, |
| Name_Find, |
| Path => Project.Object_Directory, |
| Create => "object", |
| Dir_Exists => Dir_Exists, |
| Data => Data, |
| Location => Object_Dir.Location, |
| Externally_Built => Project.Externally_Built); |
| end if; |
| |
| if Current_Verbosity = High then |
| if Project.Object_Directory = No_Path_Information then |
| Debug_Output ("no object directory"); |
| else |
| Write_Attr |
| ("Object directory", |
| Get_Name_String (Project.Object_Directory.Display_Name)); |
| end if; |
| end if; |
| |
| -- Check the exec directory |
| |
| -- We set the object directory to its default |
| |
| Project.Exec_Directory := Project.Object_Directory; |
| |
| if Exec_Dir.Value /= Empty_String then |
| Get_Name_String (Exec_Dir.Value); |
| |
| if Name_Len = 0 then |
| Error_Msg |
| (Data.Flags, |
| "Exec_Dir cannot be empty", |
| Exec_Dir.Location, Project); |
| |
| elsif Setup_Projects |
| and then No_Sources |
| and then Project.Extends = No_Project |
| then |
| -- Do not create an exec directory for a non extending project |
| -- with no sources. |
| |
| Locate_Directory |
| (Project, |
| File_Name_Type (Exec_Dir.Value), |
| Path => Project.Exec_Directory, |
| Dir_Exists => Dir_Exists, |
| Data => Data, |
| Location => Exec_Dir.Location, |
| Externally_Built => Project.Externally_Built); |
| |
| else |
| -- We check that the specified exec directory does exist |
| |
| Locate_Directory |
| (Project, |
| File_Name_Type (Exec_Dir.Value), |
| Path => Project.Exec_Directory, |
| Dir_Exists => Dir_Exists, |
| Data => Data, |
| Create => "exec", |
| Location => Exec_Dir.Location, |
| Externally_Built => Project.Externally_Built); |
| |
| if not Dir_Exists then |
| Err_Vars.Error_Msg_File_1 := File_Name_Type (Exec_Dir.Value); |
| Error_Or_Warning |
| (Data.Flags, Data.Flags.Missing_Source_Files, |
| "exec directory { not found", Project.Location, Project); |
| end if; |
| end if; |
| end if; |
| |
| if Current_Verbosity = High then |
| if Project.Exec_Directory = No_Path_Information then |
| Debug_Output ("no exec directory"); |
| else |
| Debug_Output |
| ("exec directory: ", |
| Name_Id (Project.Exec_Directory.Display_Name)); |
| end if; |
| end if; |
| |
| -- Look for the source directories |
| |
| Debug_Output ("starting to look for source directories"); |
| |
| pragma Assert (Source_Dirs.Kind = List, "Source_Dirs is not a list"); |
| |
| if not Source_Files.Default |
| and then Source_Files.Values = Nil_String |
| then |
| Project.Source_Dirs := Nil_String; |
| |
| if Project.Qualifier = Standard then |
| Error_Msg |
| (Data.Flags, |
| "a standard project cannot have no sources", |
| Source_Files.Location, Project); |
| end if; |
| |
| elsif Source_Dirs.Default then |
| |
| -- No Source_Dirs specified: the single source directory is the one |
| -- containing the project file. |
| |
| Remove_Source_Dirs := False; |
| Add_To_Or_Remove_From_Source_Dirs |
| (Path => (Name => Project.Directory.Name, |
| Display_Name => Project.Directory.Display_Name), |
| Rank => 1); |
| |
| else |
| Remove_Source_Dirs := False; |
| Find_Source_Dirs |
| (Project => Project, |
| Data => Data, |
| Patterns => Source_Dirs.Values, |
| Ignore => Ignore_Source_Sub_Dirs.Values, |
| Search_For => Search_Directories, |
| Resolve_Links => Opt.Follow_Links_For_Dirs); |
| |
| if Project.Source_Dirs = Nil_String |
| and then Project.Qualifier = Standard |
| then |
| Error_Msg |
| (Data.Flags, |
| "a standard project cannot have no source directories", |
| Source_Dirs.Location, Project); |
| end if; |
| end if; |
| |
| if not Excluded_Source_Dirs.Default |
| and then Excluded_Source_Dirs.Values /= Nil_String |
| then |
| Remove_Source_Dirs := True; |
| Find_Source_Dirs |
| (Project => Project, |
| Data => Data, |
| Patterns => Excluded_Source_Dirs.Values, |
| Ignore => Nil_String, |
| Search_For => Search_Directories, |
| Resolve_Links => Opt.Follow_Links_For_Dirs); |
| end if; |
| |
| Debug_Output ("putting source directories in canonical cases"); |
| |
| declare |
| Current : String_List_Id := Project.Source_Dirs; |
| Element : String_Element; |
| |
| begin |
| while Current /= Nil_String loop |
| Element := Shared.String_Elements.Table (Current); |
| if Element.Value /= No_Name then |
| Element.Value := |
| Name_Id (Canonical_Case_File_Name (Element.Value)); |
| Shared.String_Elements.Table (Current) := Element; |
| end if; |
| |
| Current := Element.Next; |
| end loop; |
| end; |
| end Get_Directories; |
| |
| --------------- |
| -- Get_Mains -- |
| --------------- |
| |
| procedure Get_Mains |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data) |
| is |
| Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared; |
| |
| Mains : constant Variable_Value := |
| Prj.Util.Value_Of |
| (Name_Main, Project.Decl.Attributes, Shared); |
| List : String_List_Id; |
| Elem : String_Element; |
| |
| begin |
| Project.Mains := Mains.Values; |
| |
| -- If no Mains were specified, and if we are an extending project, |
| -- inherit the Mains from the project we are extending. |
| |
| if Mains.Default then |
| if not Project.Library and then Project.Extends /= No_Project then |
| Project.Mains := Project.Extends.Mains; |
| end if; |
| |
| -- In a library project file, Main cannot be specified |
| |
| elsif Project.Library then |
| Error_Msg |
| (Data.Flags, |
| "a library project file cannot have Main specified", |
| Mains.Location, Project); |
| |
| else |
| List := Mains.Values; |
| while List /= Nil_String loop |
| Elem := Shared.String_Elements.Table (List); |
| |
| if Length_Of_Name (Elem.Value) = 0 then |
| Error_Msg |
| (Data.Flags, |
| "?a main cannot have an empty name", |
| Elem.Location, Project); |
| exit; |
| end if; |
| |
| List := Elem.Next; |
| end loop; |
| end if; |
| end Get_Mains; |
| |
| --------------------------- |
| -- Get_Sources_From_File -- |
| --------------------------- |
| |
| procedure Get_Sources_From_File |
| (Path : String; |
| Location : Source_Ptr; |
| Project : in out Project_Processing_Data; |
| Data : in out Tree_Processing_Data) |
| is |
| File : Prj.Util.Text_File; |
| Line : String (1 .. 250); |
| Last : Natural; |
| Source_Name : File_Name_Type; |
| Name_Loc : Name_Location; |
| |
| begin |
| if Current_Verbosity = High then |
| Debug_Output ("opening """ & Path & '"'); |
| end if; |
| |
| -- Open the file |
| |
| Prj.Util.Open (File, Path); |
| |
| if not Prj.Util.Is_Valid (File) then |
| Error_Msg |
| (Data.Flags, "file does not exist", Location, Project.Project); |
| |
| else |
| -- Read the lines one by one |
| |
| while not Prj.Util.End_Of_File (File) loop |
| Prj.Util.Get_Line (File, Line, Last); |
| |
| -- A non empty, non comment line should contain a file name |
| |
| if Last /= 0 |
| and then (Last = 1 or else Line (1 .. 2) /= "--") |
| then |
| Name_Len := Last; |
| Name_Buffer (1 .. Name_Len) := Line (1 .. Last); |
| Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); |
| Source_Name := Name_Find; |
| |
| -- Check that there is no directory information |
| |
| for J in 1 .. Last loop |
| if Line (J) = '/' or else Line (J) = Directory_Separator then |
| Error_Msg_File_1 := Source_Name; |
| Error_Msg |
| (Data.Flags, |
| "file name cannot include directory information ({)", |
| Location, Project.Project); |
| exit; |
| end if; |
| end loop; |
| |
| Name_Loc := Source_Names_Htable.Get |
| (Project.Source_Names, Source_Name); |
| |
| if Name_Loc = No_Name_Location then |
| Name_Loc := |
| (Name => Source_Name, |
| Location => Location, |
| Source => No_Source, |
| Listed => True, |
| Found => False); |
| |
| else |
| Name_Loc.Listed := True; |
| end if; |
| |
| Source_Names_Htable.Set |
| (Project.Source_Names, Source_Name, Name_Loc); |
| end if; |
| end loop; |
| |
| Prj.Util.Close (File); |
| |
| end if; |
| end Get_Sources_From_File; |
| |
| ------------------ |
| -- No_Space_Img -- |
| ------------------ |
| |
| function No_Space_Img (N : Natural) return String is |
| Image : constant String := N'Img; |
| begin |
| return Image (2 .. Image'Last); |
| end No_Space_Img; |
| |
| ----------------------- |
| -- Compute_Unit_Name -- |
| ----------------------- |
| |
| procedure Compute_Unit_Name |
| (File_Name : File_Name_Type; |
| Naming : Lang_Naming_Data; |
| Kind : out Source_Kind; |
| Unit : out Name_Id; |
| Project : Project_Processing_Data) |
| is |
| Filename : constant String := Get_Name_String (File_Name); |
| Last : Integer := Filename'Last; |
| Sep_Len : Integer; |
| Body_Len : Integer; |
| Spec_Len : Integer; |
| |
| Unit_Except : Unit_Exception; |
| Masked : Boolean := False; |
| |
| begin |
| Unit := No_Name; |
| Kind := Spec; |
| |
| if Naming.Separate_Suffix = No_File |
| or else Naming.Body_Suffix = No_File |
| or else Naming.Spec_Suffix = No_File |
| then |
| return; |
| end if; |
| |
| if Naming.Dot_Replacement = No_File then |
| Debug_Output ("no dot_replacement specified"); |
| return; |
| end if; |
| |
| Sep_Len := Integer (Length_Of_Name (Naming.Separate_Suffix)); |
| Spec_Len := Integer (Length_Of_Name (Naming.Spec_Suffix)); |
| Body_Len := Integer (Length_Of_Name (Naming.Body_Suffix)); |
| |
| -- Choose the longest suffix that matches. If there are several matches, |
| -- give priority to specs, then bodies, then separates. |
| |
| if Naming.Separate_Suffix /= Naming.Body_Suffix |
| and then Suffix_Matches (Filename, Naming.Separate_Suffix) |
| then |
| Last := Filename'Last - Sep_Len; |
| Kind := Sep; |
| end if; |
| |
| if Filename'Last - Body_Len <= Last |
| and then Suffix_Matches (Filename, Naming.Body_Suffix) |
| then |
| Last := Natural'Min (Last, Filename'Last - Body_Len); |
| Kind := Impl; |
| end if; |
| |
| if Filename'Last - Spec_Len <= Last |
| and then Suffix_Matches (Filename, Naming.Spec_Suffix) |
| then |
| Last := Natural'Min (Last, Filename'Last - Spec_Len); |
| Kind := Spec; |
| end if; |
| |
| if Last = Filename'Last then |
| Debug_Output ("no matching suffix"); |
| return; |
| end if; |
| |
| -- Check that the casing matches |
| |
| if File_Names_Case_Sensitive then |
| case Naming.Casing is |
| when All_Lower_Case => |
| for J in Filename'First .. Last loop |
| if Is_Letter (Filename (J)) |
| and then not Is_Lower (Filename (J)) |
| then |
| Debug_Output ("invalid casing"); |
| return; |
| end if; |
| end loop; |
| |
| when All_Upper_Case => |
| for J in Filename'First .. Last loop |
| if Is_Letter (Filename (J)) |
| and then not Is_Upper (Filename (J)) |
| then |
| Debug_Output ("invalid casing"); |
| return; |
| end if; |
| end loop; |
| |
| when Mixed_Case | Unknown => |
| null; |
| end case; |
| end if; |
| |
| -- If Dot_Replacement is not a single dot, then there should not |
| -- be any dot in the name. |
| |
| declare |
| Dot_Repl : constant String := |
| Get_Name_String (Naming.Dot_Replacement); |
| |
| begin |
| if Dot_Repl /= "." then |
| for Index in Filename'First .. Last loop |
| if Filename (Index) = '.' then |
| Debug_Output ("invalid name, contains dot"); |
| return; |
| end if; |
| end loop; |
| |
| Replace_Into_Name_Buffer |
| (Filename (Filename'First .. Last), Dot_Repl, '.'); |
| |
| else |
| Name_Len := Last - Filename'First + 1; |
| Name_Buffer (1 .. Name_Len) := Filename (Filename'First .. Last); |
| Fixed.Translate |
| (Source => Name_Buffer (1 .. Name_Len), |
| Mapping => Lower_Case_Map); |
| end if; |
| end; |
| |
| -- In the standard GNAT naming scheme, check for special cases: children |
| -- or separates of A, G, I or S, and run time sources. |
| |
| if Is_Standard_GNAT_Naming (Naming) |
| and then Name_Len >= 3 |
| then |
| declare |
| S1 : constant Character := Name_Buffer (1); |
| S2 : constant Character := Name_Buffer (2); |
| S3 : constant Character := Name_Buffer (3); |
| |
| begin |
| if S1 = 'a' |
| or else S1 = 'g' |
| or else S1 = 'i' |
| or else S1 = 's' |
| then |
| -- Children or separates of packages A, G, I or S. These names |
| -- are x__ ... or x~... (where x is a, g, i, or s). Both |
| -- versions (x__... and x~...) are allowed in all platforms, |
| -- because it is not possible to know the platform before |
| -- processing of the project files. |
| |
| if S2 = '_' and then S3 = '_' then |
| Name_Buffer (2) := '.'; |
| Name_Buffer (3 .. Name_Len - 1) := |
| Name_Buffer (4 .. Name_Len); |
| Name_Len := Name_Len - 1; |
| |
| elsif S2 = '~' then |
| Name_Buffer (2) := '.'; |
| |
| elsif S2 = '.' then |
| |
| -- If it is potentially a run time source |
| |
| null; |
| end if; |
| end if; |
| end; |
| end if; |
| |
| -- Name_Buffer contains the name of the unit in lower-cases. Check |
| -- that this is a valid unit name |
| |
| Check_Unit_Name (Name_Buffer (1 .. Name_Len), Unit); |
| |
| -- If there is a naming exception for the same unit, the file is not |
| -- a source for the unit. |
| |
| if Unit /= No_Name then |
| Unit_Except := |
| Unit_Exceptions_Htable.Get (Project.Unit_Exceptions, Unit); |
| |
| if Kind = Spec then |
| Masked := Unit_Except.Spec /= No_File |
| and then |
| Unit_Except.Spec /= File_Name; |
| else |
| Masked := Unit_Except.Impl /= No_File |
| and then |
| Unit_Except.Impl /= File_Name; |
| end if; |
| |
| if Masked then |
| if Current_Verbosity = High then |
| Debug_Indent; |
| Write_Str (" """ & Filename & """ contains the "); |
| |
| if Kind = Spec then |
| Write_Str ("spec of a unit found in """); |
| Write_Str (Get_Name_String (Unit_Except.Spec)); |
| else |
| Write_Str ("body of a unit found in """); |
| Write_Str (Get_Name_String (Unit_Except.Impl)); |
| end if; |
| |
| Write_Line (""" (ignored)"); |
| end if; |
| |
| Unit := No_Name; |
| end if; |
| end if; |
| |
| if Unit /= No_Name |
| and then Current_Verbosity = High |
| then |
| case Kind is |
| when Spec => Debug_Output ("spec of", Unit); |
| when Impl => Debug_Output ("body of", Unit); |
| when Sep => Debug_Output ("sep of", Unit); |
| end case; |
| end if; |
| end Compute_Unit_Name; |
| |
| -------------------------- |
| -- Check_Illegal_Suffix -- |
| -------------------------- |
| |
| procedure Check_Illegal_Suffix |
| (Project : Project_Id; |
| Suffix : File_Name_Type; |
| Dot_Replacement : File_Name_Type; |
| Attribute_Name : String; |
| Location : Source_Ptr; |
| Data : in out Tree_Processing_Data) |
| is |
| Suffix_Str : constant String := Get_Name_String (Suffix); |
| |
| begin |
| if Suffix_Str'Length = 0 then |
| |
| -- Always valid |
| |
| return; |
| |
| elsif Index (Suffix_Str, ".") = 0 then |
| Err_Vars.Error_Msg_File_1 := Suffix; |
| Error_Msg |
| (Data.Flags, |
| "{ is illegal for " & Attribute_Name & ": must have a dot", |
| Location, Project); |
| return; |
| end if; |
| |
| -- Case of dot replacement is a single dot, and first character of |
| -- suffix is also a dot. |
| |
| if Dot_Replacement /= No_File |
| and then Get_Name_String (Dot_Replacement) = "." |
| and then Suffix_Str (Suffix_Str'First) = '.' |
| then |
| for Index in Suffix_Str'First + 1 .. Suffix_Str'Last loop |
| |
| -- If there are multiple dots in the name |
| |
| if Suffix_Str (Index) = '.' then |
| |
| -- It is illegal to have a letter following the initial dot |
| |
| if Is_Letter (Suffix_Str (Suffix_Str'First + 1)) then |
| Err_Vars.Error_Msg_File_1 := Suffix; |
| Error_Msg |
| (Data.Flags, |
| "{ is illegal for " & Attribute_Name |
| & ": ambiguous prefix when Dot_Replacement is a dot", |
| Location, Project); |
| end if; |
| return; |
| end if; |
| end loop; |
| end if; |
| end Check_Illegal_Suffix; |
| |
| ---------------------- |
| -- Locate_Directory -- |
| ---------------------- |
| |
| procedure Locate_Directory |
| (Project : Project_Id; |
| Name : File_Name_Type; |
| Path : out Path_Information; |
| Dir_Exists : out Boolean; |
| Data : in out Tree_Processing_Data; |
| Create : String := ""; |
| Location : Source_Ptr := No_Location; |
| Must_Exist : Boolean := True; |
| Externally_Built : Boolean := False) |
| is |
| Parent : constant Path_Name_Type := |
| Project.Directory.Display_Name; |
| The_Parent : constant String := |
| Get_Name_String (Parent); |
| The_Parent_Last : constant Natural := |
| Compute_Directory_Last (The_Parent); |
| Full_Name : File_Name_Type; |
| The_Name : File_Name_Type; |
| |
| begin |
| Get_Name_String (Name); |
| |
| -- Add Subdirs.all if it is a directory that may be created and |
| -- Subdirs is not null; |
| |
| if Create /= "" and then Subdirs /= null then |
| if Name_Buffer (Name_Len) /= Directory_Separator then |
| Add_Char_To_Name_Buffer (Directory_Separator); |
| end if; |
| |
| Add_Str_To_Name_Buffer (Subdirs.all); |
| end if; |
| |
| -- Convert '/' to directory separator (for Windows) |
| |
| for J in 1 .. Name_Len loop |
| if Name_Buffer (J) = '/' then |
| Name_Buffer (J) := Directory_Separator; |
| end if; |
| end loop; |
| |
| The_Name := Name_Find; |
| |
| if Current_Verbosity = High then |
| Debug_Indent; |
| Write_Str ("Locate_Directory ("""); |
| Write_Str (Get_Name_String (The_Name)); |
| Write_Str (""", in """); |
| Write_Str (The_Parent); |
| Write_Line (""")"); |
| end if; |
| |
| Path := No_Path_Information; |
| Dir_Exists := False; |
| |
| if Is_Absolute_Path (Get_Name_String (The_Name)) then |
| Full_Name := The_Name; |
| |
| else |
| Name_Len := 0; |
| Add_Str_To_Name_Buffer |
| (The_Parent (The_Parent'First .. The_Parent_Last)); |
| Add_Str_To_Name_Buffer (Get_Name_String (The_Name)); |
| Full_Name := Name_Find; |
| end if; |
| |
| declare |
| Full_Path_Name : String_Access := |
| new String'(Get_Name_String (Full_Name)); |
| |
| begin |
| if (Setup_Projects or else Subdirs /= null) |
| and then Create'Length > 0 |
| then |
| if not Is_Directory (Full_Path_Name.all) then |
| |
| -- If project is externally built, do not create a subdir, |
| -- use the specified directory, without the subdir. |
| |
| if Externally_Built then |
| if Is_Absolute_Path (Get_Name_String (Name)) then |
| Get_Name_String (Name); |
| |
| else |
| Name_Len := 0; |
| Add_Str_To_Name_Buffer |
| (The_Parent (The_Parent'First .. The_Parent_Last)); |
| Add_Str_To_Name_Buffer (Get_Name_String (Name)); |
| end if; |
| |
| Full_Path_Name := new String'(Name_Buffer (1 .. Name_Len)); |
| |
| else |
| begin |
| Create_Path (Full_Path_Name.all); |
| |
| if not Quiet_Output then |
| Write_Str (Create); |
| Write_Str (" directory """); |
| Write_Str (Full_Path_Name.all); |
| Write_Str (""" created for project "); |
| Write_Line (Get_Name_String (Project.Name)); |
| end if; |
| |
| exception |
| when Use_Error => |
| Error_Msg |
| (Data.Flags, |
| "could not create " & Create & |
| " directory " & Full_Path_Name.all, |
| Location, Project); |
| end; |
| end if; |
| end if; |
| end if; |
| |
| Dir_Exists := Is_Directory (Full_Path_Name.all); |
| |
| if not Must_Exist or else Dir_Exists then |
| declare |
| Normed : constant String := |
| Normalize_Pathname |
| (Full_Path_Name.all, |
| Directory => |
| The_Parent (The_Parent'First .. The_Parent_Last), |
| Resolve_Links => False, |
| Case_Sensitive => True); |
| |
| Canonical_Path : constant String := |
| Normalize_Pathname |
| (Normed, |
| Directory => |
| The_Parent |
| (The_Parent'First .. The_Parent_Last), |
| Resolve_Links => |
| Opt.Follow_Links_For_Dirs, |
| Case_Sensitive => False); |
| |
| begin |
| Name_Len := Normed'Length; |
| Name_Buffer (1 .. Name_Len) := Normed; |
| |
| -- Directories should always end with a directory separator |
| |
| if Name_Buffer (Name_Len) /= Directory_Separator then |
| Add_Char_To_Name_Buffer (Directory_Separator); |
| end if; |
| |
| Path.Display_Name := Name_Find; |
| |
| Name_Len := Canonical_Path'Length; |
| Name_Buffer (1 .. Name_Len) := Canonical_Path; |
| |
| if Name_Buffer (Name_Len) /= Directory_Separator then |
| Add_Char_To_Name_Buffer (Directory_Separator); |
| end if; |
| |
| Path.Name := Name_Find; |
| end; |
| end if; |
| |
| Free (Full_Path_Name); |
| end; |
| end Locate_Directory; |
| |
| --------------------------- |
| -- Find_Excluded_Sources -- |
| --------------------------- |
| |
| procedure Find_Excluded_Sources |
| (Project : in out Project_Processing_Data; |
| Data : in out Tree_Processing_Data) |
| is |
| Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared; |
| |
| Excluded_Source_List_File : constant Variable_Value := |
| Util.Value_Of |
| (Name_Excluded_Source_List_File, |
| Project.Project.Decl.Attributes, |
| Shared); |
| Excluded_Sources : Variable_Value := Util.Value_Of |
| (Name_Excluded_Source_Files, |
| Project.Project.Decl.Attributes, |
| Shared); |
| |
| Current : String_List_Id; |
| Element : String_Element; |
| Location : Source_Ptr; |
| Name : File_Name_Type; |
| File : Prj.Util.Text_File; |
| Line : String (1 .. 300); |
| Last : Natural; |
| Locally_Removed : Boolean := False; |
| |
| begin |
| -- If Excluded_Source_Files is not declared, check Locally_Removed_Files |
| |
| if Excluded_Sources.Default then |
| Locally_Removed := True; |
| Excluded_Sources := |
| Util.Value_Of |
| (Name_Locally_Removed_Files, |
| Project.Project.Decl.Attributes, Shared); |
| end if; |
| |
| -- If there are excluded sources, put them in the table |
| |
| if not Excluded_Sources.Default then |
| if not Excluded_Source_List_File.Default then |
| if Locally_Removed then |
| Error_Msg |
| (Data.Flags, |
| "?both attributes Locally_Removed_Files and " & |
| "Excluded_Source_List_File are present", |
| Excluded_Source_List_File.Location, Project.Project); |
| else |
| Error_Msg |
| (Data.Flags, |
| "?both attributes Excluded_Source_Files and " & |
| "Excluded_Source_List_File are present", |
| Excluded_Source_List_File.Location, Project.Project); |
| end if; |
| end if; |
| |
| Current := Excluded_Sources.Values; |
| while Current /= Nil_String loop |
| Element := Shared.String_Elements.Table (Current); |
| Name := Canonical_Case_File_Name (Element.Value); |
| |
| -- If the element has no location, then use the location of |
| -- Excluded_Sources to report possible errors. |
| |
| if Element.Location = No_Location then |
| Location := Excluded_Sources.Location; |
| else |
| Location := Element.Location; |
| end if; |
| |
| Excluded_Sources_Htable.Set |
| (Project.Excluded, Name, |
| (Name, No_File, 0, False, Location)); |
| Current := Element.Next; |
| end loop; |
| |
| elsif not Excluded_Source_List_File.Default then |
| Location := Excluded_Source_List_File.Location; |
| |
| declare |
| Source_File_Name : constant File_Name_Type := |
| File_Name_Type |
| (Excluded_Source_List_File.Value); |
| Source_File_Line : Natural := 0; |
| |
| Source_File_Path_Name : constant String := |
| Path_Name_Of |
| (Source_File_Name, |
| Project.Project.Directory.Name); |
| |
| begin |
| if Source_File_Path_Name'Length = 0 then |
| Err_Vars.Error_Msg_File_1 := |
| File_Name_Type (Excluded_Source_List_File.Value); |
| Error_Msg |
| (Data.Flags, |
| "file with excluded sources { does not exist", |
| Excluded_Source_List_File.Location, Project.Project); |
| |
| else |
| -- Open the file |
| |
| Prj.Util.Open (File, Source_File_Path_Name); |
| |
| if not Prj.Util.Is_Valid (File) then |
| Error_Msg |
| (Data.Flags, "file does not exist", |
| Location, Project.Project); |
| else |
| -- Read the lines one by one |
| |
| while not Prj.Util.End_Of_File (File) loop |
| Prj.Util.Get_Line (File, Line, Last); |
| Source_File_Line := Source_File_Line + 1; |
| |
| -- Non empty, non comment line should contain a file name |
| |
| if Last /= 0 |
| and then (Last = 1 or else Line (1 .. 2) /= "--") |
| then |
| Name_Len := Last; |
| Name_Buffer (1 .. Name_Len) := Line (1 .. Last); |
| Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); |
| Name := Name_Find; |
| |
| -- Check that there is no directory information |
| |
| for J in 1 .. Last loop |
| if Line (J) = '/' |
| or else Line (J) = Directory_Separator |
| then |
| Error_Msg_File_1 := Name; |
| Error_Msg |
| (Data.Flags, |
| "file name cannot include " & |
| "directory information ({)", |
| Location, Project.Project); |
| exit; |
| end if; |
| end loop; |
| |
| Excluded_Sources_Htable.Set |
| (Project.Excluded, |
| Name, |
| (Name, Source_File_Name, Source_File_Line, |
| False, Location)); |
| end if; |
| end loop; |
| |
| Prj.Util.Close (File); |
| end if; |
| end if; |
| end; |
| end if; |
| end Find_Excluded_Sources; |
| |
| ------------------ |
| -- Find_Sources -- |
| ------------------ |
| |
| procedure Find_Sources |
| (Project : in out Project_Processing_Data; |
| Data : in out Tree_Processing_Data) |
| is |
| Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared; |
| |
| Sources : constant Variable_Value := |
| Util.Value_Of |
| (Name_Source_Files, |
| Project.Project.Decl.Attributes, |
| Shared); |
| |
| Source_List_File : constant Variable_Value := |
| Util.Value_Of |
| (Name_Source_List_File, |
| Project.Project.Decl.Attributes, |
| Shared); |
| |
| Name_Loc : Name_Location; |
| Has_Explicit_Sources : Boolean; |
| |
| begin |
| pragma Assert (Sources.Kind = List, "Source_Files is not a list"); |
| pragma Assert |
| (Source_List_File.Kind = Single, |
| "Source_List_File is not a single string"); |
| |
| Project.Source_List_File_Location := Source_List_File.Location; |
| |
| -- If the user has specified a Source_Files attribute |
| |
| if not Sources.Default then |
| if not Source_List_File.Default then |
| Error_Msg |
| (Data.Flags, |
| "?both attributes source_files and " & |
| "source_list_file are present", |
| Source_List_File.Location, Project.Project); |
| end if; |
| |
| -- Sources is a list of file names |
| |
| declare |
| Current : String_List_Id := Sources.Values; |
| Element : String_Element; |
| Location : Source_Ptr; |
| Name : File_Name_Type; |
| |
| begin |
| if Current = Nil_String then |
| Project.Project.Languages := No_Language_Index; |
| |
| -- This project contains no source. For projects that don't |
| -- extend other projects, this also means that there is no |
| -- need for an object directory, if not specified. |
| |
| if Project.Project.Extends = No_Project |
| and then |
| Project.Project.Object_Directory = Project.Project.Directory |
| and then |
| not (Project.Project.Qualifier = Aggregate_Library) |
| then |
| Project.Project.Object_Directory := No_Path_Information; |
| end if; |
| end if; |
| |
| while Current /= Nil_String loop |
| Element := Shared.String_Elements.Table (Current); |
| Name := Canonical_Case_File_Name (Element.Value); |
| Get_Name_String (Element.Value); |
| |
| -- If the element has no location, then use the location of |
| -- Sources to report possible errors. |
| |
| if Element.Location = No_Location then |
| Location := Sources.Location; |
| else |
| Location := Element.Location; |
| end if; |
| |
| -- Check that there is no directory information |
| |
| for J in 1 .. Name_Len loop |
| if Name_Buffer (J) = '/' |
| or else Name_Buffer (J) = Directory_Separator |
| then |
| Error_Msg_File_1 := Name; |
| Error_Msg |
| (Data.Flags, |
| "file name cannot include directory " & |
| "information ({)", |
| Location, Project.Project); |
| exit; |
| end if; |
| end loop; |
| |
| -- Check whether the file is already there: the same file name |
| -- may be in the list. If the source is missing, the error will |
| -- be on the first mention of the source file name. |
| |
| Name_Loc := Source_Names_Htable.Get |
| (Project.Source_Names, Name); |
| |
| if Name_Loc = No_Name_Location then |
| Name_Loc := |
| (Name => Name, |
| Location => Location, |
| Source => No_Source, |
| Listed => True, |
| Found => False); |
| |
| else |
| Name_Loc.Listed := True; |
| end if; |
| |
| Source_Names_Htable.Set |
| (Project.Source_Names, Name, Name_Loc); |
| |
| Current := Element.Next; |
| end loop; |
| |
| Has_Explicit_Sources := True; |
| end; |
| |
| -- If we have no Source_Files attribute, check the Source_List_File |
| -- attribute. |
| |
| elsif not Source_List_File.Default then |
| |
| -- Source_List_File is the name of the file that contains the source |
| -- file names. |
| |
| declare |
| Source_File_Path_Name : constant String := |
| Path_Name_Of |
| (File_Name_Type |
| (Source_List_File.Value), |
| Project.Project. |
| Directory.Display_Name); |
| |
| begin |
| Has_Explicit_Sources := True; |
| |
| if Source_File_Path_Name'Length = 0 then |
| Err_Vars.Error_Msg_File_1 := |
| File_Name_Type (Source_List_File.Value); |
| Error_Msg |
| (Data.Flags, |
| "file with sources { does not exist", |
| Source_List_File.Location, Project.Project); |
| |
| else |
| Get_Sources_From_File |
| (Source_File_Path_Name, Source_List_File.Location, |
| Project, Data); |
| end if; |
| end; |
| |
| else |
| -- Neither Source_Files nor Source_List_File has been specified. Find |
| -- all the files that satisfy the naming scheme in all the source |
| -- directories. |
| |
| Has_Explicit_Sources := False; |
| end if; |
| |
| -- Remove any exception that is not in the specified list of sources |
| |
| if Has_Explicit_Sources then |
| declare |
| Source : Source_Id; |
| Iter : Source_Iterator; |
| NL : Name_Location; |
| Again : Boolean; |
| begin |
| Iter_Loop : |
| loop |
| Again := False; |
| Iter := For_Each_Source (Data.Tree, Project.Project); |
| |
| Source_Loop : |
| loop |
| Source := Prj.Element (Iter); |
| exit Source_Loop when Source = No_Source; |
| |
| if Source.Naming_Exception /= No then |
| NL := Source_Names_Htable.Get |
| (Project.Source_Names, Source.File); |
| |
| if NL /= No_Name_Location and then not NL.Listed then |
| -- Remove the exception |
| Source_Names_Htable.Set |
| (Project.Source_Names, |
| Source.File, |
| No_Name_Location); |
| Remove_Source (Data.Tree, Source, No_Source); |
| |
| if Source.Naming_Exception = Yes then |
| Error_Msg_Name_1 := Name_Id (Source.File); |
| Error_Msg |
| (Data.Flags, |
| "? unknown source file %%", |
| NL.Location, |
| Project.Project); |
| end if; |
| |
| Again := True; |
| exit Source_Loop; |
| end if; |
| end if; |
| |
| Next (Iter); |
| end loop Source_Loop; |
| |
| exit Iter_Loop when not Again; |
| end loop Iter_Loop; |
| end; |
| end if; |
| |
| Search_Directories |
| (Project, |
| Data => Data, |
| For_All_Sources => Sources.Default and then Source_List_File.Default); |
| |
| -- Check if all exceptions have been found |
| |
| declare |
| Source : Source_Id; |
| Iter : Source_Iterator; |
| Found : Boolean := False; |
| |
| begin |
| Iter := For_Each_Source (Data.Tree, Project.Project); |
| loop |
| Source := Prj.Element (Iter); |
| exit when Source = No_Source; |
| |
| -- If the full source path is unknown for this source_id, there |
| -- could be several reasons: |
| -- * we simply did not find the file itself, this is an error |
| -- * we have a multi-unit source file. Another Source_Id from |
| -- the same file has received the full path, so we need to |
| -- propagate it. |
| |
| if Source.Path = No_Path_Information then |
| if Source.Naming_Exception = Yes then |
| if Source.Unit /= No_Unit_Index then |
| Found := False; |
| |
| if Source.Index /= 0 then -- Only multi-unit files |
| declare |
| S : Source_Id := |
| Source_Files_Htable.Get |
| (Data.Tree.Source_Files_HT, Source.File); |
| |
| begin |
| while S /= null loop |
| if S.Path /= No_Path_Information then |
| Source.Path := S.Path; |
| Found := True; |
| |
| if Current_Verbosity = High then |
| Debug_Output |
| ("setting full path for " |
| & Get_Name_String (Source.File) |
| & " at" & Source.Index'Img |
| & " to " |
| & Get_Name_String (Source.Path.Name)); |
| end if; |
| |
| exit; |
| end if; |
| |
| S := S.Next_With_File_Name; |
| end loop; |
| end; |
| end if; |
| |
| if not Found then |
| Error_Msg_Name_1 := Name_Id (Source.Display_File); |
| Error_Msg_Name_2 := Source.Unit.Name; |
| Error_Or_Warning |
| (Data.Flags, Data.Flags.Missing_Source_Files, |
| "source file %% for unit %% not found", |
| No_Location, Project.Project); |
| end if; |
| end if; |
| |
| if Source.Path = No_Path_Information then |
| Remove_Source (Data.Tree, Source, No_Source); |
| end if; |
| |
| elsif Source.Naming_Exception = Inherited then |
| Remove_Source (Data.Tree, Source, No_Source); |
| end if; |
| end if; |
| |
| Next (Iter); |
| end loop; |
| end; |
| |
| -- It is an error if a source file name in a source list or in a source |
| -- list file is not found. |
| |
| if Has_Explicit_Sources then |
| declare |
| NL : Name_Location; |
| First_Error : Boolean; |
| |
| begin |
| NL := Source_Names_Htable.Get_First (Project.Source_Names); |
| First_Error := True; |
| while NL /= No_Name_Location loop |
| if not NL.Found then |
| Err_Vars.Error_Msg_File_1 := NL.Name; |
| if First_Error then |
| Error_Or_Warning |
| (Data.Flags, Data.Flags.Missing_Source_Files, |
| "source file { not found", |
| NL.Location, Project.Project); |
| First_Error := False; |
| else |
| Error_Or_Warning |
| (Data.Flags, Data.Flags.Missing_Source_Files, |
| "\source file { not found", |
| NL.Location, Project.Project); |
| end if; |
| end if; |
| |
| NL := Source_Names_Htable.Get_Next (Project.Source_Names); |
| end loop; |
| end; |
| end if; |
| end Find_Sources; |
| |
| ---------------- |
| -- Initialize -- |
| ---------------- |
| |
| procedure Initialize |
| (Data : out Tree_Processing_Data; |
| Tree : Project_Tree_Ref; |
| Node_Tree : Prj.Tree.Project_Node_Tree_Ref; |
| Flags : Prj.Processing_Flags) |
| is |
| begin |
| Data.Tree := Tree; |
| Data.Node_Tree := Node_Tree; |
| Data.Flags := Flags; |
| end Initialize; |
| |
| ---------- |
| -- Free -- |
| ---------- |
| |
| procedure Free (Data : in out Tree_Processing_Data) is |
| pragma Unreferenced (Data); |
| begin |
| null; |
| end Free; |
| |
| ---------------- |
| -- Initialize -- |
| ---------------- |
| |
| procedure Initialize |
| (Data : in out Project_Processing_Data; |
| Project : Project_Id) |
| is |
| begin |
| Data.Project := Project; |
| end Initialize; |
| |
| ---------- |
| -- Free -- |
| ---------- |
| |
| procedure Free (Data : in out Project_Processing_Data) is |
| begin |
| Source_Names_Htable.Reset (Data.Source_Names); |
| Unit_Exceptions_Htable.Reset (Data.Unit_Exceptions); |
| Excluded_Sources_Htable.Reset (Data.Excluded); |
| end Free; |
| |
| ------------------------------- |
| -- Check_File_Naming_Schemes -- |
| ------------------------------- |
| |
| procedure Check_File_Naming_Schemes |
| (Project : Project_Processing_Data; |
| File_Name : File_Name_Type; |
| Alternate_Languages : out Language_List; |
| Language : out Language_Ptr; |
| Display_Language_Name : out Name_Id; |
| Unit : out Name_Id; |
| Lang_Kind : out Language_Kind; |
| Kind : out Source_Kind) |
| is |
| Filename : constant String := Get_Name_String (File_Name); |
| Config : Language_Config; |
| Tmp_Lang : Language_Ptr; |
| |
| Header_File : Boolean := False; |
| -- True if we found at least one language for which the file is a header |
| -- In such a case, we search for all possible languages where this is |
| -- also a header (C and C++ for instance), since the file might be used |
| -- for several such languages. |
| |
| procedure Check_File_Based_Lang; |
| -- Does the naming scheme test for file-based languages. For those, |
| -- there is no Unit. Just check if the file name has the implementation |
| -- or, if it is specified, the template suffix of the language. |
| -- |
| -- Returns True if the file belongs to the current language and we |
| -- should stop searching for matching languages. Not that a given header |
| -- file could belong to several languages (C and C++ for instance). Thus |
| -- if we found a header we'll check whether it matches other languages. |
| |
| --------------------------- |
| -- Check_File_Based_Lang -- |
| --------------------------- |
| |
| procedure Check_File_Based_Lang is |
| begin |
| if not Header_File |
| and then Suffix_Matches (Filename, Config.Naming_Data.Body_Suffix) |
| then |
| Unit := No_Name; |
| Kind := Impl; |
| Language := Tmp_Lang; |
| |
| Debug_Output |
| ("implementation of language ", Display_Language_Name); |
| |
| elsif Suffix_Matches (Filename, Config.Naming_Data.Spec_Suffix) then |
| Debug_Output |
| ("header of language ", Display_Language_Name); |
| |
| if Header_File then |
| Alternate_Languages := new Language_List_Element' |
| (Language => Language, |
| Next => Alternate_Languages); |
| |
| else |
| Header_File := True; |
| Kind := Spec; |
| Unit := No_Name; |
| Language := Tmp_Lang; |
| end if; |
| end if; |
| end Check_File_Based_Lang; |
| |
| -- Start of processing for Check_File_Naming_Schemes |
| |
| begin |
| Language := No_Language_Index; |
| Alternate_Languages := null; |
| Display_Language_Name := No_Name; |
| Unit := No_Name; |
| Lang_Kind := File_Based; |
| Kind := Spec; |
| |
| Tmp_Lang := Project.Project.Languages; |
| while Tmp_Lang /= No_Language_Index loop |
| if Current_Verbosity = High then |
| Debug_Output |
| ("testing language " |
| & Get_Name_String (Tmp_Lang.Name) |
| & " Header_File=" & Header_File'Img); |
| end if; |
| |
| Display_Language_Name := Tmp_Lang.Display_Name; |
| Config := Tmp_Lang.Config; |
| Lang_Kind := Config.Kind; |
| |
| case Config.Kind is |
| when File_Based => |
| Check_File_Based_Lang; |
| exit when Kind = Impl; |
| |
| when Unit_Based => |
| |
| -- We know it belongs to a least a file_based language, no |
| -- need to check unit-based ones. |
| |
| if not Header_File then |
| Compute_Unit_Name |
| (File_Name => File_Name, |
| Naming => Config.Naming_Data, |
| Kind => Kind, |
| Unit => Unit, |
| Project => Project); |
| |
| if Unit /= No_Name then |
| Language := Tmp_Lang; |
| exit; |
| end if; |
| end if; |
| end case; |
| |
| Tmp_Lang := Tmp_Lang.Next; |
| end loop; |
| |
| if Language = No_Language_Index then |
| Debug_Output ("not a source of any language"); |
| end if; |
| end Check_File_Naming_Schemes; |
| |
| ------------------- |
| -- Override_Kind -- |
| ------------------- |
| |
| procedure Override_Kind (Source : Source_Id; Kind : Source_Kind) is |
| begin |
| -- If the file was previously already associated with a unit, change it |
| |
| if Source.Unit /= null |
| and then Source.Kind in Spec_Or_Body |
| and then Source.Unit.File_Names (Source.Kind) /= null |
| then |
| -- If we had another file referencing the same unit (for instance it |
| -- was in an extended project), that source file is in fact invisible |
| -- from now on, and in particular doesn't belong to the same unit. |
| -- If the source is an inherited naming exception, then it may not |
| -- really exist: the source potentially replaced is left untouched. |
| |
| if Source.Unit.File_Names (Source.Kind) /= Source then |
| Source.Unit.File_Names (Source.Kind).Unit := No_Unit_Index; |
| end if; |
| |
| Source.Unit.File_Names (Source.Kind) := null; |
| end if; |
| |
| Source.Kind := Kind; |
| |
| if Current_Verbosity = High |
| and then Source.File /= No_File |
| then |
| Debug_Output ("override kind for " |
| & Get_Name_String (Source.File) |
| & " idx=" & Source.Index'Img |
| & " kind=" & Source.Kind'Img); |
| end if; |
| |
| if Source.Unit /= null then |
| if Source.Kind = Spec then |
| Source.Unit.File_Names (Spec) := Source; |
| else |
| Source.Unit.File_Names (Impl) := Source; |
| end if; |
| end if; |
| end Override_Kind; |
| |
| ---------------- |
| -- Check_File -- |
| ---------------- |
| |
| procedure Check_File |
| (Project : in out Project_Processing_Data; |
| Data : in out Tree_Processing_Data; |
| Source_Dir_Rank : Natural; |
| Path : Path_Name_Type; |
| Display_Path : Path_Name_Type; |
| File_Name : File_Name_Type; |
| Display_File_Name : File_Name_Type; |
| Locally_Removed : Boolean; |
| For_All_Sources : Boolean) |
| is |
| Name_Loc : Name_Location := |
| Source_Names_Htable.Get |
| (Project.Source_Names, File_Name); |
| Check_Name : Boolean := False; |
| Alternate_Languages : Language_List; |
| Language : Language_Ptr; |
| Source : Source_Id; |
| Src_Ind : Source_File_Index; |
| Unit : Name_Id; |
| Display_Language_Name : Name_Id; |
| Lang_Kind : Language_Kind; |
| Kind : Source_Kind := Spec; |
| |
| begin |
| if Current_Verbosity = High then |
| Debug_Increase_Indent |
| ("checking file (rank=" & Source_Dir_Rank'Img & ")", |
| Name_Id (Display_Path)); |
| end if; |
| |
| if Name_Loc = No_Name_Location then |
| Check_Name := For_All_Sources; |
| |
| else |
| if Name_Loc.Found then |
| |
| -- Check if it is OK to have the same file name in several |
| -- source directories. |
| |
| if Source_Dir_Rank = Name_Loc.Source.Source_Dir_Rank then |
| Error_Msg_File_1 := File_Name; |
| Error_Msg |
| (Data.Flags, |
| "{ is found in several source directories", |
| Name_Loc.Location, Project.Project); |
| end if; |
| |
| else |
| Name_Loc.Found := True; |
| |
| Source_Names_Htable.Set |
| (Project.Source_Names, File_Name, Name_Loc); |
| |
| if Name_Loc.Source = No_Source then |
| Check_Name := True; |
| |
| else |
| -- Set the full path for the source_id (which might have been |
| -- created when parsing the naming exceptions, and therefore |
| -- might not have the full path). |
| -- We only set this for this source_id, but not for other |
| -- source_id in the same file (case of multi-unit source files) |
| -- For the latter, they will be set in Find_Sources when we |
| -- check that all source_id have known full paths. |
| -- Doing this later saves one htable lookup per file in the |
| -- common case where the user is not using multi-unit files. |
| |
| Name_Loc.Source.Path := (Path, Display_Path); |
| |
| Source_Paths_Htable.Set |
| (Data.Tree.Source_Paths_HT, Path, Name_Loc.Source); |
| |
| -- Check if this is a subunit |
| |
| if Name_Loc.Source.Unit /= No_Unit_Index |
| and then Name_Loc.Source.Kind = Impl |
| then |
| Src_Ind := Sinput.P.Load_Project_File |
| (Get_Name_String (Display_Path)); |
| |
| if Sinput.P.Source_File_Is_Subunit (Src_Ind) then |
| Override_Kind (Name_Loc.Source, Sep); |
| end if; |
| end if; |
| |
| -- If this is an inherited naming exception, make sure that |
| -- the naming exception it replaces is no longer a source. |
| |
| if Name_Loc.Source.Naming_Exception = Inherited then |
| declare |
| Proj : Project_Id := Name_Loc.Source.Project.Extends; |
| Iter : Source_Iterator; |
| Src : Source_Id; |
| begin |
| while Proj /= No_Project loop |
| Iter := For_Each_Source (Data.Tree, Proj); |
| Src := Prj.Element (Iter); |
| while Src /= No_Source loop |
| if Src.File = Name_Loc.Source.File then |
| Src.Replaced_By := Name_Loc.Source; |
| exit; |
| end if; |
| |
| Next (Iter); |
| Src := Prj.Element (Iter); |
| end loop; |
| |
| Proj := Proj.Extends; |
| end loop; |
| end; |
| |
| if Name_Loc.Source.Unit /= No_Unit_Index then |
| if Name_Loc.Source.Kind = Spec then |
| Name_Loc.Source.Unit.File_Names (Spec) := |
| Name_Loc.Source; |
| |
| elsif Name_Loc.Source.Kind = Impl then |
| Name_Loc.Source.Unit.File_Names (Impl) := |
| Name_Loc.Source; |
| end if; |
| |
| Units_Htable.Set |
| (Data.Tree.Units_HT, |
| Name_Loc.Source.Unit.Name, |
| Name_Loc.Source.Unit); |
| end if; |
| end if; |
| end if; |
| end if; |
| end if; |
| |
| if Check_Name then |
| Check_File_Naming_Schemes |
| (Project => Project, |
| File_Name => File_Name, |
| Alternate_Languages => Alternate_Languages, |
| Language => Language, |
| Display_Language_Name => Display_Language_Name, |
| Unit => Unit, |
| Lang_Kind => Lang_Kind, |
| Kind => Kind); |
| |
| if Language = No_Language_Index then |
| |
| -- A file name in a list must be a source of a language |
| |
| if Data.Flags.Error_On_Unknown_Language |
| and then Name_Loc.Found |
| then |
| Error_Msg_File_1 := File_Name; |
| Error_Msg |
| (Data.Flags, |
| "language unknown for {", |
| Name_Loc.Location, Project.Project); |
| end if; |
| |
| else |
| Add_Source |
| (Id => Source, |
| Project => Project.Project, |
| Source_Dir_Rank => Source_Dir_Rank, |
| Lang_Id => Language, |
| Kind => Kind, |
| Data => Data, |
| Alternate_Languages => Alternate_Languages, |
| File_Name => File_Name, |
| Display_File => Display_File_Name, |
| Unit => Unit, |
| Locally_Removed => Locally_Removed, |
| Path => (Path, Display_Path)); |
| |
| -- If it is a source specified in a list, update the entry in |
| -- the Source_Names table. |
| |
| if Name_Loc.Found and then Name_Loc.Source = No_Source then |
| Name_Loc.Source := Source; |
| Source_Names_Htable.Set |
| (Project.Source_Names, File_Name, Name_Loc); |
| end if; |
| end if; |
| end if; |
| |
| Debug_Decrease_Indent; |
| end Check_File; |
| |
| --------------------------------- |
| -- Expand_Subdirectory_Pattern -- |
| --------------------------------- |
| |
| procedure Expand_Subdirectory_Pattern |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data; |
| Patterns : String_List_Id; |
| Ignore : String_List_Id; |
| Search_For : Search_Type; |
| Resolve_Links : Boolean) |
| is |
| Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared; |
| |
| package Recursive_Dirs is new GNAT.Dynamic_HTables.Simple_HTable |
| (Header_Num => Header_Num, |
| Element => Boolean, |
| No_Element => False, |
| Key => Path_Name_Type, |
| Hash => Hash, |
| Equal => "="); |
| -- Hash table stores recursive source directories, to avoid looking |
| -- several times, and to avoid cycles that may be introduced by symbolic |
| -- links. |
| |
| File_Pattern : GNAT.Regexp.Regexp; |
| -- Pattern to use when matching file names |
| |
| Visited : Recursive_Dirs.Instance; |
| |
| procedure Find_Pattern |
| (Pattern_Id : Name_Id; |
| Rank : Natural; |
| Location : Source_Ptr); |
| -- Find a specific pattern |
| |
| function Recursive_Find_Dirs |
| (Path : Path_Information; |
| Rank : Natural) return Boolean; |
| -- Search all the subdirectories (recursively) of Path. |
| -- Return True if at least one file or directory was processed |
| |
| function Subdirectory_Matches |
| (Path : Path_Information; |
| Rank : Natural) return Boolean; |
| -- Called when a matching directory was found. If the user is in fact |
| -- searching for files, we then search for those files matching the |
| -- pattern within the directory. |
| -- Return True if at least one file or directory was processed |
| |
| -------------------------- |
| -- Subdirectory_Matches -- |
| -------------------------- |
| |
| function Subdirectory_Matches |
| (Path : Path_Information; |
| Rank : Natural) return Boolean |
| is |
| Dir : Dir_Type; |
| Name : String (1 .. 250); |
| Last : Natural; |
| Found : Path_Information; |
| Success : Boolean := False; |
| |
| begin |
| case Search_For is |
| when Search_Directories => |
| Callback (Path, Rank); |
| return True; |
| |
| when Search_Files => |
| Open (Dir, Get_Name_String (Path.Display_Name)); |
| loop |
| Read (Dir, Name, Last); |
| exit when Last = 0; |
| |
| if Name (Name'First .. Last) /= "." |
| and then Name (Name'First .. Last) /= ".." |
| and then Match (Name (Name'First .. Last), File_Pattern) |
| then |
| Get_Name_String (Path.Display_Name); |
| Add_Str_To_Name_Buffer (Name (Name'First .. Last)); |
| |
| Found.Display_Name := Name_Find; |
| Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); |
| Found.Name := Name_Find; |
| |
| Callback (Found, Rank); |
| Success := True; |
| end if; |
| end loop; |
| |
| Close (Dir); |
| |
| return Success; |
| end case; |
| end Subdirectory_Matches; |
| |
| ------------------------- |
| -- Recursive_Find_Dirs -- |
| ------------------------- |
| |
| function Recursive_Find_Dirs |
| (Path : Path_Information; |
| Rank : Natural) return Boolean |
| is |
| Path_Str : constant String := Get_Name_String (Path.Display_Name); |
| Dir : Dir_Type; |
| Name : String (1 .. 250); |
| Last : Natural; |
| Success : Boolean := False; |
| |
| begin |
| Debug_Output ("looking for subdirs of ", Name_Id (Path.Display_Name)); |
| |
| if Recursive_Dirs.Get (Visited, Path.Name) then |
| return Success; |
| end if; |
| |
| Recursive_Dirs.Set (Visited, Path.Name, True); |
| |
| Success := Subdirectory_Matches (Path, Rank) or Success; |
| |
| Open (Dir, Path_Str); |
| |
| loop |
| Read (Dir, Name, Last); |
| exit when Last = 0; |
| |
| if Name (1 .. Last) /= "." |
| and then |
| Name (1 .. Last) /= ".." |
| then |
| declare |
| Path_Name : constant String := |
| Normalize_Pathname |
| (Name => Name (1 .. Last), |
| Directory => Path_Str, |
| Resolve_Links => Resolve_Links) |
| & Directory_Separator; |
| Path2 : Path_Information; |
| OK : Boolean := True; |
| |
| begin |
| if Is_Directory (Path_Name) then |
| if Ignore /= Nil_String then |
| declare |
| Dir_Name : String := Name (1 .. Last); |
| List : String_List_Id := Ignore; |
| |
| begin |
| Canonical_Case_File_Name (Dir_Name); |
| |
| while List /= Nil_String loop |
| Get_Name_String |
| (Shared.String_Elements.Table (List).Value); |
| Canonical_Case_File_Name |
| (Name_Buffer (1 .. Name_Len)); |
| OK := Name_Buffer (1 .. Name_Len) /= Dir_Name; |
| exit when not OK; |
| List := Shared.String_Elements.Table (List).Next; |
| end loop; |
| end; |
| end if; |
| |
| if OK then |
| Name_Len := 0; |
| Add_Str_To_Name_Buffer (Path_Name); |
| Path2.Display_Name := Name_Find; |
| |
| Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); |
| Path2.Name := Name_Find; |
| |
| Success := |
| Recursive_Find_Dirs (Path2, Rank) or Success; |
| end if; |
| end if; |
| end; |
| end if; |
| end loop; |
| |
| Close (Dir); |
| |
| return Success; |
| |
| exception |
| when Directory_Error => |
| return Success; |
| end Recursive_Find_Dirs; |
| |
| ------------------ |
| -- Find_Pattern -- |
| ------------------ |
| |
| procedure Find_Pattern |
| (Pattern_Id : Name_Id; |
| Rank : Natural; |
| Location : Source_Ptr) |
| is |
| Pattern : constant String := Get_Name_String (Pattern_Id); |
| Pattern_End : Natural := Pattern'Last; |
| Recursive : Boolean; |
| Dir : File_Name_Type; |
| Path_Name : Path_Information; |
| Dir_Exists : Boolean; |
| Has_Error : Boolean := False; |
| Success : Boolean; |
| |
| begin |
| Debug_Increase_Indent ("Find_Pattern", Pattern_Id); |
| |
| -- If we are looking for files, find the pattern for the files |
| |
| if Search_For = Search_Files then |
| while Pattern_End >= Pattern'First |
| and then Pattern (Pattern_End) /= '/' |
| and then Pattern (Pattern_End) /= Directory_Separator |
| loop |
| Pattern_End := Pattern_End - 1; |
| end loop; |
| |
| if Pattern_End = Pattern'Last then |
| Err_Vars.Error_Msg_File_1 := File_Name_Type (Pattern_Id); |
| Error_Or_Warning |
| (Data.Flags, Data.Flags.Missing_Source_Files, |
| "Missing file name or pattern in {", Location, Project); |
| return; |
| end if; |
| |
| if Current_Verbosity = High then |
| Debug_Indent; |
| Write_Str ("file_pattern="); |
| Write_Str (Pattern (Pattern_End + 1 .. Pattern'Last)); |
| Write_Str (" dir_pattern="); |
| Write_Line (Pattern (Pattern'First .. Pattern_End)); |
| end if; |
| |
| File_Pattern := Compile |
| (Pattern (Pattern_End + 1 .. Pattern'Last), |
| Glob => True, |
| Case_Sensitive => File_Names_Case_Sensitive); |
| |
| -- If we had just "*.gpr", this is equivalent to "./*.gpr" |
| |
| if Pattern_End > Pattern'First then |
| Pattern_End := Pattern_End - 1; -- Skip directory separator |
| end if; |
| end if; |
| |
| Recursive := |
| Pattern_End - 1 >= Pattern'First |
| and then Pattern (Pattern_End - 1 .. Pattern_End) = "**" |
| and then (Pattern_End - 1 = Pattern'First |
| or else Pattern (Pattern_End - 2) = '/' |
| or else Pattern (Pattern_End - 2) = Directory_Separator); |
| |
| if Recursive then |
| Pattern_End := Pattern_End - 2; |
| if Pattern_End > Pattern'First then |
| Pattern_End := Pattern_End - 1; -- Skip '/' |
| end if; |
| end if; |
| |
| Name_Len := Pattern_End - Pattern'First + 1; |
| Name_Buffer (1 .. Name_Len) := Pattern (Pattern'First .. Pattern_End); |
| Dir := Name_Find; |
| |
| Locate_Directory |
| (Project => Project, |
| Name => Dir, |
| Path => Path_Name, |
| Dir_Exists => Dir_Exists, |
| Data => Data, |
| Must_Exist => False); |
| |
| if not Dir_Exists then |
| Err_Vars.Error_Msg_File_1 := Dir; |
| Error_Or_Warning |
| (Data.Flags, Data.Flags.Missing_Source_Files, |
| "{ is not a valid directory", Location, Project); |
| Has_Error := Data.Flags.Missing_Source_Files = Error; |
| end if; |
| |
| if not Has_Error then |
| |
| -- Links have been resolved if necessary, and Path_Name |
| -- always ends with a directory separator. |
| |
| if Recursive then |
| Success := Recursive_Find_Dirs (Path_Name, Rank); |
| else |
| Success := Subdirectory_Matches (Path_Name, Rank); |
| end if; |
| |
| if not Success then |
| case Search_For is |
| when Search_Directories => |
| null; -- Error can't occur |
| |
| when Search_Files => |
| Err_Vars.Error_Msg_File_1 := File_Name_Type (Pattern_Id); |
| Error_Or_Warning |
| (Data.Flags, Data.Flags.Missing_Source_Files, |
| "file { not found", Location, Project); |
| end case; |
| end if; |
| end if; |
| |
| Debug_Decrease_Indent ("done Find_Pattern"); |
| end Find_Pattern; |
| |
| -- Local variables |
| |
| Pattern_Id : String_List_Id := Patterns; |
| Element : String_Element; |
| Rank : Natural := 1; |
| |
| -- Start of processing for Expand_Subdirectory_Pattern |
| |
| begin |
| while Pattern_Id /= Nil_String loop |
| Element := Shared.String_Elements.Table (Pattern_Id); |
| Find_Pattern (Element.Value, Rank, Element.Location); |
| Rank := Rank + 1; |
| Pattern_Id := Element.Next; |
| end loop; |
| |
| Recursive_Dirs.Reset (Visited); |
| end Expand_Subdirectory_Pattern; |
| |
| ------------------------ |
| -- Search_Directories -- |
| ------------------------ |
| |
| procedure Search_Directories |
| (Project : in out Project_Processing_Data; |
| Data : in out Tree_Processing_Data; |
| For_All_Sources : Boolean) |
| is |
| Shared : constant Shared_Project_Tree_Data_Access := Data.Tree.Shared; |
| |
| Source_Dir : String_List_Id; |
| Element : String_Element; |
| Src_Dir_Rank : Number_List_Index; |
| Num_Nod : Number_Node; |
| Dir : Dir_Type; |
| Name : String (1 .. 1_000); |
| Last : Natural; |
| File_Name : File_Name_Type; |
| Display_File_Name : File_Name_Type; |
| |
| begin |
| Debug_Increase_Indent ("looking for sources of", Project.Project.Name); |
| |
| -- Loop through subdirectories |
| |
| Src_Dir_Rank := Project.Project.Source_Dir_Ranks; |
| |
| Source_Dir := Project.Project.Source_Dirs; |
| while Source_Dir /= Nil_String loop |
| begin |
| Num_Nod := Shared.Number_Lists.Table (Src_Dir_Rank); |
| Element := Shared.String_Elements.Table (Source_Dir); |
| |
| -- Use Element.Value in this test, not Display_Value, because we |
| -- want the symbolic links to be resolved when appropriate. |
| |
| if Element.Value /= No_Name then |
| declare |
| Source_Directory : constant String := |
| Get_Name_String (Element.Value) |
| & Directory_Separator; |
| |
| Dir_Last : constant Natural := |
| Compute_Directory_Last (Source_Directory); |
| |
| Display_Source_Directory : constant String := |
| Get_Name_String |
| (Element.Display_Value) |
| & Directory_Separator; |
| -- Display_Source_Directory is to allow us to open a UTF-8 |
| -- encoded directory on Windows. |
| |
| begin |
| if Current_Verbosity = High then |
| Debug_Increase_Indent |
| ("Source_Dir (node=" & Num_Nod.Number'Img & ") """ |
| & Source_Directory (Source_Directory'First .. Dir_Last) |
| & '"'); |
| end if; |
| |
| -- We look to every entry in the source directory |
| |
| Open (Dir, Display_Source_Directory); |
| |
| loop |
| Read (Dir, Name, Last); |
| exit when Last = 0; |
| |
| -- In fast project loading mode (without -eL), the user |
| -- guarantees that no directory has a name which is a |
| -- valid source name, so we can avoid doing a system call |
| -- here. This provides a very significant speed up on |
| -- slow file systems (remote files for instance). |
| |
| if not Opt.Follow_Links_For_Files |
| or else Is_Regular_File |
| (Display_Source_Directory & Name (1 .. Last)) |
| then |
| Name_Len := Last; |
| Name_Buffer (1 .. Name_Len) := Name (1 .. Last); |
| Display_File_Name := Name_Find; |
| |
| if Osint.File_Names_Case_Sensitive then |
| File_Name := Display_File_Name; |
| else |
| Canonical_Case_File_Name |
| (Name_Buffer (1 .. Name_Len)); |
| File_Name := Name_Find; |
| end if; |
| |
| declare |
| Path_Name : constant String := |
| Normalize_Pathname |
| (Name (1 .. Last), |
| Directory => |
| Source_Directory |
| (Source_Directory'First .. |
| Dir_Last), |
| Resolve_Links => |
| Opt.Follow_Links_For_Files, |
| Case_Sensitive => True); |
| |
| Path : Path_Name_Type; |
| FF : File_Found := |
| Excluded_Sources_Htable.Get |
| (Project.Excluded, File_Name); |
| To_Remove : Boolean := False; |
| |
| begin |
| Name_Len := Path_Name'Length; |
| Name_Buffer (1 .. Name_Len) := Path_Name; |
| |
| if Osint.File_Names_Case_Sensitive then |
| Path := Name_Find; |
| else |
| Canonical_Case_File_Name |
| (Name_Buffer (1 .. Name_Len)); |
| Path := Name_Find; |
| end if; |
| |
| if FF /= No_File_Found then |
| if not FF.Found then |
| FF.Found := True; |
| Excluded_Sources_Htable.Set |
| (Project.Excluded, File_Name, FF); |
| |
| Debug_Output |
| ("excluded source ", |
| Name_Id (Display_File_Name)); |
| |
| -- Will mark the file as removed, but we |
| -- still need to add it to the list: if we |
| -- don't, the file will not appear in the |
| -- mapping file and will cause the compiler |
| -- to fail. |
| |
| To_Remove := True; |
| end if; |
| end if; |
| |
| -- Preserve the user's original casing and use of |
| -- links. The display_value (a directory) already |
| -- ends with a directory separator by construction, |
| -- so no need to add one. |
| |
| Get_Name_String (Element.Display_Value); |
| Get_Name_String_And_Append (Display_File_Name); |
| |
| Check_File |
| (Project => Project, |
| Source_Dir_Rank => Num_Nod.Number, |
| Data => Data, |
| Path => Path, |
| Display_Path => Name_Find, |
| File_Name => File_Name, |
| Locally_Removed => To_Remove, |
| Display_File_Name => Display_File_Name, |
| For_All_Sources => For_All_Sources); |
| end; |
| |
| else |
| if Current_Verbosity = High then |
| Debug_Output ("ignore " & Name (1 .. Last)); |
| end if; |
| end if; |
| end loop; |
| |
| Debug_Decrease_Indent; |
| Close (Dir); |
| end; |
| end if; |
| |
| exception |
| when Directory_Error => |
| null; |
| end; |
| |
| Source_Dir := Element.Next; |
| Src_Dir_Rank := Num_Nod.Next; |
| end loop; |
| |
| Debug_Decrease_Indent ("end looking for sources."); |
| end Search_Directories; |
| |
| ---------------------------- |
| -- Load_Naming_Exceptions -- |
| ---------------------------- |
| |
| procedure Load_Naming_Exceptions |
| (Project : in out Project_Processing_Data; |
| Data : in out Tree_Processing_Data) |
| is |
| Source : Source_Id; |
| Iter : Source_Iterator; |
| |
| begin |
| Iter := For_Each_Source (Data.Tree, Project.Project); |
| loop |
| Source := Prj.Element (Iter); |
| exit when Source = No_Source; |
| |
| -- An excluded file cannot also be an exception file name |
| |
| if Excluded_Sources_Htable.Get (Project.Excluded, Source.File) /= |
| No_File_Found |
| then |
| Error_Msg_File_1 := Source.File; |
| Error_Msg |
| (Data.Flags, |
| "{ cannot be both excluded and an exception file name", |
| No_Location, Project.Project); |
| end if; |
| |
| Debug_Output |
| ("naming exception: adding source file to source_Names: ", |
| Name_Id (Source.File)); |
| |
| Source_Names_Htable.Set |
| (Project.Source_Names, |
| K => Source.File, |
| E => Name_Location' |
| (Name => Source.File, |
| Location => Source.Location, |
| Source => Source, |
| Listed => False, |
| Found => False)); |
| |
| -- If this is an Ada exception, record in table Unit_Exceptions |
| |
| if Source.Unit /= No_Unit_Index then |
| declare |
| Unit_Except : Unit_Exception := |
| Unit_Exceptions_Htable.Get |
| (Project.Unit_Exceptions, Source.Unit.Name); |
| |
| begin |
| Unit_Except.Name := Source.Unit.Name; |
| |
| if Source.Kind = Spec then |
| Unit_Except.Spec := Source.File; |
| else |
| Unit_Except.Impl := Source.File; |
| end if; |
| |
| Unit_Exceptions_Htable.Set |
| (Project.Unit_Exceptions, Source.Unit.Name, Unit_Except); |
| end; |
| end if; |
| |
| Next (Iter); |
| end loop; |
| end Load_Naming_Exceptions; |
| |
| ---------------------- |
| -- Look_For_Sources -- |
| ---------------------- |
| |
| procedure Look_For_Sources |
| (Project : in out Project_Processing_Data; |
| Data : in out Tree_Processing_Data) |
| is |
| Object_Files : Object_File_Names_Htable.Instance; |
| Iter : Source_Iterator; |
| Src : Source_Id; |
| |
| procedure Check_Object (Src : Source_Id); |
| -- Check if object file name of Src is already used in the project tree, |
| -- and report an error if so. |
| |
| procedure Check_Object_Files; |
| -- Check that no two sources of this project have the same object file |
| |
| procedure Mark_Excluded_Sources; |
| -- Mark as such the sources that are declared as excluded |
| |
| procedure Check_Missing_Sources; |
| -- Check whether one of the languages has no sources, and report an |
| -- error when appropriate |
| |
| procedure Get_Sources_From_Source_Info; |
| -- Get the source information from the tables that were created when a |
| -- source info file was read. |
| |
| --------------------------- |
| -- Check_Missing_Sources -- |
| --------------------------- |
| |
| procedure Check_Missing_Sources is |
| Extending : constant Boolean := |
| Project.Project.Extends /= No_Project; |
| Language : Language_Ptr; |
| Source : Source_Id; |
| Alt_Lang : Language_List; |
| Continuation : Boolean := False; |
| Iter : Source_Iterator; |
| begin |
| if not Project.Project.Externally_Built |
| and then not Extending |
| then |
| Language := Project.Project.Languages; |
| while Language /= No_Language_Index loop |
| |
| -- If there are no sources for this language, check if there |
| -- are sources for which this is an alternate language. |
| |
| if Language.First_Source = No_Source |
| and then (Data.Flags.Require_Sources_Other_Lang |
| or else Language.Name = Name_Ada) |
| then |
| Iter := For_Each_Source (In_Tree => Data.Tree, |
| Project => Project.Project); |
| Source_Loop : loop |
| Source := Element (Iter); |
| exit Source_Loop when Source = No_Source |
| or else Source.Language = Language; |
| |
| Alt_Lang := Source.Alternate_Languages; |
| while Alt_Lang /= null loop |
| exit Source_Loop when Alt_Lang.Language = Language; |
| Alt_Lang := Alt_Lang.Next; |
| end loop; |
| |
| Next (Iter); |
| end loop Source_Loop; |
| |
| if Source = No_Source then |
| Report_No_Sources |
| (Project.Project, |
| Get_Name_String (Language.Display_Name), |
| Data, |
| Project.Source_List_File_Location, |
| Continuation); |
| Continuation := True; |
| end if; |
| end if; |
| |
| Language := Language.Next; |
| end loop; |
| end if; |
| end Check_Missing_Sources; |
| |
| ------------------ |
| -- Check_Object -- |
| ------------------ |
| |
| procedure Check_Object (Src : Source_Id) is |
| Source : Source_Id; |
| |
| begin |
| Source := Object_File_Names_Htable.Get (Object_Files, Src.Object); |
| |
| -- We cannot just check on "Source /= Src", since we might have |
| -- two different entries for the same file (and since that's |
| -- the same file it is expected that it has the same object) |
| |
| if Source /= No_Source |
| and then Source.Replaced_By = No_Source |
| and then Source.Path /= Src.Path |
| and then Is_Extending (Src.Project, Source.Project) |
| then |
| Error_Msg_File_1 := Src.File; |
| Error_Msg_File_2 := Source.File; |
| Error_Msg |
| (Data.Flags, |
| "{ and { have the same object file name", |
| No_Location, Project.Project); |
| |
| else |
| Object_File_Names_Htable.Set (Object_Files, Src.Object, Src); |
| end if; |
| end Check_Object; |
| |
| --------------------------- |
| -- Mark_Excluded_Sources -- |
| --------------------------- |
| |
| procedure Mark_Excluded_Sources is |
| Source : Source_Id := No_Source; |
| Excluded : File_Found; |
| Proj : Project_Id; |
| |
| begin |
| -- Minor optimization: if there are no excluded files, no need to |
| -- traverse the list of sources. We cannot however also check whether |
| -- the existing exceptions have ".Found" set to True (indicating we |
| -- found them before) because we need to do some final processing on |
| -- them in any case. |
| |
| if Excluded_Sources_Htable.Get_First (Project.Excluded) /= |
| No_File_Found |
| then |
| Proj := Project.Project; |
| while Proj /= No_Project loop |
| Iter := For_Each_Source (Data.Tree, Proj); |
| while Prj.Element (Iter) /= No_Source loop |
| Source := Prj.Element (Iter); |
| Excluded := Excluded_Sources_Htable.Get |
| (Project.Excluded, Source.File); |
| |
| if Excluded /= No_File_Found then |
| Source.In_Interfaces := False; |
| Source.Locally_Removed := True; |
| |
| if Proj = Project.Project then |
| Source.Suppressed := True; |
| end if; |
| |
| if Current_Verbosity = High then |
| Debug_Indent; |
| Write_Str ("removing file "); |
| Write_Line |
| (Get_Name_String (Excluded.File) |
| & " " & Get_Name_String (Source.Project.Name)); |
| end if; |
| |
| Excluded_Sources_Htable.Remove |
| (Project.Excluded, Source.File); |
| end if; |
| |
| Next (Iter); |
| end loop; |
| |
| Proj := Proj.Extends; |
| end loop; |
| end if; |
| |
| -- If we have any excluded element left, that means we did not find |
| -- the source file |
| |
| Excluded := Excluded_Sources_Htable.Get_First (Project.Excluded); |
| while Excluded /= No_File_Found loop |
| if not Excluded.Found then |
| |
| -- Check if the file belongs to another imported project to |
| -- provide a better error message. |
| |
| Src := Find_Source |
| (In_Tree => Data.Tree, |
| Project => Project.Project, |
| In_Imported_Only => True, |
| Base_Name => Excluded.File); |
| |
| Err_Vars.Error_Msg_File_1 := Excluded.File; |
| |
| if Src = No_Source then |
| if Excluded.Excl_File = No_File then |
| Error_Msg |
| (Data.Flags, |
| "unknown file {", Excluded.Location, Project.Project); |
| |
| else |
| Error_Msg |
| (Data.Flags, |
| "in " & |
| Get_Name_String (Excluded.Excl_File) & ":" & |
| No_Space_Img (Excluded.Excl_Line) & |
| ": unknown file {", Excluded.Location, Project.Project); |
| end if; |
| |
| else |
| if Excluded.Excl_File = No_File then |
| Error_Msg |
| (Data.Flags, |
| "cannot remove a source from an imported project: {", |
| Excluded.Location, Project.Project); |
| |
| else |
| Error_Msg |
| (Data.Flags, |
| "in " & |
| Get_Name_String (Excluded.Excl_File) & ":" & |
| No_Space_Img (Excluded.Excl_Line) & |
| ": cannot remove a source from an imported project: {", |
| Excluded.Location, Project.Project); |
| end if; |
| end if; |
| end if; |
| |
| Excluded := Excluded_Sources_Htable.Get_Next (Project.Excluded); |
| end loop; |
| end Mark_Excluded_Sources; |
| |
| ------------------------ |
| -- Check_Object_Files -- |
| ------------------------ |
| |
| procedure Check_Object_Files is |
| Iter : Source_Iterator; |
| Src_Id : Source_Id; |
| Src_Ind : Source_File_Index; |
| |
| begin |
| Iter := For_Each_Source (Data.Tree); |
| loop |
| Src_Id := Prj.Element (Iter); |
| exit when Src_Id = No_Source; |
| |
| if Is_Compilable (Src_Id) |
| and then Src_Id.Language.Config.Object_Generated |
| and then Is_Extending (Project.Project, Src_Id.Project) |
| then |
| if Src_Id.Unit = No_Unit_Index then |
| if Src_Id.Kind = Impl then |
| Check_Object (Src_Id); |
| end if; |
| |
| else |
| case Src_Id.Kind is |
| when Spec => |
| if Other_Part (Src_Id) = No_Source then |
| Check_Object (Src_Id); |
| end if; |
| |
| when Sep => |
| null; |
| |
| when Impl => |
| if Other_Part (Src_Id) /= No_Source then |
| Check_Object (Src_Id); |
| |
| else |
| -- Check if it is a subunit |
| |
| Src_Ind := |
| Sinput.P.Load_Project_File |
| (Get_Name_String (Src_Id.Path.Display_Name)); |
| |
| if Sinput.P.Source_File_Is_Subunit (Src_Ind) then |
| Override_Kind (Src_Id, Sep); |
| else |
| Check_Object (Src_Id); |
| end if; |
| end if; |
| end case; |
| end if; |
| end if; |
| |
| Next (Iter); |
| end loop; |
| end Check_Object_Files; |
| |
| ---------------------------------- |
| -- Get_Sources_From_Source_Info -- |
| ---------------------------------- |
| |
| procedure Get_Sources_From_Source_Info is |
| Iter : Source_Info_Iterator; |
| Src : Source_Info; |
| Id : Source_Id; |
| Lang_Id : Language_Ptr; |
| |
| begin |
| Initialize (Iter, Project.Project.Name); |
| |
| loop |
| Src := Source_Info_Of (Iter); |
| |
| exit when Src = No_Source_Info; |
| |
| Id := new Source_Data; |
| |
| Id.Project := Project.Project; |
| |
| Lang_Id := Project.Project.Languages; |
| while Lang_Id /= No_Language_Index |
| and then Lang_Id.Name /= Src.Language |
| loop |
| Lang_Id := Lang_Id.Next; |
| end loop; |
| |
| if Lang_Id = No_Language_Index then |
| Prj.Com.Fail |
| ("unknown language " & |
| Get_Name_String (Src.Language) & |
| " for project " & |
| Get_Name_String (Src.Project) & |
| " in source info file"); |
| end if; |
| |
| Id.Language := Lang_Id; |
| Id.Kind := Src.Kind; |
| Id.Index := Src.Index; |
| |
| Id.Path := |
| (Path_Name_Type (Src.Display_Path_Name), |
| Path_Name_Type (Src.Path_Name)); |
| |
| Name_Len := 0; |
| Add_Str_To_Name_Buffer |
| (Directories.Simple_Name (Get_Name_String (Src.Path_Name))); |
| Id.File := Name_Find; |
| |
| Id.Next_With_File_Name := |
| Source_Files_Htable.Get (Data.Tree.Source_Files_HT, Id.File); |
| Source_Files_Htable.Set (Data.Tree.Source_Files_HT, Id.File, Id); |
| |
| Name_Len := 0; |
| Add_Str_To_Name_Buffer |
| (Directories.Simple_Name |
| (Get_Name_String (Src.Display_Path_Name))); |
| Id.Display_File := Name_Find; |
| |
| Id.Dep_Name := |
| Dependency_Name (Id.File, Id.Language.Config.Dependency_Kind); |
| Id.Naming_Exception := Src.Naming_Exception; |
| Id.Object := |
| Object_Name (Id.File, Id.Language.Config.Object_File_Suffix); |
| Id.Switches := Switches_Name (Id.File); |
| |
| -- Add the source id to the Unit_Sources_HT hash table, if the |
| -- unit name is not null. |
| |
| if Src.Kind /= Sep and then Src.Unit_Name /= No_Name then |
| |
| declare |
| UData : Unit_Index := |
| Units_Htable.Get |
| (Data.Tree.Units_HT, Src.Unit_Name); |
| begin |
| if UData = No_Unit_Index then |
| UData := new Unit_Data; |
| UData.Name := Src.Unit_Name; |
| Units_Htable.Set |
| (Data.Tree.Units_HT, Src.Unit_Name, UData); |
| end if; |
| |
| Id.Unit := UData; |
| end; |
| |
| -- Note that this updates Unit information as well |
| |
| Override_Kind (Id, Id.Kind); |
| end if; |
| |
| if Src.Index /= 0 then |
| Project.Project.Has_Multi_Unit_Sources := True; |
| end if; |
| |
| -- Add the source to the language list |
| |
| Id.Next_In_Lang := Id.Language.First_Source; |
| Id.Language.First_Source := Id; |
| |
| Next (Iter); |
| end loop; |
| end Get_Sources_From_Source_Info; |
| |
| -- Start of processing for Look_For_Sources |
| |
| begin |
| if Data.Tree.Source_Info_File_Exists then |
| Get_Sources_From_Source_Info; |
| |
| else |
| if Project.Project.Source_Dirs /= Nil_String then |
| Find_Excluded_Sources (Project, Data); |
| |
| if Project.Project.Languages /= No_Language_Index then |
| Load_Naming_Exceptions (Project, Data); |
| Find_Sources (Project, Data); |
| Mark_Excluded_Sources; |
| Check_Object_Files; |
| Check_Missing_Sources; |
| end if; |
| end if; |
| |
| Object_File_Names_Htable.Reset (Object_Files); |
| end if; |
| end Look_For_Sources; |
| |
| ------------------ |
| -- Path_Name_Of -- |
| ------------------ |
| |
| function Path_Name_Of |
| (File_Name : File_Name_Type; |
| Directory : Path_Name_Type) return String |
| is |
| Result : String_Access; |
| The_Directory : constant String := Get_Name_String (Directory); |
| |
| begin |
| Debug_Output ("Path_Name_Of file name=", Name_Id (File_Name)); |
| Debug_Output ("Path_Name_Of directory=", Name_Id (Directory)); |
| Get_Name_String (File_Name); |
| Result := |
| Locate_Regular_File |
| (File_Name => Name_Buffer (1 .. Name_Len), |
| Path => The_Directory); |
| |
| if Result = null then |
| return ""; |
| else |
| declare |
| R : constant String := Result.all; |
| begin |
| Free (Result); |
| return R; |
| end; |
| end if; |
| end Path_Name_Of; |
| |
| ------------------- |
| -- Remove_Source -- |
| ------------------- |
| |
| procedure Remove_Source |
| (Tree : Project_Tree_Ref; |
| Id : Source_Id; |
| Replaced_By : Source_Id) |
| is |
| Source : Source_Id; |
| |
| begin |
| if Current_Verbosity = High then |
| Debug_Indent; |
| Write_Str ("removing source "); |
| Write_Str (Get_Name_String (Id.File)); |
| |
| if Id.Index /= 0 then |
| Write_Str (" at" & Id.Index'Img); |
| end if; |
| |
| Write_Eol; |
| end if; |
| |
| if Replaced_By /= No_Source then |
| Id.Replaced_By := Replaced_By; |
| Replaced_By.Declared_In_Interfaces := Id.Declared_In_Interfaces; |
| |
| if Id.File /= Replaced_By.File then |
| declare |
| Replacement : constant File_Name_Type := |
| Replaced_Source_HTable.Get |
| (Tree.Replaced_Sources, Id.File); |
| |
| begin |
| Replaced_Source_HTable.Set |
| (Tree.Replaced_Sources, Id.File, Replaced_By.File); |
| |
| if Replacement = No_File then |
| Tree.Replaced_Source_Number := |
| Tree.Replaced_Source_Number + 1; |
| end if; |
| end; |
| end if; |
| end if; |
| |
| Id.In_Interfaces := False; |
| Id.Locally_Removed := True; |
| |
| -- ??? Should we remove the source from the unit ? The file is not used, |
| -- so probably should not be referenced from the unit. On the other hand |
| -- it might give useful additional info |
| -- if Id.Unit /= null then |
| -- Id.Unit.File_Names (Id.Kind) := null; |
| -- end if; |
| |
| Source := Id.Language.First_Source; |
| |
| if Source = Id then |
| Id.Language.First_Source := Id.Next_In_Lang; |
| |
| else |
| while Source.Next_In_Lang /= Id loop |
| Source := Source.Next_In_Lang; |
| end loop; |
| |
| Source.Next_In_Lang := Id.Next_In_Lang; |
| end if; |
| end Remove_Source; |
| |
| ----------------------- |
| -- Report_No_Sources -- |
| ----------------------- |
| |
| procedure Report_No_Sources |
| (Project : Project_Id; |
| Lang_Name : String; |
| Data : Tree_Processing_Data; |
| Location : Source_Ptr; |
| Continuation : Boolean := False) |
| is |
| begin |
| case Data.Flags.When_No_Sources is |
| when Silent => |
| null; |
| |
| when Warning | Error => |
| declare |
| Msg : constant String := |
| "<there are no " |
| & Lang_Name & " sources in this project"; |
| |
| begin |
| Error_Msg_Warn := Data.Flags.When_No_Sources = Warning; |
| |
| if Continuation then |
| Error_Msg (Data.Flags, "\" & Msg, Location, Project); |
| else |
| Error_Msg (Data.Flags, Msg, Location, Project); |
| end if; |
| end; |
| end case; |
| end Report_No_Sources; |
| |
| ---------------------- |
| -- Show_Source_Dirs -- |
| ---------------------- |
| |
| procedure Show_Source_Dirs |
| (Project : Project_Id; |
| Shared : Shared_Project_Tree_Data_Access) |
| is |
| Current : String_List_Id; |
| Element : String_Element; |
| |
| begin |
| if Project.Source_Dirs = Nil_String then |
| Debug_Output ("no Source_Dirs"); |
| else |
| Debug_Increase_Indent ("Source_Dirs:"); |
| |
| Current := Project.Source_Dirs; |
| while Current /= Nil_String loop |
| Element := Shared.String_Elements.Table (Current); |
| Debug_Output (Get_Name_String (Element.Display_Value)); |
| Current := Element.Next; |
| end loop; |
| |
| Debug_Decrease_Indent ("end Source_Dirs."); |
| end if; |
| end Show_Source_Dirs; |
| |
| --------------------------- |
| -- Process_Naming_Scheme -- |
| --------------------------- |
| |
| procedure Process_Naming_Scheme |
| (Tree : Project_Tree_Ref; |
| Root_Project : Project_Id; |
| Node_Tree : Prj.Tree.Project_Node_Tree_Ref; |
| Flags : Processing_Flags) |
| is |
| |
| procedure Check |
| (Project : Project_Id; |
| In_Aggregate_Lib : Boolean; |
| Data : in out Tree_Processing_Data); |
| -- Process the naming scheme for a single project |
| |
| procedure Recursive_Check |
| (Project : Project_Id; |
| Prj_Tree : Project_Tree_Ref; |
| Context : Project_Context; |
| Data : in out Tree_Processing_Data); |
| -- Check_Naming_Scheme for the project |
| |
| ----------- |
| -- Check -- |
| ----------- |
| |
| procedure Check |
| (Project : Project_Id; |
| In_Aggregate_Lib : Boolean; |
| Data : in out Tree_Processing_Data) |
| is |
| procedure Check_Aggregate |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data); |
| -- Check the aggregate project attributes, reject any not supported |
| -- attributes. |
| |
| procedure Check_Aggregated |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data); |
| -- Check aggregated projects which should not be externally built. |
| -- What is Data??? if same as outer Data, why passed??? |
| -- What exact check is performed here??? Seems a bad idea to have |
| -- two procedures with such close names ??? |
| |
| --------------------- |
| -- Check_Aggregate -- |
| --------------------- |
| |
| procedure Check_Aggregate |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data) |
| is |
| procedure Check_Not_Defined (Name : Name_Id); |
| -- Report an error if Var is defined |
| |
| ----------------------- |
| -- Check_Not_Defined -- |
| ----------------------- |
| |
| procedure Check_Not_Defined (Name : Name_Id) is |
| Var : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Name, Project.Decl.Attributes, Data.Tree.Shared); |
| begin |
| if not Var.Default then |
| Error_Msg_Name_1 := Name; |
| Error_Msg |
| (Data.Flags, "wrong attribute %% in aggregate library", |
| Var.Location, Project); |
| end if; |
| end Check_Not_Defined; |
| |
| -- Start of processing for Check_Aggregate |
| |
| begin |
| Check_Not_Defined (Snames.Name_Library_Dir); |
| Check_Not_Defined (Snames.Name_Library_Interface); |
| Check_Not_Defined (Snames.Name_Library_Name); |
| Check_Not_Defined (Snames.Name_Library_Ali_Dir); |
| Check_Not_Defined (Snames.Name_Library_Src_Dir); |
| Check_Not_Defined (Snames.Name_Library_Options); |
| Check_Not_Defined (Snames.Name_Library_Standalone); |
| Check_Not_Defined (Snames.Name_Library_Kind); |
| Check_Not_Defined (Snames.Name_Leading_Library_Options); |
| Check_Not_Defined (Snames.Name_Library_Version); |
| end Check_Aggregate; |
| |
| ---------------------- |
| -- Check_Aggregated -- |
| ---------------------- |
| |
| procedure Check_Aggregated |
| (Project : Project_Id; |
| Data : in out Tree_Processing_Data) |
| is |
| L : Aggregated_Project_List; |
| |
| begin |
| -- Check that aggregated projects are not externally built |
| |
| L := Project.Aggregated_Projects; |
| while L /= null loop |
| declare |
| Var : constant Prj.Variable_Value := |
| Prj.Util.Value_Of |
| (Snames.Name_Externally_Built, |
| L.Project.Decl.Attributes, |
| Data.Tree.Shared); |
| begin |
| if not Var.Default then |
| Error_Msg_Name_1 := L.Project.Display_Name; |
| Error_Msg |
| (Data.Flags, |
| "cannot aggregate externally build library %%", |
| Var.Location, Project); |
| end if; |
| end; |
| |
| L := L.Next; |
| end loop; |
| end Check_Aggregated; |
| |
| -- Local Variables |
| |
| Shared : constant Shared_Project_Tree_Data_Access := |
| Data.Tree.Shared; |
| Prj_Data : Project_Processing_Data; |
| |
| -- Start of processing for Check |
| |
| begin |
| Debug_Increase_Indent ("check", Project.Name); |
| |
| Initialize (Prj_Data, Project); |
| |
| Check_If_Externally_Built (Project, Data); |
| |
| case Project.Qualifier is |
| when Aggregate => |
| Check_Aggregated (Project, Data); |
| |
| when Aggregate_Library => |
| Check_Aggregated (Project, Data); |
| |
| if Project.Object_Directory = No_Path_Information then |
| Project.Object_Directory := Project.Directory; |
| end if; |
| |
| when others => |
| Get_Directories (Project, Data); |
| Check_Programming_Languages (Project, Data); |
| |
| if Current_Verbosity = High then |
| Show_Source_Dirs (Project, Shared); |
| end if; |
| |
| if Project.Qualifier = Dry then |
| Check_Abstract_Project (Project, Data); |
| end if; |
| end case; |
| |
| -- Check configuration. Must be done for gnatmake (even though no |
| -- user configuration file was provided) since the default config we |
| -- generate indicates whether libraries are supported for instance. |
| |
| Check_Configuration (Project, Data); |
| |
| -- For aggregate project check no library attributes are defined |
| |
| if Project.Qualifier = Aggregate then |
| Check_Aggregate (Project, Data); |
| |
| else |
| Check_Library_Attributes (Project, Data); |
| Check_Package_Naming (Project, Data); |
| |
| -- An aggregate library has no source, no need to look for them |
| |
| if Project.Qualifier /= Aggregate_Library then |
| Look_For_Sources (Prj_Data, Data); |
| end if; |
| |
| Check_Interfaces (Project, Data); |
| |
| -- If this library is part of an aggregated library don't check it |
| -- as it has no sources by itself and so interface won't be found. |
| |
| if Project.Library and not In_Aggregate_Lib then |
| Check_Stand_Alone_Library (Project, Data); |
| end if; |
| |
| Get_Mains (Project, Data); |
| end if; |
| |
| Free (Prj_Data); |
| |
| Debug_Decrease_Indent ("done check"); |
| end Check; |
| |
| --------------------- |
| -- Recursive_Check -- |
| --------------------- |
| |
| procedure Recursive_Check |
| (Project : Project_Id; |
| Prj_Tree : Project_Tree_Ref; |
| Context : Project_Context; |
| Data : in out Tree_Processing_Data) |
| is |
| begin |
| if Current_Verbosity = High then |
| Debug_Increase_Indent |
| ("Processing_Naming_Scheme for project", Project.Name); |
| end if; |
| |
| Data.Tree := Prj_Tree; |
| Data.In_Aggregate_Lib := Context.In_Aggregate_Lib; |
| |
| Check (Project, Context.In_Aggregate_Lib, Data); |
| |
| if Current_Verbosity = High then |
| Debug_Decrease_Indent ("done Processing_Naming_Scheme"); |
| end if; |
| end Recursive_Check; |
| |
| procedure Check_All_Projects is new For_Every_Project_Imported_Context |
| (Tree_Processing_Data, Recursive_Check); |
| -- Comment required??? |
| |
| -- Local Variables |
| |
| Data : Tree_Processing_Data; |
| |
| -- Start of processing for Process_Naming_Scheme |
| |
| begin |
| Lib_Data_Table.Init; |
| Initialize (Data, Tree => Tree, Node_Tree => Node_Tree, Flags => Flags); |
| Check_All_Projects (Root_Project, Tree, Data, Imported_First => True); |
| Free (Data); |
| |
| -- Adjust language configs for projects that are extended |
| |
| declare |
| List : Project_List; |
| Proj : Project_Id; |
| Exte : Project_Id; |
| Lang : Language_Ptr; |
| Elng : Language_Ptr; |
| |
| begin |
| List := Tree.Projects; |
| while List /= null loop |
| Proj := List.Project; |
| |
| Exte := Proj; |
| while Exte.Extended_By /= No_Project loop |
| Exte := Exte.Extended_By; |
| end loop; |
| |
| if Exte /= Proj then |
| Lang := Proj.Languages; |
| |
| if Lang /= No_Language_Index then |
| loop |
| Elng := Get_Language_From_Name |
| (Exte, Get_Name_String (Lang.Name)); |
| exit when Elng /= No_Language_Index; |
| Exte := Exte.Extends; |
| end loop; |
| |
| if Elng /= Lang then |
| Lang.Config := Elng.Config; |
| end if; |
| end if; |
| end if; |
| |
| List := List.Next; |
| end loop; |
| end; |
| end Process_Naming_Scheme; |
| |
| end Prj.Nmsc; |