Patchwork [Ada] New generic routine to iterate through interface sources

login
register
mail settings
Submitter Arnaud Charlet
Date July 9, 2012, 10:48 a.m.
Message ID <20120709104804.GA32399@adacore.com>
Download mbox | patch
Permalink /patch/169773/
State New
Headers show

Comments

Arnaud Charlet - July 9, 2012, 10:48 a.m.
This new routine interfaces through all sources needed to interface
to a library. All the specs are handled and also the bodies when
needed (if there is a pragma inline of the spec is generic for
example).

Tested on x86_64-pc-linux-gnu, committed on trunk

2012-07-09  Pascal Obry  <obry@adacore.com>

	* prj-util.adb, prj-util.ads (For_Interface_Sources): New routine.

Patch

Index: prj-util.adb
===================================================================
--- prj-util.adb	(revision 189366)
+++ prj-util.adb	(working copy)
@@ -6,7 +6,7 @@ 
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 2001-2011, Free Software Foundation, Inc.         --
+--          Copyright (C) 2001-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- --
@@ -23,11 +23,14 @@ 
 --                                                                          --
 ------------------------------------------------------------------------------
 
+with Ada.Containers.Indefinite_Ordered_Sets;
+with Ada.Directories;
 with Ada.Unchecked_Deallocation;
 
 with GNAT.Case_Util; use GNAT.Case_Util;
 with GNAT.Regexp;    use GNAT.Regexp;
 
+with ALI;      use ALI;
 with Osint;    use Osint;
 with Output;   use Output;
 with Opt;
@@ -390,6 +393,143 @@ 
       return Add_Suffix (Name_Find);
    end Executable_Of;
 
+   ---------------------------
+   -- For_Interface_Sources --
+   ---------------------------
+
+   procedure For_Interface_Sources
+     (Tree : Project_Tree_Ref; Project : Project_Id)
+   is
+      use Ada;
+      use type Ada.Containers.Count_Type;
+
+      package Dep_Names is new Containers.Indefinite_Ordered_Sets (String);
+
+      function Load_ALI (Filename : String) return ALI_Id;
+      --  Load an ALI file and returns its id
+
+      --------------
+      -- Load_ALI --
+      --------------
+
+      function Load_ALI (Filename : String) return ALI_Id is
+         Result   : ALI_Id := No_ALI_Id;
+         Text     : Text_Buffer_Ptr;
+         Lib_File : File_Name_Type;
+      begin
+         if Directories.Exists (Filename) then
+            Name_Len := 0;
+            Add_Str_To_Name_Buffer (Filename);
+            Lib_File := Name_Find;
+            Text := Osint.Read_Library_Info (Lib_File);
+            Result :=
+              ALI.Scan_ALI
+                (Lib_File,
+                 Text,
+                 Ignore_ED  => False,
+                 Err        => True,
+                 Read_Lines => "UD");
+            Free (Text);
+         end if;
+
+         return Result;
+      end Load_ALI;
+
+      Iter : Source_Iterator := For_Each_Source (Tree, Project);
+      Sid  : Source_Id;
+      ALI  : ALI_Id;
+
+      First_Unit  : Unit_Id;
+      Second_Unit : Unit_Id;
+      Body_Needed : Boolean;
+      Deps        : Dep_Names.Set;
+
+   begin
+      --  First look at all the spec, check if the body is needed
+
+      loop
+         Sid := Element (Iter);
+         exit when Sid = No_Source;
+
+         --  Skip sources that are removed/excluded and sources not part of
+         --  the interface for standalone libraries.
+
+         if Sid.Kind = Spec
+           and then not Sid.Locally_Removed
+           and then (Project.Standalone_Library = No
+                     or else Sid.Declared_In_Interfaces)
+         then
+            Action (Sid);
+
+            --  Check ALI for dependencies on body and sep
+
+            ALI := Load_ALI
+              (Get_Name_String (Get_Object_Directory (Sid.Project, True))
+               & Get_Name_String (Sid.Dep_Name));
+
+            if ALI /= No_ALI_Id then
+               First_Unit := ALIs.Table (ALI).First_Unit;
+               Second_Unit := No_Unit_Id;
+               Body_Needed := True;
+
+               --  If there is both a spec and a body, check if they are both
+               --  needed.
+
+               if Units.Table (First_Unit).Utype = Is_Body then
+                  Second_Unit := ALIs.Table (ALI).Last_Unit;
+
+                  --  If the body is not needed, then reset First_Unit
+
+                  if not Units.Table (Second_Unit).Body_Needed_For_SAL then
+                     Body_Needed := False;
+                  end if;
+
+               elsif Units.Table (First_Unit).Utype = Is_Spec_Only then
+                  Body_Needed := False;
+               end if;
+
+               --  Handle all the separates, if any
+
+               if Body_Needed then
+                  if Other_Part (Sid) /= null then
+                     Deps.Include (Get_Name_String (Other_Part (Sid).File));
+                  end if;
+
+                  for Dep in ALIs.Table (ALI).First_Sdep ..
+                    ALIs.Table (ALI).Last_Sdep
+                  loop
+                     if Sdep.Table (Dep).Subunit_Name /= No_Name then
+                        Deps.Include
+                          (Get_Name_String (Sdep.Table (Dep).Sfile));
+                     end if;
+                  end loop;
+               end if;
+            end if;
+         end if;
+
+         Next (Iter);
+      end loop;
+
+      --  Now handle the bodies and separates if needed
+
+      if Deps.Length /= 0 then
+         Iter := For_Each_Source (Tree, Project);
+
+         loop
+            Sid := Element (Iter);
+            exit when Sid = No_Source;
+
+            if Sid.Kind /= Spec
+              and then Deps.Contains (Get_Name_String (Sid.File))
+            then
+               Action (Sid);
+            end if;
+
+            Next (Iter);
+         end loop;
+      end if;
+   end For_Interface_Sources;
+
    --------------
    -- Get_Line --
    --------------
Index: prj-util.ads
===================================================================
--- prj-util.ads	(revision 189369)
+++ prj-util.ads	(working copy)
@@ -233,6 +233,17 @@ 
    procedure Next (Iter : in out Source_Info_Iterator);
    --  Advance the iterator to the next source in the project
 
+   generic
+      with procedure Action (Source : Source_Id);
+   procedure For_Interface_Sources
+     (Tree : Project_Tree_Ref; Project : Project_Id);
+   --  Call Action for every sources that are needed to use Project. This
+   --  is either the sources corresponding to the unit in the Interfaces
+   --  attributes or all sources of the project. Note that only the body
+   --  needed (because the unit if generic or contains some inline pragmas)
+   --  are handled. This routine must be called only when the project as
+   --  sucessfully been built.
+
 private
    type Text_File_Data is record
       FD                  : File_Descriptor := Invalid_FD;