-- -- Copyright (C) 2019-2024, AdaCore -- -- SPDX-License-Identifier: Apache-2.0 WITH LLVM-Exception -- with Ada.Finalization; with Ada.Iterator_Interfaces; with GPR2.Build.Compilation_Unit; with GPR2.Build.Tree_Db; with GPR2.Build.View_Db; with GPR2.Containers; with GPR2.Context; with GPR2.File_Readers; with GPR2.KB; with GPR2.Log; with GPR2.Options; with GPR2.Path_Name; with GPR2.Path_Name.Set; with GPR2.Project.Configuration; limited with GPR2.Project.Tree.View_Builder; with GPR2.Project.View.Set; with GPR2.Project.View.Vector; with GPR2.View_Ids; private with GNATCOLL.Refcount; private with GPR2.Tree_Internal; private with GPR2.View_Internal; package GPR2.Project.Tree is use type GPR2.Context.Object; type Verbosity_Level is (Quiet, Minimal, Errors, Warnings_And_Errors, Info, Linter); -- Quiet: do not display anything -- Minimal: display only messages concerning new files or directories -- Warnings_And_Errors: in case the configuration or tree logs contain -- warnings or errors, display them -- Info: also display informational messages -- Linter: also display gpr linter messages Verbosity : Verbosity_Level := Warnings_And_Errors; -- Indicates the global verbosity expected by the user of this library. -- Logs will be displayed only if the verbosity level is verbose enough -- according to the message level (see GPR2.Message). -- The active message reporter is used to report such message, that will -- be displayed on the console by default (see GPR2.Message.Reporter). type Object is tagged private with Constant_Indexing => Constant_Reference, Default_Iterator => Iterate, Iterator_Element => View.Object; -- Note: the project tree object is actually a Refcounted object. -- This object is null by default, only a call to Load, -- Register_Project_Search_Path or Restrict_Autoconf_To_Languages will -- create the actual value. -- This means that if a copy of an instance of Object is done before the -- underlying value is created, the copy will remain null. -- This also means that after the initialisation of the object is done, -- copies become actually aliases, meaning that any change on one instance -- will modify all copies of it. Undefined : constant Object; -- This constant is equal to any object declared without an explicit -- initializer. function Is_Defined (Self : Object) return Boolean; -- Returns true if Self is defined overriding function "=" (Left, Right : Object) return Boolean; -- Returns True if Left and Right are the same tree procedure Create (Self : in out Object) with Post => Self.Is_Defined; -- Creates an empty tree structure procedure Register_Project_Search_Path (Self : in out Object; Dir : Path_Name.Object); -- Adds a project search path for this tree procedure Restrict_Autoconf_To_Languages (Self : in out Object; Langs : GPR2.Containers.Language_Set); -- Sets a list of languages that auto-configuration will be reduced to -- from the actual set of languages used in project tree. Empty set of -- languages means regular auto-configuration with no reductions. function Load (Self : in out Object; Options : GPR2.Options.Object'Class; With_Runtime : Boolean := False; Absent_Dir_Error : GPR2.Error_Level := GPR2.Warning; Allow_Implicit_Project : Boolean := True; Environment : GPR2.Environment.Object := GPR2.Environment.Process_Environment; Config : GPR2.Project.Configuration.Object := GPR2.Project.Configuration.Undefined; Check_Shared_Libs_Import : Boolean := False; File_Reader : GPR2.File_Readers.File_Reader_Reference := GPR2.File_Readers.No_File_Reader_Reference) return Boolean; -- Load a project tree using configured options, and report the warning -- and errors if any. The verbosity level of such report can be adjusted -- by setting GPR2.Project.Tree.Verbosity to the desired level. If -- non-console output is desired, the default reporter can be changed -- in GPR2.Messages.Reporter. -- -- Self: the tree to load -- Options: the options to use to load the tree. See below to see how -- the options are checked. -- With_Runtime: whether the runtime sources are looked for when updating -- the sources. -- Absent_Dir_Error: whether a missing directory should be treated as an -- error or a warning. -- Allow_Implicit_Project: if set and no project is specified in the -- load options, or the project designates a directory, and then only -- one project file is present in current directory (or the designated -- directory), then it is loaded. -- Environment allows passing explictely environment variables to the -- tree. -- Config allows passing explictely the configuration project. If defined -- then options --config or --autoconf are ignored. -- Check_Shared_Libs_Import: when set, libgpr2 will check for shared -- library projects importing static libraries and will report an error. -- This prevents having a static library being imported both on the -- application side and by the shared library and thus ending up with -- duplicated global states for this static library. -- File_Reader: if set, this file reader is used instead of the standard -- text file reader to load the projects. -- -- raises GPR2.Options.Usage_Error in case the set of Options given as -- parameter is invalid, The reason for the failure is given in the -- exception message. function Load_Virtual_View (Self : in out Object; Root_Project : View_Builder.Object; Options : GPR2.Options.Object'Class; With_Runtime : Boolean := False; Absent_Dir_Error : GPR2.Error_Level := GPR2.Warning; Environment : GPR2.Environment.Object := GPR2.Environment.Process_Environment; Config : GPR2.Project.Configuration.Object := GPR2.Project.Configuration.Undefined; File_Reader : GPR2.File_Readers.File_Reader_Reference := GPR2.File_Readers.No_File_Reader_Reference) return Boolean; -- Same as above, but uses a virtual project view as a root project. -- -P option is ignored if set in Options. procedure Unload (Self : in out Object); -- Clears the internal structure of the Object function Root_Project (Self : Object) return View.Object with Pre => Self.Is_Defined; -- Returns the root project for the given tree. function Namespace_Root_Projects (Self : Object) return View.Set.Object with Pre => Self.Is_Defined; -- Returns the list of namespace root projects: either the root project -- for regular trees, or the root of the subtrees for an aggregate project. function Has_Configuration (Self : Object) return Boolean with Pre => Self.Is_Defined; -- Returns True if a configuration project is loaded on this tree function Configuration (Self : Object) return Configuration.Object with Pre => Self.Is_Defined and then Self.Has_Configuration; -- Returns the configuration project for the given tree function Has_Runtime_Project (Self : Object) return Boolean with Pre => Self.Is_Defined; -- Returns True if a runtime project is loaded on this tree function Runtime_Project (Self : Object) return View.Object with Pre => Self.Is_Defined; -- Returns the runtime project for the given tree function Runtime_Requested (Self : Object) return Boolean with Pre => Self.Is_Defined; -- Returns whether With_Runtime was set while loading the tree function Languages (Self : Object) return Containers.Language_Set with Pre => Self.Is_Defined; -- Returns the list of all the languages used in the loaded tree function Target (Self : Object; Canonical : Boolean := False) return Name_Type with Pre => Self.Is_Defined; -- Returns the target for the project tree function Runtime (Self : Object; Language : Language_Id) return Optional_Name_Type with Pre => Self.Is_Defined; -- Returns the runtime selected for the given language or the empty string -- if no specific runtime has been configured for this project tree. function Artifacts_Dir (Self : Object) return Path_Name.Object with Pre => Self.Is_Defined; -- Tries to return a directory that can be used to store artifacts that -- are global to the tree. -- This returns the object directory of the root view if available, else -- it returns the root view's project directory. -- **Important note** project directories may not be writable, as only -- object dirs are required to have read/write access. So this function -- needs to be used with care. function Ordered_Views (Self : Object) return View.Vector.Object with Pre => Self.Is_Defined; function Has_Messages (Self : Object) return Boolean; -- Returns whether some messages are present for this project tree function Log_Messages (Self : Object) return not null access Log.Object with Pre => Self.Is_Defined, Post => not Self.Has_Messages or else not Log_Messages'Result.Is_Empty; -- Returns the Logs, this contains information, warning and error messages -- found while handling the project. -- Context -- Note that the context of the project tree corresponds to the context of -- the root project view. function Has_Context (Self : Object) return Boolean with Pre => Self.Is_Defined; -- Returns True if the project tree has some context. If any of the project -- in the tree has some external variables then a context is present. A -- project without context is fully static as it does not reference any -- external (and so modifiable) variables. function Context (Self : Object) return Context.Object with Pre => Self.Is_Defined, Post => Self.Has_Context = (Context'Result /= GPR2.Context.Empty); -- Returns the Context for the given project tree function Set_Context (Self : in out Object; Context : GPR2.Context.Object; Changed : access procedure (Project : View.Object) := null) return Boolean with Pre => Self.Is_Defined; -- Sets the context for the project tree. The callback Changed is called -- for any project view which is impacted by this change of context, i.e. -- if the project view references directly or indirectly an external -- variable. -- If the new context generate an error while re-loading the project tree -- then False is returned. -- Iterator type Cursor is private; No_Element : constant Cursor; function Element (Position : Cursor) return View.Object with Post => (if Has_Element (Position) then Element'Result.Is_Defined else not Element'Result.Is_Defined); function Has_Element (Position : Cursor) return Boolean; package Project_Iterator is new Ada.Iterator_Interfaces (Cursor, Has_Element); function Is_Root (Position : Cursor) return Boolean; -- Returns True if the cursor is pointing to the root project function Constant_Reference (Self : aliased Object; Position : Cursor) return View.Object with Pre => Self.Is_Defined and then Position /= No_Element; function Iterate (Self : Object; Kind : Project.Iterator_Control := Project.Default_Iterator; Filter : Project.Filter_Control := Project.Default_Filter; Status : Project.Status_Control := Project.Default_Status) return Project_Iterator.Forward_Iterator'Class with Pre => Self.Is_Defined; -- Iterates over all project views in the tree given the iterator kind -- (only the project with or without imports) and the filter which can be -- used to iterate over only some specific projects (only the library -- projects for example). -- Views -- Artifacts database function Artifacts_Database (Self : Object) return Build.Tree_Db.Object_Access with Pre => Self.Is_Defined; function Has_Artifacts_Database (Self : Object) return Boolean with Pre => Self.Is_Defined; function Artifacts_Database (Self : Object; View : GPR2.Project.View.Object) return Build.View_Db.Object with Pre => Self.Is_Defined and then View.Kind in With_Object_Dir_Kind, Inline; function Artifacts_Database (Self : Object; View : GPR2.View_Ids.View_Id) return Build.View_Db.Object with Pre => Self.Is_Defined, Inline; function Source_Option (Self : Object) return Optional_Source_Info_Option; -- Retrieve the level of source information currently requested for -- the tree database. procedure Clear_Sources (Self : Object; View : Project.View.Object := Project.View.Undefined) with Pre => Self.Is_Defined, Post => (if not View.Is_Defined then Self.Source_Option = No_Source); -- Invalidates the sources for all views in the tree if View is undefined -- or the source in the given view otherwise. This is needed when some -- sources are added or removed from the view. It is not required to call -- Update_Sources below, when the routine Sources on one of the views of -- the tree will be called, the set of sources will be recomputed. procedure Update_Sources (Self : Object; Option : Source_Info_Option := Sources_Units) with Pre => Self.Is_Defined; -- Ensures that all views' sources are up-to-date. -- Option selects the information that will be gathered on the sources. The -- more information is requested, the slower is the update operation. function Update_Sources (Self : Object; Option : Source_Info_Option := Sources_Units) return Boolean with Pre => Self.Is_Defined; -- Same as above, and returns False upon error detected. procedure Update_Sources (Self : Object; Messages : out GPR2.Log.Object; Option : Source_Info_Option := Sources_Units) with Pre => Self.Is_Defined; -- Same as above and returns the messages generated during the load -- operation. procedure For_Each_Ada_Closure (Self : Object; Action : access procedure (Unit : Build.Compilation_Unit.Object); Mains : Containers.Filename_Set := Containers.Empty_Filename_Set; All_Sources : Boolean := False; Root_Project_Only : Boolean := False; Externally_Built : Boolean := False) with Pre => Self.Is_Defined and then Self.Source_Option >= Sources_Units; -- Call action for each source of the closure of the loaded tree (Mains -- or library interfaces and their dependencies). --. -- Mains: -- used to limit the entry points of the closure to the sources or -- units specified in this parameter -- All_Sources (-U command line option): -- process also sources that are not in Main -- Root_Project_Only (--no-subproject command line option): -- will return only sources from the root project. -- Externally_Built: -- if not set, units defined in externally built views will be ignored. -- -- Note that if Root_Project_Only is set and the root project is an -- aggregate project, then the closure is considered empty -- -- Raises Usage_Error when Mains is specified and All_Sources is set. function Project_Search_Paths (Self : Object) return Path_Name.Set.Object with Pre => Self.Is_Defined; -- Returns the Tree project search paths function Subdirs (Self : Object) return Filename_Optional with Pre => Self.Is_Defined; -- Returns the subdirs parameter of the project tree such that, for -- each project, the actual {executable,object,library} directories are -- {,,}/. function Has_Src_Subdirs (Self : Object) return Boolean with Pre => Self.Is_Defined; -- Returns True if the Src_Subdirs has been defined function Src_Subdirs (Self : Object) return Filename_Optional with Pre => Self.Is_Defined and then Self.Has_Src_Subdirs; -- Returns the src_subdirs parameter of the project tree such that, -- for each project, the actual source directories list will be prepended -- with {object_dir}/. function Build_Path (Self : Object) return Path_Name.Object with Pre => Self.Is_Defined; -- Path to build tree function Find_Project (Self : Object; Base_Name : Simple_Name) return Path_Name.Object with Pre => Self.Is_Defined; -- Search for the project file named "Base_Name" through the tree's -- hierarchy or the project paths. If not found, Path_Name.Undefined is -- returned Target_Name : constant Name_Type; -- Native host target function Get_View (Self : Object; Id : GPR2.View_Ids.View_Id) return Project.View.Object; -- Given a View_Id Id returns the associated view if it exists. Returns -- Project.View.Undefined otherwise. function Get_KB (Self : Object) return GPR2.KB.Object with Pre => Self.Is_Defined; private Get_View_Data : access function (Public : GPR2.Project.Tree.View_Builder.Object) return GPR2.View_Internal.Data; package Pools is new GNATCOLL.Refcount.Headers.Typed (Tree_Internal.Object); subtype Tree_Internal_Access is Pools.Element_Access; use type Pools.Element_Access; type Object is new Ada.Finalization.Controlled with record Tree : Tree_Internal_Access; end record; pragma Finalize_Storage_Only (Object); overriding procedure Adjust (Self : in out Object); overriding procedure Finalize (Self : in out Object); Undefined : constant Object := (Ada.Finalization.Controlled with others => <>); overriding function "=" (Left, Right : Object) return Boolean is (Left.Tree = Right.Tree); type Cursor is record Internal : Tree_Internal.Cursor; end record; No_Element : constant Cursor := (Internal => Tree_Internal.No_Element); Target_Name : constant Name_Type := Tree_Internal.Target_Name; function Is_Defined (Self : Object) return Boolean is (Self /= Undefined); function Subdirs (Self : Object) return Filename_Optional is (Self.Tree.Subdirs); function Has_Src_Subdirs (Self : Object) return Boolean is (Self.Tree.Has_Src_Subdirs); function Src_Subdirs (Self : Object) return Filename_Optional is (Self.Tree.Src_Subdirs); function Build_Path (Self : Object) return Path_Name.Object is (Self.Tree.Build_Path); function Has_Artifacts_Database (Self : Object) return Boolean is (Self.Tree.Has_Artifacts_Database); function Artifacts_Database (Self : Object) return Build.Tree_Db.Object_Access is (Self.Tree.Artifacts_Database); function Artifacts_Database (Self : Object; View : GPR2.Project.View.Object) return Build.View_Db.Object is (Self.Tree.Artifacts_Database (View)); function Artifacts_Database (Self : Object; View : GPR2.View_Ids.View_Id) return Build.View_Db.Object is (Self.Tree.Artifacts_Database (View)); function Source_Option (Self : Object) return Optional_Source_Info_Option is (Self.Tree.Source_Option); function Namespace_Root_Projects (Self : Object) return View.Set.Object is (Self.Tree.Namespace_Root_Projects); function Root_Project (Self : Object) return View.Object is (Self.Tree.Root_Project); function Has_Configuration (Self : Object) return Boolean is (Self.Tree.Has_Configuration); function Configuration (Self : Object) return Project.Configuration.Object is (Self.Tree.Configuration); function Has_Runtime_Project (Self : Object) return Boolean is (Self.Tree.Has_Runtime_Project); function Runtime_Project (Self : Object) return View.Object is (Self.Tree.Runtime_Project); function Runtime_Requested (Self : Object) return Boolean is (Self.Tree.With_Runtime); function Target (Self : Object; Canonical : Boolean := False) return Name_Type is (Self.Tree.Target (Canonical)); function Runtime (Self : Object; Language : Language_Id) return Optional_Name_Type is (Self.Tree.Runtime (Language)); function Artifacts_Dir (Self : Object) return Path_Name.Object is (Self.Tree.Artifacts_Dir); function Ordered_Views (Self : Object) return View.Vector.Object is (Self.Tree.Ordered_Views); function Has_Messages (Self : Object) return Boolean is (Self.Is_Defined and then not Self.Tree.Log_Messages.Is_Empty); function Log_Messages (Self : Object) return not null access Log.Object is (Self.Tree.Log_Messages); function Has_Context (Self : Object) return Boolean is (Self.Tree.Has_Context); function Context (Self : Object) return GPR2.Context.Object is (Self.Tree.Context); function Project_Search_Paths (Self : Object) return Path_Name.Set.Object is (Self.Tree.Project_Search_Paths); function Find_Project (Self : Object; Base_Name : Simple_Name) return Path_Name.Object is (Self.Tree.Find_Project (Base_Name)); function Get_View (Self : Object; Id : GPR2.View_Ids.View_Id) return Project.View.Object is (Self.Tree.Get_View (Id)); function Get_KB (Self : Object) return GPR2.KB.Object is (Self.Tree.Get_KB); function Has_Element (Position : Cursor) return Boolean is (Tree_Internal.Has_Element (Position.Internal)); function Element (Position : Cursor) return View.Object is (Tree_Internal.Element (Position.Internal)); function Is_Root (Position : Cursor) return Boolean is (Tree_Internal.Is_Root (Position.Internal)); function Constant_Reference (Self : aliased Object; Position : Cursor) return View.Object is (Self.Tree.Constant_Reference (Position.Internal)); type Iterator is new Project_Iterator.Forward_Iterator with record Internal : GPR2.Tree_Internal.Iterator; end record; overriding function First (Iter : Iterator) return Cursor is (Cursor'(Internal => Iter.Internal.First)); overriding function Next (Iter : Iterator; Position : Cursor) return Cursor is (Cursor'(Internal => Iter.Internal.Next (Position.Internal))); function Iterate (Self : Object; Kind : Project.Iterator_Control := Project.Default_Iterator; Filter : Project.Filter_Control := Project.Default_Filter; Status : Project.Status_Control := Project.Default_Status) return Project_Iterator.Forward_Iterator'Class is (Iterator'(Internal => Tree_Internal.Iterator (Self.Tree.Iterate (Kind, Filter, Status)))); end GPR2.Project.Tree;