with Opt; use Opt;
with Osint; use Osint;
with Output; use Output;
+with Prj.Com;
with Prj.Err; use Prj.Err;
with Prj.Util; use Prj.Util;
with Sinput.P;
type Tree_Processing_Data is record
Tree : Project_Tree_Ref;
+ Node_Tree : Prj.Tree.Project_Node_Tree_Ref;
File_To_Source : Files_Htable.Instance;
Flags : Prj.Processing_Flags;
end record;
-- projects do not have the same library names.
procedure Initialize
- (Data : out Tree_Processing_Data;
- Tree : Project_Tree_Ref;
- Flags : Prj.Processing_Flags);
+ (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);
-- exceptions, and copied into the Source_Names and Unit_Exceptions tables
-- as appropriate.
+ type Search_Type is (Search_Files, Search_Directories);
+ pragma Unreferenced (Search_Files);
+
+ generic
+ with procedure Callback
+ (Path_Id : Path_Name_Type;
+ Display_Path_Id : Path_Name_Type;
+ Pattern_Index : Natural);
+ procedure Expand_Subdirectory_Pattern
+ (Project : Project_Id;
+ Data : in out Tree_Processing_Data;
+ Patterns : 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
+
procedure Add_Source
(Id : out Source_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_Aggregate_Project
+ (Project : Project_Id;
+ Data : in out Tree_Processing_Data);
+ -- Check aggregate projects attributes
+
+ procedure Check_Abstract_Project
+ (Project : Project_Id;
+ Data : in out Tree_Processing_Data);
+ -- Check abstract projects attributes
+
procedure Check_Programming_Languages
(Project : Project_Id;
Data : in out Tree_Processing_Data);
(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 Data.First_Source has
- -- been initialized with the list of excluded sources and special naming
- -- exceptions.
+ -- update its Data accordingly. This assumes that the special naming
+ -- exceptions have already been processed.
function Path_Name_Of
(File_Name : File_Name_Type;
end if;
end Canonical_Case_File_Name;
+ -----------------------------
+ -- Check_Aggregate_Project --
+ -----------------------------
+
+ procedure Check_Aggregate_Project
+ (Project : Project_Id;
+ Data : in out Tree_Processing_Data)
+ is
+ Project_Files : constant Prj.Variable_Value :=
+ Prj.Util.Value_Of
+ (Snames.Name_Project_Files,
+ Project.Decl.Attributes,
+ Data.Tree);
+ begin
+ if Project_Files.Default then
+ Error_Msg_Name_1 := Snames.Name_Project_Files;
+ Error_Msg
+ (Data.Flags,
+ "Attribute %% must be specified in aggregate project",
+ Project.Location, Project);
+ end if;
+ end Check_Aggregate_Project;
+
+ ----------------------------
+ -- Check_Abstract_Project --
+ ----------------------------
+
+ procedure Check_Abstract_Project
+ (Project : Project_Id;
+ Data : in out Tree_Processing_Data)
+ is
+ Source_Dirs : constant Variable_Value :=
+ Util.Value_Of
+ (Name_Source_Dirs,
+ Project.Decl.Attributes, Data.Tree);
+ Source_Files : constant Variable_Value :=
+ Util.Value_Of
+ (Name_Source_Files,
+ Project.Decl.Attributes, Data.Tree);
+ Source_List_File : constant Variable_Value :=
+ Util.Value_Of
+ (Name_Source_List_File,
+ Project.Decl.Attributes, Data.Tree);
+ Languages : constant Variable_Value :=
+ Util.Value_Of
+ (Name_Languages,
+ Project.Decl.Attributes, Data.Tree);
+
+ 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 --
-----------
(Project : Project_Id;
Data : in out Tree_Processing_Data)
is
- Extending : Boolean := False;
Prj_Data : Project_Processing_Data;
begin
Initialize (Prj_Data, Project);
- Check_If_Externally_Built (Project, Data);
-
- -- Object, exec and source directories
-
- Get_Directories (Project, Data);
-
- -- Get the programming languages
-
+ Check_If_Externally_Built (Project, Data);
+ Get_Directories (Project, Data);
Check_Programming_Languages (Project, Data);
- if Project.Qualifier = Dry
- and then Project.Source_Dirs /= Nil_String
- then
- declare
- Source_Dirs : constant Variable_Value :=
- Util.Value_Of
- (Name_Source_Dirs,
- Project.Decl.Attributes, Data.Tree);
- Source_Files : constant Variable_Value :=
- Util.Value_Of
- (Name_Source_Files,
- Project.Decl.Attributes, Data.Tree);
- Source_List_File : constant Variable_Value :=
- Util.Value_Of
- (Name_Source_List_File,
- Project.Decl.Attributes, Data.Tree);
- Languages : constant Variable_Value :=
- Util.Value_Of
- (Name_Languages,
- Project.Decl.Attributes, Data.Tree);
-
- begin
- 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;
- end if;
+ case Project.Qualifier is
+ when Aggregate => Check_Aggregate_Project (Project, Data);
+ when Dry => Check_Abstract_Project (Project, Data);
+ when others => null;
+ end case;
-- Check configuration. This must be done even for gnatmake (even though
-- no user configuration file was provided) since the default config we
Check_Configuration (Project, Data);
- -- Library attributes
-
Check_Library_Attributes (Project, Data);
if Current_Verbosity = High then
Show_Source_Dirs (Project, Data.Tree);
end if;
- Extending := Project.Extends /= No_Project;
-
Check_Package_Naming (Project, Data);
- -- Find the sources
-
- if Project.Source_Dirs /= Nil_String then
+ if Project.Qualifier /= Aggregate then
Look_For_Sources (Prj_Data, Data);
-
- if not Project.Externally_Built
- and then not Extending
- then
- declare
- Language : Language_Ptr;
- Source : Source_Id;
- Alt_Lang : Language_List;
- Continuation : Boolean := False;
- Iter : Source_Iterator;
-
- begin
- Language := 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);
- 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,
- Get_Name_String (Language.Display_Name),
- Data,
- Prj_Data.Source_List_File_Location,
- Continuation);
- Continuation := True;
- end if;
- end if;
-
- Language := Language.Next;
- end loop;
- end;
- end if;
end if;
- -- If a list of sources is specified in attribute Interfaces, set
- -- In_Interfaces only for the sources specified in the list.
-
Check_Interfaces (Project, Data);
- -- If it is a library project file, check if it is a standalone library
-
if Project.Library then
Check_Stand_Alone_Library (Project, Data);
end if;
- -- Put the list of Mains, if any, in the project data
-
Get_Mains (Project, Data);
Free (Prj_Data);
(Project : Project_Id;
Data : in out Tree_Processing_Data)
is
- 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.
-
- Visited : Recursive_Dirs.Instance;
-
Object_Dir : constant Variable_Value :=
Util.Value_Of
(Name_Object_Dir, Project.Decl.Attributes, Data.Tree);
Languages : constant Variable_Value :=
Prj.Util.Value_Of
- (Name_Languages, Project.Decl.Attributes, Data.Tree);
+ (Name_Languages, Project.Decl.Attributes, Data.Tree);
- procedure Find_Source_Dirs
- (From : File_Name_Type;
- Location : Source_Ptr;
- Rank : Natural;
- Removed : Boolean := False);
- -- Find one or several source directories, and add (or remove, if
- -- Removed is True) them to list of source directories of the project.
+ Remove_Source_Dirs : Boolean := False;
procedure Add_To_Or_Remove_From_Source_Dirs
(Path_Id : Path_Name_Type;
Display_Path_Id : Path_Name_Type;
- Rank : Natural;
- Removed : Boolean);
+ 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_Id : Path_Name_Type;
Display_Path_Id : Path_Name_Type;
- Rank : Natural;
- Removed : Boolean)
+ Rank : Natural)
is
List : String_List_Id;
Prev : String_List_Id;
-- The directory is in the list if List is not Nil_String
- if not Removed and then List = Nil_String then
+ if not Remove_Source_Dirs and then List = Nil_String then
if Current_Verbosity = High then
Write_Str (" Adding Source Dir=");
Write_Line (Get_Name_String (Display_Path_Id));
Data.Tree.Number_Lists.Table (Last_Src_Dir_Rank) :=
(Number => Rank, Next => No_Number_List);
- elsif Removed and then List /= Nil_String then
+ elsif Remove_Source_Dirs and then List /= Nil_String then
-- Remove source dir, if present
end if;
end Add_To_Or_Remove_From_Source_Dirs;
- ----------------------
- -- Find_Source_Dirs --
- ----------------------
-
- procedure Find_Source_Dirs
- (From : File_Name_Type;
- Location : Source_Ptr;
- Rank : Natural;
- Removed : Boolean := False)
- is
- Directory : constant String := Get_Name_String (From);
-
- procedure Recursive_Find_Dirs (Path : Name_Id);
- -- Find all the subdirectories (recursively) of Path and add them
- -- to the list of source directories of the project.
-
- -------------------------
- -- Recursive_Find_Dirs --
- -------------------------
-
- procedure Recursive_Find_Dirs (Path : Name_Id) is
- Dir : Dir_Type;
- Name : String (1 .. 250);
- Last : Natural;
-
- Non_Canonical_Path : Path_Name_Type := No_Path;
- Canonical_Path : Path_Name_Type := No_Path;
-
- The_Path : constant String :=
- Normalize_Pathname
- (Get_Name_String (Path),
- Directory =>
- Get_Name_String (Project.Directory.Display_Name),
- Resolve_Links => Opt.Follow_Links_For_Dirs) &
- Directory_Separator;
-
- The_Path_Last : constant Natural :=
- Compute_Directory_Last (The_Path);
-
- begin
- Name_Len := The_Path_Last - The_Path'First + 1;
- Name_Buffer (1 .. Name_Len) :=
- The_Path (The_Path'First .. The_Path_Last);
- Non_Canonical_Path := Name_Find;
- Canonical_Path :=
- Path_Name_Type
- (Canonical_Case_File_Name (Name_Id (Non_Canonical_Path)));
-
- -- To avoid processing the same directory several times, check
- -- if the directory is already in Recursive_Dirs. If it is, then
- -- there is nothing to do, just return. If it is not, put it there
- -- and continue recursive processing.
-
- if not Removed then
- if Recursive_Dirs.Get (Visited, Canonical_Path) then
- return;
- else
- Recursive_Dirs.Set (Visited, Canonical_Path, True);
- end if;
- end if;
-
- Add_To_Or_Remove_From_Source_Dirs
- (Path_Id => Canonical_Path,
- Display_Path_Id => Non_Canonical_Path,
- Rank => Rank,
- Removed => Removed);
-
- -- Now look for subdirectories. Do that even when this directory
- -- is already in the list, because some of its subdirectories may
- -- not be in the list yet.
-
- Open (Dir, The_Path (The_Path'First .. The_Path_Last));
-
- loop
- Read (Dir, Name, Last);
- exit when Last = 0;
-
- if Name (1 .. Last) /= "."
- and then Name (1 .. Last) /= ".."
- then
- -- Avoid . and .. directories
-
- if Current_Verbosity = High then
- Write_Str (" Checking ");
- Write_Line (Name (1 .. Last));
- end if;
-
- declare
- Path_Name : constant String :=
- Normalize_Pathname
- (Name => Name (1 .. Last),
- Directory =>
- The_Path
- (The_Path'First .. The_Path_Last),
- Resolve_Links =>
- Opt.Follow_Links_For_Dirs,
- Case_Sensitive => True);
-
- begin
- if Is_Directory (Path_Name) then
-
- -- We have found a new subdirectory, call self
-
- Name_Len := Path_Name'Length;
- Name_Buffer (1 .. Name_Len) := Path_Name;
- Recursive_Find_Dirs (Name_Find);
- end if;
- end;
- end if;
- end loop;
-
- Close (Dir);
-
- exception
- when Directory_Error =>
- null;
- end Recursive_Find_Dirs;
-
- -- Start of processing for Find_Source_Dirs
-
- begin
- if Current_Verbosity = High and then not Removed then
- Write_Str ("Find_Source_Dirs (""");
- Write_Str (Directory);
- Write_Str (",");
- Write_Str (Rank'Img);
- Write_Line (""")");
- end if;
+ -- Local declarations
- -- First, check if we are looking for a directory tree, indicated
- -- by "/**" at the end.
+ Dir_Exists : Boolean;
- if Directory'Length >= 3
- and then Directory (Directory'Last - 1 .. Directory'Last) = "**"
- and then (Directory (Directory'Last - 2) = '/'
+ No_Sources : constant Boolean :=
+ ((not Source_Files.Default
+ and then Source_Files.Values = Nil_String)
or else
- Directory (Directory'Last - 2) = Directory_Separator)
- then
- Name_Len := Directory'Length - 3;
-
- if Name_Len = 0 then
-
- -- Case of "/**": all directories in file system
-
- Name_Len := 1;
- Name_Buffer (1) := Directory (Directory'First);
-
- else
- Name_Buffer (1 .. Name_Len) :=
- Directory (Directory'First .. Directory'Last - 3);
- end if;
-
- if Current_Verbosity = High then
- Write_Str ("Looking for all subdirectories of """);
- Write_Str (Name_Buffer (1 .. Name_Len));
- Write_Line ("""");
- end if;
-
- declare
- Base_Dir : constant File_Name_Type := Name_Find;
- Root_Dir : constant String :=
- Normalize_Pathname
- (Name => Name_Buffer (1 .. Name_Len),
- Directory =>
- Get_Name_String
- (Project.Directory.Display_Name),
- Resolve_Links =>
- Opt.Follow_Links_For_Dirs,
- Case_Sensitive => True);
- Has_Error : Boolean := False;
-
- begin
- if Root_Dir'Length = 0 then
- Err_Vars.Error_Msg_File_1 := Base_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
-
- -- We have an existing directory, we register it and all of
- -- its subdirectories.
-
- if Current_Verbosity = High then
- Write_Line ("Looking for source directories:");
- end if;
-
- Name_Len := Root_Dir'Length;
- Name_Buffer (1 .. Name_Len) := Root_Dir;
- Recursive_Find_Dirs (Name_Find);
-
- if Current_Verbosity = High then
- Write_Line ("End of looking for source directories.");
- end if;
- end if;
- end;
-
- -- We have a single directory
-
- else
- declare
- Path_Name : Path_Information;
- Dir_Exists : Boolean;
- Has_Error : Boolean := False;
-
- begin
- Locate_Directory
- (Project => Project,
- Name => From,
- Path => Path_Name,
- Dir_Exists => Dir_Exists,
- Data => Data,
- Must_Exist => False);
-
- if not Dir_Exists then
- Err_Vars.Error_Msg_File_1 := From;
- 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.
-
- Add_To_Or_Remove_From_Source_Dirs
- (Path_Id => Path_Name.Name,
- Display_Path_Id => Path_Name.Display_Name,
- Rank => Rank,
- Removed => Removed);
- end if;
- end;
- end if;
-
- Recursive_Dirs.Reset (Visited);
- end Find_Source_Dirs;
+ (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
- Dir_Exists : Boolean;
-
begin
if Current_Verbosity = High then
Write_Line ("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 (((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
- then
+ if No_Sources then
Project.Object_Directory := No_Path_Information;
else
Project.Object_Directory := Project.Directory;
"Object_Dir cannot be empty",
Object_Dir.Location, Project);
- else
+ elsif not No_Sources then
+
-- 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
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.
+ -- 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);
end if;
end if;
- elsif Project.Object_Directory /= No_Path_Information
- and then Subdirs /= null
- then
+ elsif not No_Sources and then Subdirs /= null then
Name_Len := 1;
Name_Buffer (1) := '.';
Locate_Directory
"Exec_Dir cannot be empty",
Exec_Dir.Location, Project);
- else
+ elsif not No_Sources then
+
-- We check that the specified exec directory does exist
Locate_Directory
-- 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_Id => Project.Directory.Name,
Display_Path_Id => Project.Directory.Display_Name,
- Rank => 1,
- Removed => False);
+ Rank => 1);
else
- declare
- Source_Dir : String_List_Id;
- Element : String_Element;
- Rank : Natural;
- begin
- -- Process the source directories for each element of the list
-
- Source_Dir := Source_Dirs.Values;
- Rank := 0;
- while Source_Dir /= Nil_String loop
- Element := Data.Tree.String_Elements.Table (Source_Dir);
- Rank := Rank + 1;
- Find_Source_Dirs
- (File_Name_Type (Element.Value), Element.Location, Rank);
- Source_Dir := Element.Next;
- end loop;
-
- 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;
+ Remove_Source_Dirs := False;
+ Find_Source_Dirs
+ (Project => Project,
+ Data => Data,
+ Patterns => Source_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
- declare
- Source_Dir : String_List_Id;
- Element : String_Element;
-
- begin
- -- Process the source directories for each element of the list
-
- Source_Dir := Excluded_Source_Dirs.Values;
- while Source_Dir /= Nil_String loop
- Element := Data.Tree.String_Elements.Table (Source_Dir);
- Find_Source_Dirs
- (File_Name_Type (Element.Value),
- Element.Location,
- 0,
- Removed => True);
- Source_Dir := Element.Next;
- end loop;
- end;
+ Remove_Source_Dirs := True;
+ Find_Source_Dirs
+ (Project => Project,
+ Data => Data,
+ Patterns => Excluded_Source_Dirs.Values,
+ Search_For => Search_Directories,
+ Resolve_Links => Opt.Follow_Links_For_Dirs);
end if;
if Current_Verbosity = High then
----------------
procedure Initialize
- (Data : out Tree_Processing_Data;
- Tree : Project_Tree_Ref;
- Flags : Prj.Processing_Flags)
+ (Data : out Tree_Processing_Data;
+ Tree : Project_Tree_Ref;
+ Node_Tree : Prj.Tree.Project_Node_Tree_Ref;
+ Flags : Prj.Processing_Flags)
is
begin
Files_Htable.Reset (Data.File_To_Source);
- Data.Tree := Tree;
- Data.Flags := Flags;
+ Data.Tree := Tree;
+ Data.Node_Tree := Node_Tree;
+ Data.Flags := Flags;
end Initialize;
----------
end if;
end Check_File;
+ ---------------------------------
+ -- Expand_Subdirectory_Pattern --
+ ---------------------------------
+
+ procedure Expand_Subdirectory_Pattern
+ (Project : Project_Id;
+ Data : in out Tree_Processing_Data;
+ Patterns : String_List_Id;
+ Search_For : Search_Type;
+ Resolve_Links : Boolean)
+ is
+ pragma Unreferenced (Search_For);
+ 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.
+
+ Visited : Recursive_Dirs.Instance;
+
+ procedure Find_Pattern
+ (Pattern : String; Rank : Natural; Location : Source_Ptr);
+ -- Find a specific pattern
+
+ procedure Recursive_Find_Dirs (Normalized_Path : String; Rank : Natural);
+ -- Search all the subdirectories (recursively) of Path
+
+ procedure Check_Directory_And_Subdirs
+ (Directory : String;
+ Include_Subdirs : Boolean;
+ Rank : Natural;
+ Location : Source_Ptr);
+ -- Make sur that Directory exists (and if not report an error/warning
+ -- message depending on the flags.
+ -- Calls Callback for Directory itself and all its subdirectories if
+ -- Include_Subdirs is True).
+
+ -------------------------
+ -- Recursive_Find_Dirs --
+ -------------------------
+
+ procedure Recursive_Find_Dirs
+ (Normalized_Path : String; Rank : Natural)
+ is
+ Dir : Dir_Type;
+ Name : String (1 .. 250);
+ Last : Natural;
+
+ Non_Canonical_Path : Path_Name_Type := No_Path;
+ Canonical_Path : Path_Name_Type := No_Path;
+
+ The_Path_Last : constant Natural :=
+ Compute_Directory_Last (Normalized_Path);
+
+ begin
+ Name_Len := 0;
+ Add_Str_To_Name_Buffer
+ (Normalized_Path (Normalized_Path'First .. The_Path_Last));
+ Non_Canonical_Path := Name_Find;
+
+ Canonical_Path :=
+ Path_Name_Type
+ (Canonical_Case_File_Name (Name_Id (Non_Canonical_Path)));
+
+ if Recursive_Dirs.Get (Visited, Canonical_Path) then
+ return;
+ end if;
+
+ Recursive_Dirs.Set (Visited, Canonical_Path, True);
+
+ Callback (Canonical_Path, Non_Canonical_Path, Rank);
+
+ Open (Dir, Normalized_Path (Normalized_Path'First .. The_Path_Last));
+
+ loop
+ Read (Dir, Name, Last);
+ exit when Last = 0;
+
+ if Name (1 .. Last) /= "."
+ and then Name (1 .. Last) /= ".."
+ then
+ if Current_Verbosity = High then
+ Write_Str (" Checking ");
+ Write_Line (Name (1 .. Last));
+ end if;
+
+ declare
+ Path_Name : constant String :=
+ Normalize_Pathname
+ (Name => Name (1 .. Last),
+ Directory =>
+ Normalized_Path
+ (Normalized_Path'First .. The_Path_Last),
+ Resolve_Links => Resolve_Links)
+ & Directory_Separator;
+ begin
+ if Is_Directory (Path_Name) then
+ Recursive_Find_Dirs (Path_Name, Rank);
+ end if;
+ end;
+ end if;
+ end loop;
+
+ Close (Dir);
+
+ exception
+ when Directory_Error =>
+ null;
+ end Recursive_Find_Dirs;
+
+ ---------------------------------
+ -- Check_Directory_And_Subdirs --
+ ---------------------------------
+
+ procedure Check_Directory_And_Subdirs
+ (Directory : String;
+ Include_Subdirs : Boolean;
+ Rank : Natural;
+ Location : Source_Ptr)
+ is
+ Dir : File_Name_Type;
+ Path_Name : Path_Information;
+ Dir_Exists : Boolean;
+ Has_Error : Boolean := False;
+ begin
+ Name_Len := Directory'Length;
+ Name_Buffer (1 .. Name_Len) := Directory;
+ 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 Include_Subdirs then
+ if Current_Verbosity = High then
+ Write_Str ("Looking for all subdirectories of """);
+ Write_Str (Directory);
+ Write_Line ("""");
+ end if;
+
+ Recursive_Find_Dirs (Get_Name_String (Path_Name.Name), Rank);
+
+ if Current_Verbosity = High then
+ Write_Line ("End of looking for source directories.");
+ end if;
+
+ else
+ Callback (Path_Name.Name, Path_Name.Display_Name, Rank);
+ end if;
+ end if;
+ end Check_Directory_And_Subdirs;
+
+ ------------------
+ -- Find_Pattern --
+ ------------------
+
+ procedure Find_Pattern
+ (Pattern : String; Rank : Natural; Location : Source_Ptr) is
+ begin
+ if Current_Verbosity = High then
+ Write_Str ("Expand_Subdirectory_Pattern (""");
+ Write_Str (Pattern);
+ Write_Line (""")");
+ end if;
+
+ -- First, check if we are looking for a directory tree, indicated
+ -- by "/**" at the end.
+
+ if Pattern'Length >= 3
+ and then Pattern (Pattern'Last - 1 .. Pattern'Last) = "**"
+ and then (Pattern (Pattern'Last - 2) = '/'
+ or else Pattern (Pattern'Last - 2) = Directory_Separator)
+ then
+ if Pattern'Length = 3 then
+ -- Case of "/**": all directories in file system
+ Check_Directory_And_Subdirs
+ (Pattern (Pattern'First .. Pattern'First),
+ True, Rank, Location);
+ else
+ Check_Directory_And_Subdirs
+ (Pattern (Pattern'First .. Pattern'Last - 3),
+ True, Rank, Location);
+ end if;
+ else
+ Check_Directory_And_Subdirs (Pattern, False, Rank, Location);
+ end if;
+ end Find_Pattern;
+
+ -- Start of processing for Expand_Subdirectory_Pattern
+
+ Pattern_Id : String_List_Id := Patterns;
+ Element : String_Element;
+ Rank : Natural := 1;
+ begin
+ while Pattern_Id /= Nil_String loop
+ Element := Data.Tree.String_Elements.Table (Pattern_Id);
+ Find_Pattern
+ (Get_Name_String (Element.Value), Rank, Element.Location);
+ Rank := Rank + 1;
+ Pattern_Id := Element.Next;
+ end loop;
+
+ Recursive_Dirs.Reset (Visited);
+ end Expand_Subdirectory_Pattern;
+
------------------------
-- Search_Directories --
------------------------
Data : in out Tree_Processing_Data)
is
Object_Files : Object_File_Names_Htable.Instance;
- Iter : Source_Iterator;
- Src : Source_Id;
+ 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,
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 tabes that were created when a
+ -- source info fie 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 --
------------------
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
+ (Ada.Directories.Simple_Name
+ (Get_Name_String (Src.Path_Name)));
+ Id.File := Name_Find;
+
+ Name_Len := 0;
+ Add_Str_To_Name_Buffer
+ (Ada.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;
+
+ Files_Htable.Set (Data.File_To_Source, Id.File, Id);
+
+ Next (Iter);
+ end loop;
+ end Get_Sources_From_Source_Info;
+
-- Start of processing for Look_For_Sources
begin
- Find_Excluded_Sources (Project, Data);
+ if Data.Tree.Source_Info_File_Exists then
+ Get_Sources_From_Source_Info;
- if Project.Project.Languages /= No_Language_Index then
- Load_Naming_Exceptions (Project, Data);
- Find_Sources (Project, Data);
- Mark_Excluded_Sources;
- Check_Object_Files;
- end if;
+ 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);
+ Object_File_Names_Htable.Reset (Object_Files);
+ end if;
end Look_For_Sources;
------------------
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 Recursive_Check
-- Start of processing for Process_Naming_Scheme
begin
Lib_Data_Table.Init;
- Initialize (Data, Tree => Tree, Flags => Flags);
+ Initialize (Data, Tree => Tree, Node_Tree => Node_Tree, Flags => Flags);
Check_All_Projects (Root_Project, Data, Imported_First => True);
Free (Data);