------------------------------------------------------------------------------
-- --
-- GPR TECHNOLOGY --
-- --
-- Copyright (C) 2011-2023, AdaCore --
-- --
-- This 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. This software is distributed in the hope that it will be useful, --
-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- --
-- TABILITY 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 COPYING. If not, --
-- see . --
-- --
------------------------------------------------------------------------------
with Ada.Calendar;
with Ada.Containers.Hashed_Maps;
with Ada.Containers.Ordered_Sets;
with Ada.Directories;
with Ada.Strings.Fixed;
with Ada.Text_IO; use Ada, Ada.Text_IO;
with GNAT.Case_Util; use GNAT.Case_Util;
with GNAT.Directory_Operations; use GNAT.Directory_Operations;
with GNAT.Dynamic_HTables;
with GNAT.MD5; use GNAT.MD5;
with GNAT.OS_Lib; use GNAT.OS_Lib;
with Gpr_Build_Util; use Gpr_Build_Util;
with Gprexch; use Gprexch;
with GPR.Env;
with GPR.Err; use GPR.Err;
with GPR.Names; use GPR.Names;
with GPR.Opt;
with GPR.Script; use GPR.Script;
with GPR.Snames; use GPR.Snames;
with GPR.Tempdir;
with GPR.Util; use GPR.Util;
package body Gprbuild.Post_Compile is
type Lang_Names is array (Positive range <>) of Language_Ptr;
type Lang_Names_Ptr is access Lang_Names;
Langs : Lang_Names_Ptr := new Lang_Names (1 .. 4);
Last_Lang : Natural := 0;
Libs_Are_Building : Name_Id_Set.Set;
-- Libraries currently being built
package FNHS is new GNAT.Dynamic_HTables.Simple_HTable
(Header_Num => GPR.Header_Num,
Element => Boolean,
No_Element => False,
Key => File_Name_Type,
Hash => GPR.Hash,
Equal => "=");
procedure Build_Library
(For_Project : Project_Id;
Project_Tree : Project_Tree_Ref;
No_Create : Boolean);
-- Build, if necessary, the library of a library project. If No_Create
-- is True then the actual static or shared library is not built, yet
-- the exchange file with dependencies is created.
procedure Emit_Compiler_Switches
(Exchange_File : Text_IO.File_Type; Index : Name_List_Index);
-- Helper subprogram to emit and filter compiler switches given by
-- Index, one per line in the givenfile Exchange_File.
procedure Post_Compilation_Phase
(Main_Project : Project_Id; Project_Tree : Project_Tree_Ref);
function Is_Included_In_Global_Archive
(Object_Name : File_Name_Type;
Project : Project_Id) return Boolean;
-- Return True if the object Object_Name is not overridden by a source
-- in a project extending project Project.
procedure Wait_For_Slots_Less_Than (Count : Positive);
-- Wait for the number of available process slots less then Count
type Library_Object is record
Path : Path_Name_Type;
TS : Time_Stamp_Type;
Known : Boolean;
end record;
function "<" (Left, Right : Library_Object) return Boolean
is (Get_Name_String (Left.Path) < Get_Name_String (Right.Path));
-- Operator uses for the ordered set Library_Objs in procedure
-- Build_Library. Left < Right if Left path as a string is before
-- Right path in alphabetical order.
-- Dependency Files
type Dep_Name;
type Dep_Ptr is access Dep_Name;
type Dep_Name is record
Name : String_Access;
Next : Dep_Ptr;
end record;
First_Dep : Dep_Ptr;
-- Head of the list of dependency file path names
procedure Add_Dep (Name : String);
-- Insert a dependency file path name in the list starting at First_Dep,
-- at the right place so that the list is sorted.
----------------
-- Add_Dep --
----------------
procedure Add_Dep (Name : String) is
Next : Dep_Ptr := First_Dep;
begin
if Next = null or else Name < Next.Name.all then
First_Dep := new Dep_Name'(new String'(Name), Next);
else
while Next.Next /= null and then
Name > Next.Next.Name.all
loop
Next := Next.Next;
end loop;
Next.Next := new Dep_Name'(new String'(Name), Next.Next);
end if;
end Add_Dep;
-------------------
-- Build_Library --
-------------------
procedure Build_Library
(For_Project : Project_Id;
Project_Tree : Project_Tree_Ref;
No_Create : Boolean)
is
package Objects is new Containers.Ordered_Sets (Library_Object);
Library_Objs : Objects.Set;
-- Objects that are in the library file with their time stamps, ordered
-- by increasing path names.
Library_SAL_Projs : Project_Vectors.Vector;
-- List of non extended projects that are part of a Stand-Alone
-- (aggregate) library project.
Library_Sources : Source_Vectors.Vector;
-- Library Ada sources of Stand-Alone library, that is sources of the
-- project in the closure of the interface.
Complete_Interface_ALIs : FNHS.Instance;
-- The ALI files in the complete interface set
Expected_File_Name : String_Access;
-- Expected library file name
Mapping_Path : Path_Name_Type := No_Path;
-- The path name of an eventual binder mapping file
Mapping_FD : File_Descriptor := Invalid_FD;
-- A File Descriptor for an eventual binder mapping file
Library_Options_Success : Boolean := False;
package Lang_Set renames GPR.Name_Id_Set;
procedure Get_Objects;
-- Get the paths of the object files of the library in ordered set
-- Library_Objs.
procedure Write_List (Label : Library_Section; List : String_List_Id);
-- Write values in list into section Label in the given file. Ouptut
-- Label is written first if it is not the current section.
procedure Write_Name_List
(Label : Library_Section; List : Name_List_Index);
-- Write name list values into the Exchange_File, output Label first.
-- Output Label is written first if it is not the current section.
procedure Write_Name (Label : Library_Section; Name : Name_Id);
-- Write name with label if Name /= No_Name
procedure Write_Filename
(Label : Library_Section; Filename : File_Name_Type);
-- Write Filename with label if Filename /= No_File
procedure Check_Section (Section : Library_Section);
-- Check that current exchange file output section is Section and set it
-- if not.
-- Procedures to write specific sections of the exchange file
procedure Write_Object_Files;
procedure Write_Object_Directory;
procedure Write_Compilers;
procedure Write_Compiler_Leading_Switches;
procedure Write_Compiler_Trailing_Switches;
procedure Write_Partial_Linker;
procedure Write_Shared_Lib_Minimum_Options;
procedure Write_Library_Version;
procedure Write_Runtime_Library_Dir;
procedure Write_Auto_Init;
procedure Write_Binding_Options;
procedure Write_Run_Path_Option;
procedure Write_Leading_Library_Options;
procedure Write_Library_Options (Success : out Boolean);
procedure Write_Library_Rpath_Options;
procedure Write_Imported_Libraries;
procedure Write_Dependency_Files;
procedure Write_Toolchain_Version;
procedure Write_Interface_Dep_Files;
procedure Write_Other_Interfaces;
procedure Write_Interface_Obj_Files;
procedure Write_Sources;
procedure Write_Response_Files;
procedure Write_Mapping_File;
procedure Wait_For_Dependency (P : Project_Id);
-- Wait for dependent library project P build completed
function In_Library_SAL_Projs (Src : Source_Id) return Boolean is
(Library_SAL_Projs.Contains
(Ultimate_Extending_Project_Of (Src.Project)));
-- Returns True of Src.Project founder is in the Library_SAL_Projs
Project_Name : constant String :=
Get_Name_String (For_Project.Name);
Current_Dir : constant String := Get_Current_Dir;
Exchange_File : Text_IO.File_Type;
Exchange_File_Name : String_Access;
Latest_Object_TS : Time_Stamp_Type := Empty_Time_Stamp;
Library_Builder_Name : String_Access;
Library_Builder : String_Access;
Library_Needs_To_Be_Built : Boolean := False;
Dependencies_Ready : Boolean := False;
Object_Path : Path_Name_Type;
Object_TS : Time_Stamp_Type;
Source : Source_Id;
Project : Project_Id;
Disregard : Boolean;
Path_Found : Boolean;
Iter : Source_Iterator;
Current_Section : Library_Section := No_Library_Section;
-------------------
-- Check_Section --
-------------------
procedure Check_Section (Section : Library_Section) is
begin
if Current_Section /= Section then
Current_Section := Section;
Put_Line (Exchange_File, Library_Label (Section));
end if;
end Check_Section;
-----------------
-- Get_Objects --
-----------------
procedure Get_Objects is
Library_ALIs : FNHS.Instance;
-- The ALI files of the Stand-Alone Library project
Processed_ALIs : FNHS.Instance;
-- The ALI files that have been processed to check if the
-- corresponding library unit is in the interface set.
Never : constant Time_Stamp_Type := (others => '9');
-- A time stamp that is greater than any real one
procedure Check_Latest_Object_TS (Source : Source_Id);
-- Check if source object timestamp later than in Latest_Object_TS
-- and update it if this is the case. If object is absent, set the
-- Latest_Object_TS to Never and set Library_Needs_To_Be_Built to
-- True.
procedure Check_Interface
(Proj : Project_Id;
Tree : Project_Tree_Ref);
-- Check if the interface of SAL project Proj is complete
procedure Find_ALI_Path
(The_ALI : File_Name_Type;
ALI_Path : in out Path_Name_Type;
Proj : Project_Id;
Tree : Project_Tree_Ref);
-- Find the path of the ALI file The_ALI. It may be in project
-- Proj, or if Proj is an aggregate library in one of its aggregated
-- projects.
procedure Get_Roots (Source : Source_Id);
-- Get Roots of the SAL Source into object or ALI containers
procedure Process
(Proj : Project_Id;
Tree : Project_Tree_Ref);
-- Get objects for non Stand-Alone library
procedure Process_ALI
(The_ALI : File_Name_Type;
Proj : Project_Id;
Tree : Project_Tree_Ref);
-- Check if the closure of a library unit which is or should be in
-- the interface set is also in the interface set. Issue a warning
-- for each missing library unit.
procedure Process_Standalone
(Proj : Project_Id;
Tree : Project_Tree_Ref);
-- Get objects for a Stand-Alone Library
procedure Get_Closure;
-- For Stand-Alone libraries, get the closure of the Ada interface
-- and put the object files in Library_Objs.
----------------------------
-- Check_Latest_Object_TS --
----------------------------
procedure Check_Latest_Object_TS (Source : Source_Id) is
begin
if Source.Object_TS = Empty_Time_Stamp then
Latest_Object_TS := Never;
if not Library_Needs_To_Be_Built then
Library_Needs_To_Be_Built := True;
if Opt.Verbosity_Level > Opt.Low then
Put (" -> missing object file: ");
Put_Line (Get_Name_String (Source.Object));
end if;
end if;
elsif Source.Object_TS > Latest_Object_TS then
Latest_Object_TS := Source.Object_TS;
end if;
end Check_Latest_Object_TS;
-------------
-- Process --
-------------
procedure Process
(Proj : Project_Id;
Tree : Project_Tree_Ref)
is
pragma Unreferenced (Tree);
Source : Source_Id;
Iter : Source_Iterator;
begin
Iter := For_Each_Source (Project_Tree, Proj);
loop
Source := GPR.Element (Iter);
exit when Source = No_Source;
-- Always get the time stamps when the main project is an
-- aggregate project.
Initialize_Source_Record
(Source, Always => Main_Project.Qualifier = Aggregate);
if Is_Compilable (Source)
and then Source.Replaced_By = No_Source
and then Source.Language.Config.Objects_Linked
and then
((Source.Unit = No_Unit_Index
and then Source.Kind = Impl)
or else
(Source.Unit /= No_Unit_Index
and then (Source.Kind = Impl
or else Other_Part (Source) = No_Source)
and then not Is_Subunit (Source)))
and then
(not Source.Project.Externally_Built
or else not For_Project.Externally_Built
or else Source.Project.Extended_By /= No_Project)
then
Library_Objs.Insert
((Path => Source.Object_Path,
TS => Source.Object_TS,
Known => False));
Check_Latest_Object_TS (Source);
end if;
Next (Iter);
end loop;
end Process;
-------------------
-- Find_ALI_Path --
-------------------
procedure Find_ALI_Path
(The_ALI : File_Name_Type;
ALI_Path : in out Path_Name_Type;
Proj : Project_Id;
Tree : Project_Tree_Ref)
is
Source : Source_Id;
Iter : Source_Iterator;
Aggr_Projs : Aggregated_Project_List;
Prj : Project_Id := Proj;
begin
while Prj /= No_Project loop
Iter := For_Each_Source (Tree, Prj);
loop
Source := GPR.Element (Iter);
exit when Source = No_Source;
Initialize_Source_Record (Source);
if Source.Dep_Name = The_ALI then
ALI_Path := Source.Dep_Path;
return;
end if;
Next (Iter);
end loop;
Prj := Prj.Extends;
end loop;
if Proj.Qualifier = Aggregate_Library then
Aggr_Projs := Proj.Aggregated_Projects;
while Aggr_Projs /= null loop
Find_ALI_Path
(The_ALI, ALI_Path, Aggr_Projs.Project, Aggr_Projs.Tree);
exit when ALI_Path /= No_Path;
Aggr_Projs := Aggr_Projs.Next;
end loop;
end if;
end Find_ALI_Path;
-----------------
-- Process_ALI --
-----------------
Interface_Incomplete : Boolean := False;
procedure Process_ALI
(The_ALI : File_Name_Type;
Proj : Project_Id;
Tree : Project_Tree_Ref)
is
use ALI;
Text : Text_Buffer_Ptr;
Idread : ALI_Id;
First_Unit : Unit_Id;
Last_Unit : ALI.Unit_Id;
Unit_Data : ALI.Unit_Record;
Afile : File_Name_Type;
ALI_Path : Path_Name_Type;
begin
-- Nothing to do if the ALI file has already been processed.
-- This happens if an interface imports another interface.
if not FNHS.Get (Processed_ALIs, The_ALI) then
FNHS.Set (Processed_ALIs, The_ALI, True);
ALI_Path := No_Path;
Find_ALI_Path (The_ALI, ALI_Path, Proj, Tree);
if ALI_Path /= No_Path then
Text := Read_Library_Info (File_Name_Type (ALI_Path));
end if;
if Text /= null then
Idread :=
Scan_ALI
(F => The_ALI,
T => Text,
Ignore_ED => False,
Err => True,
Read_Lines => "W");
Free (Text);
if Idread /= No_ALI_Id then
First_Unit := ALI.ALIs.Table (Idread).First_Unit;
Last_Unit := ALI.ALIs.Table (Idread).Last_Unit;
-- Process both unit (spec and body) if the body is
-- needed by the spec (inline or generic). Otherwise,
-- just process the spec.
if First_Unit /= Last_Unit and then
not ALI.Units.Table (Last_Unit).Body_Needed_For_SAL
then
First_Unit := Last_Unit;
end if;
for Unit in First_Unit .. Last_Unit loop
Unit_Data := ALI.Units.Table (Unit);
-- Check if each withed unit which is in the library
-- is also in the interface set, if it has not yet
-- been processed.
for W in Unit_Data.First_With ..
Unit_Data.Last_With
loop
Afile := Withs.Table (W).Afile;
if Afile /= No_File
and then FNHS.Get (Library_ALIs, Afile)
and then not FNHS.Get (Processed_ALIs, Afile)
then
if not FNHS.Get (Complete_Interface_ALIs, Afile)
then
if not Interface_Incomplete then
Put ("Warning: In library project """);
Get_Name_String (Proj.Name);
To_Mixed (Name_Buffer (1 .. Name_Len));
Put (Name_Buffer (1 .. Name_Len));
Put_Line ("""");
Interface_Incomplete := True;
end if;
Put (" Unit """);
Get_Name_String (Withs.Table (W).Uname);
To_Mixed (Name_Buffer (1 .. Name_Len - 2));
Put (Name_Buffer (1 .. Name_Len - 2));
Put_Line (""" is not in the interface set");
Put (" but it is needed by ");
case Unit_Data.Utype is
when Is_Spec => Put ("the spec of ");
when Is_Body => Put ("the body of ");
when others => null;
end case;
Put ('"');
Get_Name_String (Unit_Data.Uname);
To_Mixed (Name_Buffer (1 .. Name_Len - 2));
Put (Name_Buffer (1 .. Name_Len - 2));
Put_Line ("""");
FNHS.Set
(Complete_Interface_ALIs, Afile, True);
end if;
-- Now, process this unit
Process_ALI (Afile, Proj, Tree);
end if;
end loop;
end loop;
end if;
end if;
end if;
end Process_ALI;
------------------------
-- Process_Standalone --
------------------------
procedure Process_Standalone
(Proj : Project_Id;
Tree : Project_Tree_Ref)
is
pragma Unreferenced (Tree);
Source : Source_Id;
Iter : Source_Iterator;
List : String_List_Id;
Elem : String_Element;
OK : Boolean;
begin
if Proj.Qualifier /= Aggregate_Library
and then Proj.Extended_By = No_Project
then
Library_SAL_Projs.Append (Proj);
end if;
Iter := For_Each_Source (Project_Tree, Proj);
loop
Source := GPR.Element (Iter);
exit when Source = No_Source;
Initialize_Source_Record (Source);
if Is_Compilable (Source)
and then Source.Replaced_By = No_Source
and then Source.Language.Config.Objects_Linked
and then
((Source.Unit = No_Unit_Index
and then Source.Kind = Impl)
or else
(Source.Unit /= No_Unit_Index
and then (Source.Kind = Impl
or else Other_Part (Source) = No_Source)
and then not Is_Subunit (Source)))
and then
(not Source.Project.Externally_Built
or else not For_Project.Externally_Built
or else Source.Project.Extended_By /= No_Project)
then
if Source.Unit = No_Unit_Index then
OK := True;
Library_Objs.Insert
((Path => Source.Object_Path,
TS => Source.Object_TS,
Known => False));
Get_Roots (Source);
else
FNHS.Set (Library_ALIs, Source.Dep_Name, True);
-- Check if it is an interface and record if it is one
OK := False;
List := For_Project.Lib_Interface_ALIs;
while List /= Nil_String loop
Elem := Project_Tree.Shared.String_Elements.Table
(List);
-- Checking against Lib_Interface_ALIs will never
-- succeed if Source is in a multi-unit file because
-- Dep_Name will be in the format ~.ali
-- whereas the corresponding Elem will be .ali.
-- ??? Fix the computation of Lib_Interface_ALIs ???
-- As a quick fix we compare .
declare
use Ada.Strings.Fixed;
Dep_Str : constant String :=
Get_Name_String (Source.Dep_Name);
Elem_Str : constant String :=
Get_Name_String (Elem.Value);
Dep_Multi_Index : constant Natural :=
Index (Dep_Str, "~");
Elem_Dot_Index : constant Natural :=
Index (Elem_Str, ".");
begin
if Elem.Value = Name_Id (Source.Dep_Name)
or else
(Source.Index /= 0
and then Dep_Multi_Index = Elem_Dot_Index
and then Head (Dep_Str, Dep_Multi_Index - 1)
= Head (Elem_Str, Elem_Dot_Index - 1))
then
OK := True;
Library_Sources.Append (Source);
FNHS.Set
(Complete_Interface_ALIs, Source.Dep_Name,
True);
exit;
end if;
end;
List := Elem.Next;
end loop;
end if;
if OK then
Check_Latest_Object_TS (Source);
end if;
end if;
Next (Iter);
end loop;
end Process_Standalone;
---------------------
-- Check_Interface --
---------------------
procedure Check_Interface
(Proj : Project_Id;
Tree : Project_Tree_Ref)
is
Iface : String_List_Id := Proj.Lib_Interface_ALIs;
begin
while Iface /= Nil_String loop
Process_ALI
(File_Name_Type
(Tree.Shared.String_Elements.Table (Iface).Value),
Proj, Tree);
Iface := Tree.Shared.String_Elements.Table (Iface).Next;
end loop;
end Check_Interface;
-----------------
-- Get_Closure --
-----------------
procedure Get_Closure is
Index : Natural := 0;
The_ALI : ALI.ALI_Id;
Text : Text_Buffer_Ptr;
Dep_Path : Path_Name_Type;
Dep_TS : aliased File_Attributes := Unknown_Attributes;
Sfile : File_Name_Type;
Afile : File_Name_Type;
Src_Id : GPR.Source_Id;
Source : Source_Id;
procedure Add_To_Mapping
(Source : Source_Id; From_Object_Dir : Boolean);
-- Add data for Source in binder mapping file. Use the ALI file
-- in the library ALI directory if From_Object_Dir is False and
-- the project is a library project. Otherwise, use the ALI file
-- in the object directory.
--------------------
-- Add_To_Mapping --
--------------------
procedure Add_To_Mapping
(Source : Source_Id; From_Object_Dir : Boolean)
is
Unit : Unit_Index;
ALI_Unit : Unit_Name_Type := No_Unit_Name;
-- The unit name of an ALI file
ALI_Name : File_Name_Type := No_File;
-- The file name of the ALI file
ALI_Project : Project_Id := No_Project;
-- The project of the ALI file
begin
if Source = No_Source then
return;
end if;
Unit := Source.Unit;
if Source.Replaced_By /= No_Source
or else Unit = No_Unit_Index
or else Unit.Name = No_Name
then
ALI_Name := No_File;
-- If this is a body, put it in the mapping
elsif Source.Kind = Impl
and then Unit.File_Names (Impl) /= No_Source
and then Unit.File_Names (Impl).Project /= No_Project
then
Get_Name_String (Unit.Name);
Add_Str_To_Name_Buffer ("%b");
ALI_Unit := Name_Find;
ALI_Name :=
Lib_File_Name (Unit.File_Names (Impl).Display_File);
ALI_Project := Unit.File_Names (Impl).Project;
-- Otherwise, if this is a spec and there is no body, put it in
-- the mapping.
elsif Source.Kind = Spec
and then Unit.File_Names (Impl) = No_Source
and then Unit.File_Names (Spec) /= No_Source
and then Unit.File_Names (Spec).Project /= No_Project
then
Get_Name_String (Unit.Name);
Add_Str_To_Name_Buffer ("%s");
ALI_Unit := Name_Find;
ALI_Name :=
Lib_File_Name (Unit.File_Names (Spec).Display_File);
ALI_Project := Unit.File_Names (Spec).Project;
else
ALI_Name := No_File;
end if;
-- If we have something to put in the mapping then do it now.
-- If the project is extended, look for the ALI file in the
-- project, then in the extending projects in order, and use
-- the last one found.
if ALI_Name /= No_File then
-- Look in the project and the projects that are extending
-- it to find the real ALI
declare
ALI : constant String := Get_Name_String (ALI_Name);
ALI_Path : Name_Id := No_Name;
procedure Write_Mapping (Id : Name_Id);
-- Write name and line feed to Mapping_FD
----------------
-- Write_Name --
----------------
procedure Write_Mapping (Id : Name_Id) is
begin
Get_Name_String (Id);
Add_Char_To_Name_Buffer (ASCII.LF);
if Write (Mapping_FD, Name_Buffer'Address, Name_Len)
/= Name_Len
then
raise Program_Error with "Disk full";
end if;
end Write_Mapping;
begin
loop
-- For library projects, use the library ALI
-- directory, for other projects, use the
-- object directory.
if ALI_Project.Library and then not From_Object_Dir
then
Get_Name_String
(ALI_Project.Library_ALI_Dir.Display_Name);
else
Get_Name_String
(ALI_Project.Object_Directory.Display_Name);
end if;
Add_Str_To_Name_Buffer (ALI);
if Is_Regular_File (Name_Buffer (1 .. Name_Len)) then
ALI_Path := Name_Find;
end if;
ALI_Project := ALI_Project.Extended_By;
exit when ALI_Project = No_Project;
end loop;
if ALI_Path /= No_Name then
-- First line is the unit name
Write_Mapping (Name_Id (ALI_Unit));
-- Second line is the ALI file name
Write_Mapping (Name_Id (ALI_Name));
-- Third line is the ALI path name
Write_Mapping (ALI_Path);
end if;
end;
end if;
end Add_To_Mapping;
Closure_Sources : Source_Vectors.Vector := Library_Sources;
-- Library Ada sources of Stand-Alone library, that is sources
-- in the closure of the interface, including in imported
-- projects.
-- Start of processing for Get_Closure
begin
Over_Sources : while Index < Closure_Sources.Last_Index loop
Index := Index + 1;
Source := Closure_Sources (Index);
Add_To_Mapping
(Source,
From_Object_Dir => Library_Sources.Contains (Source));
Dep_Path := Source.Dep_Path;
Dep_TS := Source.Dep_TS;
Text := Read_Library_Info_From_Full
(File_Name_Type (Dep_Path), Dep_TS'Access);
if Text /= null then
The_ALI :=
ALI.Scan_ALI
(File_Name_Type (Dep_Path),
Text,
Ignore_ED => False,
Err => True,
Read_Lines => "W");
Free (Text);
-- Get the withed sources
Over_Units : for J in ALI.ALIs.Table (The_ALI).First_Unit
.. ALI.ALIs.Table (The_ALI).Last_Unit
loop
Over_Imports : for K in ALI.Units.Table (J).First_With
.. ALI.Units.Table (J).Last_With
loop
Sfile := ALI.Withs.Table (K).Sfile;
-- Skip generics
if Sfile /= No_File then
Afile := ALI.Withs.Table (K).Afile;
Src_Id := Source_Files_Htable.Get
(Project_Tree.Source_Files_HT, Sfile);
while Src_Id /= No_Source loop
Initialize_Source_Record (Src_Id);
if Is_Compilable (Src_Id)
and then Src_Id.Dep_Name = Afile
then
case Src_Id.Kind is
when Spec =>
declare
Bdy : constant GPR.Source_Id :=
Other_Part (Src_Id);
begin
if Bdy /= No_Source
and then not Bdy.Locally_Removed
then
Src_Id := Bdy;
end if;
end;
when Impl =>
if Is_Subunit (Src_Id) then
Src_Id := No_Source;
end if;
when Sep =>
Src_Id := No_Source;
end case;
exit;
end if;
Src_Id := Src_Id.Next_With_File_Name;
end loop;
if Src_Id /= No_Source then
if not Closure_Sources.Contains (Src_Id) then
Closure_Sources.Append (Src_Id);
end if;
if In_Library_SAL_Projs (Src_Id)
and then not Library_Sources.Contains
(Src_Id)
then
Library_Sources.Append (Src_Id);
Initialize_Source_Record (Src_Id);
Check_Latest_Object_TS (Src_Id);
end if;
end if;
end if;
end loop Over_Imports;
end loop Over_Units;
end if;
Get_Roots (Source);
end loop Over_Sources;
end Get_Closure;
---------------
-- Get_Roots --
---------------
procedure Get_Roots (Source : Source_Id) is
Root : Roots_Access := Source.Roots;
Position : Objects.Cursor;
Inserted : Boolean;
begin
while Root /= null loop
Initialize_Source_Record (Root.Root);
if Root.Root.Unit = No_Unit_Index then
Library_Objs.Insert
((Path => Root.Root.Object_Path,
TS => Root.Root.Object_TS,
Known => False), Position, Inserted);
Get_Roots (Root.Root);
elsif In_Library_SAL_Projs (Root.Root)
and then not Library_Sources.Contains (Root.Root)
then
Library_Sources.Append (Root.Root);
Check_Latest_Object_TS (Root.Root);
end if;
Root := Root.Next;
end loop;
end Get_Roots;
procedure Process_Non_Standalone_Aggregate_Library is
new For_Project_And_Aggregated (Process);
procedure Process_Standalone_Aggregate_Library is
new For_Project_And_Aggregated (Process_Standalone);
Proj : Project_Id := For_Project;
-- Start of processing of Get_Objects
begin
Library_Objs.Clear;
Library_Sources.Clear;
Library_Projs.Clear;
Library_SAL_Projs.Clear;
FNHS.Reset (Processed_ALIs);
FNHS.Reset (Library_ALIs);
FNHS.Reset (Complete_Interface_ALIs);
if For_Project.Qualifier = Aggregate_Library then
if For_Project.Standalone_Library = No then
Process_Non_Standalone_Aggregate_Library
(For_Project, Project_Tree);
else
Process_Standalone_Aggregate_Library
(For_Project, Project_Tree);
end if;
else
while Proj /= No_Project loop
if For_Project.Standalone_Library = No then
Process (Proj, Project_Tree);
else
Process_Standalone (Proj, Project_Tree);
end if;
Proj := Proj.Extends;
end loop;
end if;
if For_Project.Standalone_Library /= No then
-- Check the interface
Check_Interface (For_Project, Project_Tree);
-- Create the binder maping file
Tempdir.Create_Temp_File (Mapping_FD, Mapping_Path);
Record_Temp_File (Project_Tree.Shared, Mapping_Path);
Get_Closure;
Close (Mapping_FD);
-- Put all the object files in the closure in Library_Objs
for Source of Library_Sources loop
Library_Objs.Insert
((Path => Source.Object_Path,
TS => Source.Object_TS,
Known => False));
end loop;
end if;
end Get_Objects;
-------------------------
-- Wait_For_Dependency --
-------------------------
procedure Wait_For_Dependency (P : Project_Id) is
begin
while Libs_Are_Building.Contains (P.Name) loop
-- There may be some executable binding in parallel to the library
-- build operations, i.e. Outstanding_Processes may be greater
-- than the list of libs being built.
pragma Assert
(Natural (Libs_Are_Building.Length) <= Outstanding_Processes,
"more libs building than outstanding processes "
& Libs_Are_Building.Length'Img & Outstanding_Processes'Img
& ' ' & Get_Name_String (P.Name));
-- Wait for any process to be done to check is the dependency
-- resolved.
Wait_For_Slots_Less_Than (Outstanding_Processes);
end loop;
end Wait_For_Dependency;
------------------------
-- Write_Object_Files --
------------------------
procedure Write_Object_Files is
begin
if not Library_Objs.Is_Empty then
Put_Line (Exchange_File, Library_Label (Object_Files));
for Item of Library_Objs loop
Put_Line (Exchange_File, Get_Name_String (Item.Path));
end loop;
end if;
end Write_Object_Files;
----------------------------
-- Write_Object_Directory --
----------------------------
procedure Write_Object_Directory is
Object_Projects : Project_Vectors.Vector;
Prj : Project_Id;
Index : Natural;
-- The projects that have already be found when looking for object
-- directories.
package PNHT renames Path_Name_HTable;
Object_Directories : PNHT.Instance;
-- The object directories that have already be found
procedure Get_Object_Projects (Prj : Project_Id);
-- Recursive procedure to collect the aggregated projects
function Is_In_Object_Projects (Prj : Project_Id) return Boolean;
-- Returns True iff Prj is in table Object_Projects
function Is_In_Object_Directories
(Dir : Path_Name_Type) return Boolean
is (PNHT.Get (Object_Directories, Dir));
-- Returns True iff Dir is in table Object_Directories
-------------------------
-- Get_Object_Projects --
-------------------------
procedure Get_Object_Projects (Prj : Project_Id) is
begin
if Prj.Qualifier = Aggregate_Library then
declare
List : Aggregated_Project_List := Prj.Aggregated_Projects;
begin
while List /= null loop
Get_Object_Projects (List.Project);
List := List.Next;
end loop;
end;
else
-- Add object directories of the project and of the projects it
-- extends, if any.
declare
Proj : Project_Id := Prj;
begin
while Proj /= No_Project loop
if not Is_In_Object_Projects (Proj) then
Object_Projects.Append (Proj);
if Proj.Object_Directory /= No_Path_Information
and then not Is_In_Object_Directories
(Proj.Object_Directory.Display_Name)
then
PNHT.Set
(Object_Directories,
Proj.Object_Directory.Display_Name, True);
Put_Line
(Exchange_File,
Get_Name_String
(Proj.Object_Directory.Display_Name));
end if;
end if;
Proj := Proj.Extends;
end loop;
end;
end if;
end Get_Object_Projects;
---------------------------
-- Is_In_Object_Projects --
---------------------------
function Is_In_Object_Projects (Prj : Project_Id) return Boolean is
begin
return Object_Projects.Contains (Prj);
end Is_In_Object_Projects;
-- Start of processing for Write_Object_Directory
begin
Object_Projects.Clear;
PNHT.Reset (Object_Directories);
Put_Line (Exchange_File, Library_Label (Object_Directory));
Get_Object_Projects (For_Project);
Index := Object_Projects.First_Index;
-- Note: cannot iterate on Object_Projects as we're modifying
-- the container within the loop.
while Index <= Object_Projects.Last_Index loop
Prj := Object_Projects.Element (Index);
Index := Index + 1;
-- Add object directories of imported non library projects
Process_Imported_Non_Libraries (Prj);
for Proj of Non_Library_Projs loop
Get_Object_Projects (Proj);
end loop;
-- Add ALI dir directories of imported projects (only if it
-- is not an externally built project or if the project has
-- sources). This skip the library projects with no sources
-- used for example to add a system library to the linker.
declare
List : Project_List := Prj.All_Imported_Projects;
begin
while List /= null loop
if not Is_In_Object_Projects (List.Project) and then
(not List.Project.Externally_Built
or else List.Project.Source_Dirs /= Nil_String)
then
if List.Project.Library_ALI_Dir /= No_Path_Information
then
Put_Line
(Exchange_File,
Get_Name_String
(List.Project.Library_ALI_Dir.Display_Name));
elsif List.Project.Library_Dir /= No_Path_Information
then
Put_Line
(Exchange_File,
Get_Name_String
(List.Project.Library_Dir.Display_Name));
end if;
end if;
List := List.Next;
end loop;
end;
end loop;
end Write_Object_Directory;
---------------------
-- Write_Compilers --
---------------------
procedure Write_Compilers is
procedure Compilers_For
(Project : Project_Id;
Tree : Project_Tree_Ref;
Dummy : in out Boolean);
-- Write compilers for the given project
Dummy : Boolean := True;
Lang_Seen : Lang_Set.Set;
-------------------
-- Compilers_For --
-------------------
procedure Compilers_For
(Project : Project_Id;
Tree : Project_Tree_Ref;
Dummy : in out Boolean)
is
pragma Unreferenced (Tree, Dummy);
Lang : Language_Ptr := Project.Languages;
Compiler : String_Access;
begin
-- Exchange file, Compilers section
while Lang /= No_Language_Index loop
if not Lang_Seen.Contains (Lang.Name) then
Lang_Seen.Insert (Lang.Name);
Compiler := Get_Compiler_Driver_Path (Project, Lang);
if Compiler /= null then
Put_Line
(Exchange_File,
Get_Name_String (Lang.Name) & ASCII.LF
& Compiler.all);
elsif Lang.Config.Compiler_Driver /= No_File then
Put_Line
(Exchange_File,
Get_Name_String (Lang.Name) & ASCII.LF
& Get_Name_String (Lang.Config.Compiler_Driver));
end if;
end if;
Lang := Lang.Next;
end loop;
end Compilers_For;
procedure For_Imported is
new For_Every_Project_Imported (Boolean, Compilers_For);
-- Start of processing for Write_Compilers
begin
Put_Line (Exchange_File, Library_Label (Compilers));
Compilers_For (For_Project, Project_Tree, Dummy);
if For_Project.Qualifier = Aggregate_Library then
For_Imported (For_Project, Project_Tree, Dummy);
end if;
end Write_Compilers;
-------------------------------------
-- Write_Compiler_Leading_Switches --
-------------------------------------
procedure Write_Compiler_Leading_Switches is
procedure Compiler_Leading_Switches_For
(Project : Project_Id;
Tree : Project_Tree_Ref;
Dummy : in out Boolean);
-- Write compilers for the given project
Dummy : Boolean := True;
Lang_Seen : Lang_Set.Set;
-----------------------------------
-- Compiler_Leading_Switches_For --
-----------------------------------
procedure Compiler_Leading_Switches_For
(Project : Project_Id;
Tree : Project_Tree_Ref;
Dummy : in out Boolean)
is
pragma Unreferenced (Tree, Dummy);
Lang : Language_Ptr := Project.Languages;
Indx : Name_List_Index;
begin
while Lang /= No_Language_Index loop
if not Lang_Seen.Contains (Lang.Name) then
Lang_Seen.Insert (Lang.Name);
Indx := Lang.Config.Compiler_Leading_Required_Switches;
if Indx /= No_Name_List then
Put_Line
(Exchange_File,
"language=" & Get_Name_String (Lang.Name));
Emit_Compiler_Switches (Exchange_File, Indx);
if Opt.CodePeer_Mode then
Put_Line (Exchange_File, "-gnatcC");
end if;
end if;
end if;
Lang := Lang.Next;
end loop;
end Compiler_Leading_Switches_For;
procedure For_Imported is new For_Every_Project_Imported
(Boolean, Compiler_Leading_Switches_For);
-- Start of processing for Write_Compiler_Leading_Switches
begin
Put_Line (Exchange_File, Library_Label (Compiler_Leading_Switches));
Compiler_Leading_Switches_For (For_Project, Project_Tree, Dummy);
if For_Project.Qualifier = Aggregate_Library then
For_Imported (For_Project, Project_Tree, Dummy);
end if;
end Write_Compiler_Leading_Switches;
--------------------------------------
-- Write_Compiler_Trailing_Switches --
--------------------------------------
procedure Write_Compiler_Trailing_Switches is
procedure Compiler_Trailing_Switches_For
(Project : Project_Id;
Tree : Project_Tree_Ref;
Dummy : in out Boolean);
-- Write compilers for the given project
Dummy : Boolean := True;
Lang_Seen : Lang_Set.Set;
------------------------------------
-- Compiler_Trailing_Switches_For --
------------------------------------
procedure Compiler_Trailing_Switches_For
(Project : Project_Id;
Tree : Project_Tree_Ref;
Dummy : in out Boolean)
is
pragma Unreferenced (Tree, Dummy);
Lang : Language_Ptr := Project.Languages;
Indx : Name_List_Index;
Node : Name_Node;
begin
while Lang /= No_Language_Index loop
if not Lang_Seen.Contains (Lang.Name) then
Lang_Seen.Insert (Lang.Name);
Indx := Lang.Config.Compiler_Trailing_Required_Switches;
if Indx /= No_Name_List then
Put_Line
(Exchange_File,
"language=" & Get_Name_String (Lang.Name));
while Indx /= No_Name_List loop
Node := Project_Tree.Shared.Name_Lists.Table (Indx);
Put_Line (Exchange_File, Get_Name_String (Node.Name));
Indx := Node.Next;
end loop;
end if;
end if;
Lang := Lang.Next;
end loop;
end Compiler_Trailing_Switches_For;
procedure For_Imported is new For_Every_Project_Imported
(Boolean, Compiler_Trailing_Switches_For);
-- Start of processing for Write_Compiler_Trailing_Switches
begin
Put_Line (Exchange_File, Library_Label (Compiler_Trailing_Switches));
Compiler_Trailing_Switches_For (For_Project, Project_Tree, Dummy);
if For_Project.Qualifier = Aggregate_Library then
For_Imported (For_Project, Project_Tree, Dummy);
end if;
end Write_Compiler_Trailing_Switches;
----------------
-- Write_Name --
----------------
procedure Write_Name (Label : Library_Section; Name : Name_Id) is
begin
if Name /= No_Name then
Put_Line
(Exchange_File,
Library_Label (Label) & ASCII.LF & Get_Name_String (Name));
end if;
end Write_Name;
--------------------
-- Write_Filename --
--------------------
procedure Write_Filename
(Label : Library_Section; Filename : File_Name_Type) is
begin
Write_Name (Label, Name_Id (Filename));
end Write_Filename;
----------------
-- Write_List --
----------------
procedure Write_List (Label : Library_Section; List : String_List_Id) is
Current : String_List_Id := List;
Element : String_Element;
begin
while Current /= Nil_String loop
Element := Project_Tree.Shared.String_Elements.Table (Current);
Get_Name_String (Element.Value);
if Name_Len /= 0 then
Check_Section (Label);
Put_Line (Exchange_File, Name_Buffer (1 .. Name_Len));
end if;
Current := Element.Next;
end loop;
end Write_List;
---------------------
-- Write_Name_List --
---------------------
procedure Write_Name_List
(Label : Library_Section; List : Name_List_Index)
is
Current : Name_List_Index := List;
Nam : Name_Node;
begin
if List /= No_Name_List then
Check_Section (Label);
loop
Nam := Project_Tree.Shared.Name_Lists.Table (Current);
Put_Line (Exchange_File, Get_Name_String (Nam.Name));
Current := Nam.Next;
exit when Current = No_Name_List;
end loop;
end if;
end Write_Name_List;
--------------------------
-- Write_Partial_Linker --
--------------------------
procedure Write_Partial_Linker is
List : constant Name_List_Index :=
For_Project.Config.Lib_Partial_Linker;
begin
if List /= No_Name_List then
Write_Name_List (Partial_Linker, List);
end if;
end Write_Partial_Linker;
--------------------------------------
-- Write_Shared_Lib_Minimum_Options --
--------------------------------------
procedure Write_Shared_Lib_Minimum_Options is
Library_Options : Variable_Value := Nil_Variable_Value;
begin
-- Output the minimal options to build a shared library (standard
-- or encapsulated).
if For_Project.Standalone_Library = Encapsulated then
Library_Options :=
Value_Of
(Name_Library_Encapsulated_Options,
For_Project.Decl.Attributes, Project_Tree.Shared);
if not Library_Options.Default then
Write_List
(Gprexch.Shared_Lib_Minimum_Options, Library_Options.Values);
end if;
else
Write_Name_List
(Shared_Lib_Minimum_Options,
For_Project.Config.Shared_Lib_Min_Options);
end if;
end Write_Shared_Lib_Minimum_Options;
---------------------------
-- Write_Library_Version --
---------------------------
procedure Write_Library_Version is
List : constant Name_List_Index :=
For_Project.Config.Lib_Version_Options;
begin
if List /= No_Name_List then
Write_Name_List (Library_Version_Options, List);
end if;
end Write_Library_Version;
-------------------------------
-- Write_Runtime_Library_Dir --
-------------------------------
procedure Write_Runtime_Library_Dir is
procedure RTL_For
(Project : Project_Id;
Tree : Project_Tree_Ref;
Dummy : in out Boolean);
-- Write runtime libraries for the given project
Dummy : Boolean := True;
Lang_Seen : Lang_Set.Set;
-------------
-- RTL_For --
-------------
procedure RTL_For
(Project : Project_Id;
Tree : Project_Tree_Ref;
Dummy : in out Boolean)
is
pragma Unreferenced (Tree, Dummy);
List : Language_Ptr := Project.Languages;
Lib_Dirs : Name_List_Index;
Nam_Nod : Name_Node;
begin
while List /= No_Language_Index loop
if List.Config.Runtime_Library_Dirs /= No_Name_List then
Lib_Dirs := List.Config.Runtime_Library_Dirs;
while Lib_Dirs /= No_Name_List loop
Nam_Nod :=
Project_Tree.Shared.Name_Lists.Table (Lib_Dirs);
if not Lang_Seen.Contains (Nam_Nod.Name)
then
if Lang_Seen.Length = 0 then
Put_Line
(Exchange_File,
Library_Label (Runtime_Library_Dir));
end if;
Lang_Seen.Insert (Nam_Nod.Name);
Put_Line
(Exchange_File,
Get_Name_String (List.Name) & ASCII.LF
& Get_Name_String (Nam_Nod.Name));
end if;
Lib_Dirs := Nam_Nod.Next;
end loop;
end if;
List := List.Next;
end loop;
end RTL_For;
procedure For_Imported is
new For_Every_Project_Imported (Boolean, RTL_For);
-- Start of processing for Write_Runtime_Library_Dir
begin
RTL_For (For_Project, Project_Tree, Dummy);
if For_Project.Qualifier = Aggregate_Library then
For_Imported (For_Project, Project_Tree, Dummy);
end if;
end Write_Runtime_Library_Dir;
---------------------
-- Write_Auto_Init --
---------------------
procedure Write_Auto_Init is
begin
if For_Project.Standalone_Library /= No and then
For_Project.Lib_Auto_Init
then
Put_Line (Exchange_File, Library_Label (Auto_Init));
end if;
end Write_Auto_Init;
---------------------------
-- Write_Binding_Options --
---------------------------
procedure Write_Binding_Options is
begin
if For_Project.Standalone_Library /= No then
declare
Binder_Package : constant Package_Id :=
Value_Of
(Name => Name_Binder,
In_Packages =>
For_Project.Decl.Packages,
Shared => Project_Tree.Shared);
begin
if Binder_Package /= No_Package then
declare
Defaults : constant Array_Element_Id :=
Value_Of
(Name => Name_Default_Switches,
In_Arrays =>
Project_Tree.Shared.Packages.Table
(Binder_Package).Decl.Arrays,
Shared => Project_Tree.Shared);
Switch_Array : constant Array_Element_Id :=
Value_Of
(Name => Name_Switches,
In_Arrays =>
Project_Tree.Shared.Packages.Table
(Binder_Package).Decl.Arrays,
Shared => Project_Tree.Shared);
Switches : Variable_Value := Nil_Variable_Value;
begin
if Defaults /= No_Array_Element then
Switches :=
Value_Of
(Index => Name_Ada,
Src_Index => 0,
In_Array => Defaults,
Shared => Project_Tree.Shared);
if not Switches.Default then
Write_List
(Gprexch.Binding_Options, Switches.Values);
end if;
end if;
if Switch_Array /= No_Array_Element then
Switches :=
Value_Of
(Index => Name_Ada,
Src_Index => 0,
In_Array => Switch_Array,
Force_Lower_Case_Index => True,
Shared => Project_Tree.Shared);
if not Switches.Default
and then Switches.Kind = List
then
Write_List
(Gprexch.Binding_Options, Switches.Values);
end if;
end if;
end;
end if;
end;
end if;
end Write_Binding_Options;
---------------------------
-- Write_Run_Path_Option --
---------------------------
procedure Write_Run_Path_Option is
List : constant Name_List_Index :=
For_Project.Config.Run_Path_Option;
begin
if Opt.Run_Path_Option and then List /= No_Name_List then
Write_Name_List (Run_Path_Option, List);
Put_Line (Exchange_File,
Library_Label (Gprexch.Run_Path_Origin));
if For_Project.Config.Run_Path_Origin /= No_Name then
Put_Line (Exchange_File,
Get_Name_String (For_Project.Config.Run_Path_Origin));
end if;
if For_Project.Config.Separate_Run_Path_Options then
Put_Line
(Exchange_File,
Library_Label (Gprexch.Separate_Run_Path_Options));
end if;
end if;
end Write_Run_Path_Option;
-----------------------------------
-- Write_Leading_Library_Options --
-----------------------------------
procedure Write_Leading_Library_Options is
Leading_Library_Options : Variable_Value := Nil_Variable_Value;
begin
-- If attribute Leading_Library_Options was specified, add these
-- additional options.
Leading_Library_Options :=
Value_Of
(Name_Leading_Library_Options,
For_Project.Decl.Attributes, Project_Tree.Shared);
if not Leading_Library_Options.Default then
Write_List
(Gprexch.Leading_Library_Options,
Leading_Library_Options.Values);
end if;
end Write_Leading_Library_Options;
---------------------------
-- Write_Library_Options --
---------------------------
procedure Write_Library_Options (Success : out Boolean) is
procedure Write_Linker_Options (P : Project_Id);
-- Write linker options for Project
------------------------------
-- Write_Linker_Options --
------------------------------
procedure Write_Linker_Options (P : Project_Id) is
Linker_Package : constant Package_Id :=
Value_Of
(Name => Name_Linker,
In_Packages => P.Decl.Packages,
Shared => Project_Tree.Shared);
begin
-- Check linker package for a definition of Linker_Options
if Linker_Package /= No_Package then
Check_Attribute : declare
Opts : constant Variable_Value :=
Value_Of
(Variable_Name => Name_Linker_Options,
In_Variables =>
Project_Tree.Shared.Packages.Table
(Linker_Package).Decl.Attributes,
Shared => Project_Tree.Shared);
begin
-- If a Linker_Options attribute is found, output it
-- into the Library_Options section.
if not Opts.Default then
Output_Options : declare
List : String_List_Id := Opts.Values;
Elem : String_Element;
begin
if List /= Nil_String then
-- First ensure the section is opended
Check_Section (Library_Options);
if P.Library_Dir.Name /= No_Path then
Put_Line
(Exchange_File,
"-L" & Get_Name_String (P.Library_Dir.Name));
end if;
loop
Elem :=
Project_Tree.Shared.String_Elements.Table
(List);
Put_Line
(Exchange_File, Get_Name_String (Elem.Value));
List := Elem.Next;
exit when List = Nil_String;
end loop;
end if;
end Output_Options;
end if;
end Check_Attribute;
end if;
end Write_Linker_Options;
Library_Options : Variable_Value := Nil_Variable_Value;
-- Start of processing for Write_Library_Options
begin
Success := True;
-- If attribute Library_Options was specified, add these
-- additional options.
Library_Options :=
Value_Of
(Name_Library_Options,
For_Project.Decl.Attributes, Project_Tree.Shared);
if not Library_Options.Default then
Write_List (Gprexch.Library_Options, Library_Options.Values);
-- For static libraries, check that the library options are
-- existing object files.
-- Also, skip this check for SALs so that Library_Options other
-- than object files may be specified for the partial linking.
if For_Project.Standalone_Library = No
and then Is_Static (For_Project)
then
declare
List : String_List_Id := Library_Options.Values;
Elem : String_Element;
OK : Boolean;
begin
while List /= Nil_String loop
Elem := Project_Tree.Shared.String_Elements.Table (List);
Get_Name_String (Elem.Value);
if Is_Absolute_Path (Name_Buffer (1 .. Name_Len)) then
OK := Is_Regular_File (Name_Buffer (1 .. Name_Len));
else
OK := Is_Regular_File
(Get_Name_String (For_Project.Object_Directory.Name)
& Directory_Separator
& Name_Buffer (1 .. Name_Len));
end if;
if not OK then
Error_Msg
(Msg => "unknown object file " &
Name_Buffer (1 .. Name_Len),
Flag_Location => Library_Options.Location);
Success := False;
end if;
List := Elem.Next;
end loop;
end;
end if;
end if;
-- For encapsulated and shared libraries we also want to add the
-- Linker_Options for all imported projects.
if not Is_Static (For_Project)
or else For_Project.Standalone_Library = Encapsulated
then
declare
L : Project_List := For_Project.All_Imported_Projects;
begin
while L /= null loop
Write_Linker_Options (L.Project);
L := L.Next;
end loop;
end;
end if;
-- Get -largs section from command line for shared libraries
if not Is_Static (For_Project) then
for Arg of Command_Line_Linker_Options loop
Check_Section (Gprexch.Library_Options);
Put_Line (Exchange_File, Arg);
end loop;
end if;
end Write_Library_Options;
---------------------------------
-- Write_Library_Rpath_Options --
---------------------------------
procedure Write_Library_Rpath_Options is
procedure Add_Language (Lang : Language_Ptr);
-- Add language Name in array Langs if not already there
procedure Find_Languages
(Project : Project_Id;
Tree : Project_Tree_Ref;
With_State : in out Boolean);
-- Find the languages of a project
procedure Find_All_Languages is new
For_Every_Project_Imported (Boolean, Find_Languages);
procedure Get_Directory;
-- Get a directory for one language
procedure Get_Languages;
-- Put in Langs the languages of the project tree rooted at project
-- For_Project.
------------------
-- Add_Language --
------------------
procedure Add_Language (Lang : Language_Ptr) is
begin
-- Only add a language if it is not already in the list
for J in 1 .. Last_Lang loop
if Lang.Name = Langs (J).Name then
return;
end if;
end loop;
-- Double array Langs if already full
if Last_Lang = Langs'Last then
declare
New_Langs : constant Lang_Names_Ptr :=
new Lang_Names (1 .. 2 * Langs'Length);
begin
New_Langs (Langs'Range) := Langs.all;
Langs := New_Langs;
end;
end if;
Last_Lang := Last_Lang + 1;
Langs (Last_Lang) := Lang;
end Add_Language;
--------------------
-- Find_Languages --
--------------------
procedure Find_Languages
(Project : Project_Id;
Tree : Project_Tree_Ref;
With_State : in out Boolean)
is
pragma Unreferenced (Tree);
pragma Unreferenced (With_State);
Lang : Language_Ptr := Project.Languages;
begin
while Lang /= No_Language_Index loop
Add_Language (Lang);
Lang := Lang.Next;
end loop;
end Find_Languages;
-------------------
-- Get_Languages --
-------------------
procedure Get_Languages is
OK : Boolean := True;
begin
Last_Lang := 0;
Find_Languages (For_Project, Project_Tree, OK);
Find_All_Languages
(By => For_Project,
Tree => Project_Tree,
With_State => OK,
Include_Aggregated => False);
end Get_Languages;
List : Array_Element_Id;
Elem : Array_Element;
Label_Issued : Boolean := False;
Lang_Index : Natural;
Lang_Ptr : Language_Ptr;
Opt_List : String_List_Id;
Opt_Elem : String_Element;
-------------------
-- Get_Directory --
-------------------
procedure Get_Directory is
Opt_Nmb : Natural := 0;
Args : Argument_List_Access;
FD : File_Descriptor;
Pname : Path_Name_Type;
Return_Code : Integer;
File : Text_File;
Line : String (1 .. 1000);
Last : Natural;
Disregard : Boolean;
begin
-- Check that the compiler driver exists
if Lang_Ptr.Config.Compiler_Driver_Path = null then
Lang_Ptr.Config.Compiler_Driver_Path :=
Locate_Exec_On_Path
(Get_Name_String (Lang_Ptr.Config.Compiler_Driver));
end if;
if Lang_Ptr.Config.Compiler_Driver_Path /= null then
-- Count the options
while Opt_List /= Nil_String loop
Opt_Elem :=
Project_Tree.Shared.String_Elements.Table (Opt_List);
Opt_Nmb := Opt_Nmb + 1;
Opt_List := Opt_Elem.Next;
end loop;
Args := new Argument_List (1 .. Opt_Nmb);
-- Put the options in Args
Opt_Nmb := 0;
Opt_List := Elem.Value.Values;
while Opt_List /= Nil_String loop
Opt_Elem :=
Project_Tree.Shared.String_Elements.Table (Opt_List);
Opt_Nmb := Opt_Nmb + 1;
Args (Opt_Nmb) :=
new String'(Get_Name_String (Opt_Elem.Value));
Opt_List := Opt_Elem.Next;
end loop;
-- Create a temporary file and invoke the compiler with the
-- options redirecting the output to this temporary file.
Tempdir.Create_Temp_File (FD, Pname);
Spawn
(Program_Name => Lang_Ptr.Config.Compiler_Driver_Path.all,
Args => Args.all,
Output_File_Descriptor => FD,
Return_Code => Return_Code);
Close (FD);
Free (Args);
-- Now read the temporary file and get the first non empty
-- line, if any.
Open (File, Get_Name_String (Pname));
if Is_Valid (File) then
Last := 0;
while not End_Of_File (File) loop
Get_Line (File, Line, Last);
exit when Last > 0;
end loop;
-- Get the directory name of the path
if Last /= 0 then
declare
Dir : constant String :=
Dir_Name
(Normalize_Pathname
(Line (1 .. Last),
Resolve_Links => Opt.Follow_Links_For_Files));
begin
-- If it is in fact a directory, put it in the
-- exchange file.
if Is_Directory (Dir) then
if not Label_Issued then
Put_Line
(Exchange_File,
Library_Label
(Gprexch.Library_Rpath_Options));
Label_Issued := True;
end if;
Put_Line (Exchange_File, Dir);
end if;
end;
end if;
end if;
if Is_Valid (File) then
Close (File);
end if;
-- Delete the temporary file, if gprbuild was not invoked
-- with -dn.
if not Opt.Keep_Temporary_Files then
Delete_File (Get_Name_String (Pname), Disregard);
end if;
end if;
end Get_Directory;
-- Start of processing for Write_Library_Rpath_Options
begin
if Opt.Run_Path_Option
and then For_Project.Config.Run_Path_Option /= No_Name_List
then
List :=
Value_Of
(Name_Library_Rpath_Options,
For_Project.Decl.Arrays, Project_Tree.Shared);
if List /= No_Array_Element then
Get_Languages;
while Last_Lang /= 0 and then List /= No_Array_Element loop
Elem := Project_Tree.Shared.Array_Elements.Table (List);
Lang_Index := 0;
for J in 1 .. Last_Lang loop
if Elem.Index = Langs (J).Name then
Lang_Index := J;
exit;
end if;
end loop;
if Lang_Index /= 0 then
Lang_Ptr := Langs (Lang_Index);
-- Remove language from the list so that rpath options
-- are not looked for twice for the same language.
Langs (Lang_Index .. Last_Lang - 1) :=
Langs (Lang_Index + 1 .. Last_Lang);
Last_Lang := Last_Lang - 1;
-- Invoke the compiler for the language, followed by
-- the options and put the result into a temporary file.
Opt_List := Elem.Value.Values;
-- Nothing to do if there is no options
if Opt_List /= Nil_String then
Get_Directory;
end if;
end if;
List := Elem.Next;
end loop;
end if;
end if;
end Write_Library_Rpath_Options;
------------------------------
-- Write_Imported_Libraries --
------------------------------
procedure Write_Imported_Libraries is
begin
-- If there are imported libraries, put their data in the exchange
-- file.
if not Library_Projs.Is_Empty then
Put_Line (Exchange_File, Library_Label (Imported_Libraries));
for J in reverse 1 .. Library_Projs.Last_Index loop
if For_Project.Qualifier /= Aggregate_Library
or else Library_Projs (J).Proj.Externally_Built
then
Put_Line
(Exchange_File,
Get_Name_String
(Library_Projs (J).Proj.Library_Dir.Display_Name)
& ASCII.LF
& Get_Name_String (Library_Projs (J).Proj.Library_Name));
end if;
end loop;
end if;
end Write_Imported_Libraries;
----------------------------
-- Write_Dependency_Files --
----------------------------
procedure Write_Dependency_Files is
procedure Process (Proj : Project_Id; Tree : Project_Tree_Ref);
procedure Add (Source : Source_Id);
---------
-- Add --
---------
procedure Add (Source : Source_Id) is
begin
if Source.Unit = No_Unit_Index
or else For_Project.Standalone_Library = No
then
Add_Dep (Get_Name_String (Source.Dep_Path));
end if;
end Add;
-------------
-- Process --
-------------
procedure Process (Proj : Project_Id; Tree : Project_Tree_Ref) is
pragma Unreferenced (Tree);
Current_Proj : Project_Id := Proj;
Source : Source_Id;
begin
while Current_Proj /= No_Project loop
declare
Iter : Source_Iterator;
begin
Iter := For_Each_Source (Project_Tree, Current_Proj);
loop
Source := GPR.Element (Iter);
exit when Source = No_Source;
if not Source.Locally_Removed
and then Source.Dep_Path /= No_Path
and then
(not Source.Project.Externally_Built
or else not For_Project.Externally_Built
or else Source.Project.Extended_By /= No_Project)
then
if Source.Kind = Spec then
if Other_Part (Source) = No_Source then
Add (Source);
end if;
elsif not Is_Subunit (Source) then
Add (Source);
end if;
end if;
Next (Iter);
end loop;
end;
Current_Proj := Current_Proj.Extends;
end loop;
end Process;
procedure Process_Aggregate_Library is
new For_Project_And_Aggregated (Process);
-- Start of processing for Write_Dependency_Files
begin
Put_Line (Exchange_File, Library_Label (Dependency_Files));
First_Dep := null;
Process_Aggregate_Library (For_Project, Project_Tree);
if For_Project.Standalone_Library /= No then
for Source of Library_Sources loop
Add_Dep (Get_Name_String (Source.Dep_Path));
end loop;
end if;
while First_Dep /= null loop
Put_Line (Exchange_File, First_Dep.Name.all);
First_Dep := First_Dep.Next;
end loop;
end Write_Dependency_Files;
------------------------
-- Write_Mapping_File --
------------------------
procedure Write_Mapping_File is
begin
if Mapping_Path /= No_Path then
Put_Line
(Exchange_File,
Library_Label (Mapping_File) & ASCII.LF
& Get_Name_String (Mapping_Path));
end if;
end Write_Mapping_File;
-----------------------------
-- Write_Toolchain_Version --
-----------------------------
procedure Write_Toolchain_Version is
procedure Toolchain_Version_For
(Project : Project_Id;
Tree : Project_Tree_Ref;
Dummy : in out Boolean);
-- Write runtime libraries for the given project
Dummy : Boolean := True;
Lang_Seen : Lang_Set.Set;
---------------------------
-- Toolchain_Version_For --
---------------------------
procedure Toolchain_Version_For
(Project : Project_Id;
Tree : Project_Tree_Ref;
Dummy : in out Boolean)
is
pragma Unreferenced (Tree, Dummy);
List : Language_Ptr := Project.Languages;
begin
while List /= No_Language_Index loop
if (List.Config.Toolchain_Version /= No_Name or else
List.Config.Runtime_Library_Version /= No_Name)
and then not Lang_Seen.Contains (List.Name)
then
if Lang_Seen.Length = 0 then
Put_Line
(Exchange_File, Library_Label (Toolchain_Version));
end if;
Lang_Seen.Insert (List.Name);
Put_Line (Exchange_File, Get_Name_String (List.Name));
if List.Config.Runtime_Library_Version /= No_Name then
Put_Line
(Exchange_File,
Get_Name_String (List.Config.Runtime_Library_Version));
else
Put_Line
(Exchange_File,
Get_Name_String (List.Config.Toolchain_Version));
end if;
end if;
List := List.Next;
end loop;
end Toolchain_Version_For;
procedure For_Imported is
new For_Every_Project_Imported (Boolean, Toolchain_Version_For);
-- Start of processing for Write_Toolchain_Version
begin
Toolchain_Version_For (For_Project, Project_Tree, Dummy);
if For_Project.Qualifier = Aggregate_Library then
For_Imported (For_Project, Project_Tree, Dummy);
end if;
end Write_Toolchain_Version;
-------------------------------
-- Write_Interface_Dep_Files --
-------------------------------
procedure Write_Interface_Dep_Files is
Key : FNHS.Key_Option;
function Interface_ALI return File_Name_Type
is (Key.K);
begin
Put_Line (Exchange_File, Library_Label (Interface_Dep_Files));
Key := FNHS.Get_First_Key (Complete_Interface_ALIs);
while Key.Present loop
-- Find the source to get the absolute path of the ALI file
declare
Next_Proj : Project_Id;
Iter : Source_Iterator;
begin
Next_Proj := For_Project.Extends;
if For_Project.Qualifier = Aggregate_Library then
Iter := For_Each_Source (Project_Tree);
else
Iter := For_Each_Source (Project_Tree, For_Project);
end if;
loop
while GPR.Element (Iter) /= No_Source
and then
(GPR.Element (Iter).Unit = null
or else GPR.Element (Iter).Dep_Name /= Interface_ALI)
loop
Next (Iter);
end loop;
Source := GPR.Element (Iter);
exit when Source /= No_Source
or else Next_Proj = No_Project;
Iter := For_Each_Source (Project_Tree, Next_Proj);
Next_Proj := Next_Proj.Extends;
end loop;
if Source /= No_Source then
if Source.Kind = Sep then
Source := No_Source;
elsif Source.Kind = Spec
and then Other_Part (Source) /= No_Source
then
Source := Other_Part (Source);
end if;
end if;
if Source /= No_Source then
if Source.Project /= Project
and then not Is_Extending (For_Project, Source.Project)
and then For_Project.Qualifier /= Aggregate_Library
then
Source := No_Source;
end if;
end if;
if Source /= No_Source then
Put_Line (Exchange_File, Get_Name_String (Source.Dep_Path));
end if;
end;
Key := FNHS.Get_Next_Key (Complete_Interface_ALIs);
end loop;
end Write_Interface_Dep_Files;
----------------------------
-- Write_Other_Interfaces --
----------------------------
procedure Write_Other_Interfaces is
Interfaces : String_List_Id := For_Project.Other_Interfaces;
Element : String_Element;
begin
Put_Line (Exchange_File, Library_Label (Other_Interfaces));
while Interfaces /= Nil_String loop
Element := Project_Tree.Shared.String_Elements.Table (Interfaces);
Put_Line (Exchange_File, Get_Name_String (Element.Value));
Interfaces := Element.Next;
end loop;
end Write_Other_Interfaces;
-------------------------------
-- Write_Interface_Obj_Files --
-------------------------------
procedure Write_Interface_Obj_Files is
List : String_List_Id := For_Project.Other_Interfaces;
Element : String_Element;
Other_Int : Boolean := False;
Key : FNHS.Key_Option;
function Interface_Dep return File_Name_Type
is (Key.K);
function Base_Name (Name : Name_Id) return String;
-- File name without path nor extension
procedure Find_Source;
-- Find the source corresponding to Interface_Dep (when Other_Int is
-- False) or Element.Value (when Other_Int is True).
---------------
-- Base_Name --
---------------
function Base_Name (Name : Name_Id) return String is
N : constant String := Get_Name_String (Name);
begin
return Base_Name (N, File_Extension (N));
end Base_Name;
-----------------
-- Find_Source --
-----------------
procedure Find_Source is
Next_Proj : Project_Id;
Iter : Source_Iterator;
begin
Next_Proj := For_Project.Extends;
if For_Project.Qualifier = Aggregate_Library then
Iter := For_Each_Source (Project_Tree);
else
Iter := For_Each_Source (Project_Tree, For_Project);
end if;
loop
-- Look for the Source_Id corresponding to this unit
while GPR.Element (Iter) /= No_Source
and then
-- Either an foreign language, we need the
-- implementation of this unit.
((Other_Int
and then
(Base_Name (Name_Id (GPR.Element (Iter).Object)) /=
Base_Name (Element.Value)
or else GPR.Element (Iter).Kind = Spec
or else GPR.Element (Iter).Locally_Removed))
-- Or and Ada unit, we need the dependency file
or else
(not Other_Int and then
(GPR.Element (Iter).Unit = null
or else GPR.Element (Iter).Dep_Name /=
Interface_Dep)))
loop
Next (Iter);
end loop;
Source := GPR.Element (Iter);
exit when Source /= No_Source
or else Next_Proj = No_Project;
Iter := For_Each_Source (Project_Tree, Next_Proj);
Next_Proj := Next_Proj.Extends;
end loop;
if Source /= No_Source then
if Source.Kind = Sep then
Source := No_Source;
elsif Source.Kind = Spec
and then Other_Part (Source) /= No_Source
then
Source := Other_Part (Source);
end if;
end if;
if Source /= No_Source
and then Source.Project /= Project
and then not Is_Extending (For_Project, Source.Project)
and then For_Project.Qualifier /= Aggregate_Library
then
Source := No_Source;
end if;
if Source /= No_Source then
Put_Line (Exchange_File, Get_Name_String (Source.Object_Path));
end if;
end Find_Source;
begin
Put_Line (Exchange_File, Library_Label (Interface_Obj_Files));
-- First the Ada sources
Other_Int := False;
Key := FNHS.Get_First_Key (Complete_Interface_ALIs);
while Key.Present loop
Find_Source;
Key := FNHS.Get_Next_Key (Complete_Interface_ALIs);
end loop;
-- Then the foreign language objects
Other_Int := True;
while List /= Nil_String loop
Element := Project_Tree.Shared.String_Elements.Table (List);
Find_Source;
List := Element.Next;
end loop;
end Write_Interface_Obj_Files;
-------------------
-- Write_Sources --
-------------------
procedure Write_Sources is
begin
Put_Line (Exchange_File, Library_Label (Sources));
-- Copy the path of the sources
Project := For_Project;
while Project /= No_Project loop
Iter := For_Each_Source (Project_Tree, Project);
loop
Source := GPR.Element (Iter);
exit when Source = No_Source;
if not Source.Locally_Removed
and then Source.Replaced_By = No_Source
then
Put_Line
(Exchange_File,
Get_Name_String (Source.Path.Display_Name));
end if;
Next (Iter);
end loop;
Project := Project.Extends;
end loop;
end Write_Sources;
--------------------------
-- Write_Response_Files --
--------------------------
procedure Write_Response_Files is
begin
if For_Project.Config.Max_Command_Line_Length > 0
and then For_Project.Config.Resp_File_Format /= None
then
Put_Line
(Exchange_File,
Library_Label (Max_Command_Line_Length) & ASCII.LF
& For_Project.Config.Max_Command_Line_Length'Img & ASCII.LF
& Library_Label (Gprexch.Response_File_Format) & ASCII.LF
& For_Project.Config.Resp_File_Format'Img);
if For_Project.Config.Resp_File_Options /= No_Name_List then
Write_Name_List
(Response_File_Switches,
For_Project.Config.Resp_File_Options);
end if;
end if;
end Write_Response_Files;
-- Start of processing for Build_Library
begin
-- Check if there is an object directory
if For_Project.Object_Directory.Display_Name = No_Path then
Fail_Program
(Project_Tree,
"no object directory for library project "
& Get_Name_String (For_Project.Display_Name),
Exit_Code => E_Project);
end if;
-- Check consistency and build environment
if For_Project.Config.Lib_Support = None then
Fail_Program
(Project_Tree, "library projects not supported on this platform",
Exit_Code => E_General);
elsif not Is_Static (For_Project)
and then For_Project.Config.Lib_Support /= Full
then
Fail_Program
(Project_Tree,
"shared library projects not supported on this platform",
Exit_Code => E_General);
elsif not For_Project.Config.Lib_Encapsulated_Supported
and then For_Project.Standalone_Library = Encapsulated
then
Fail_Program
(Project_Tree,
"encapsulated library projects not supported on this platform",
Exit_Code => E_General);
end if;
if For_Project.Config.Library_Builder = No_Path then
Fail_Program (Project_Tree, "no library builder specified");
end if;
Library_Builder :=
Locate_Exec_On_Path
(Get_Name_String (For_Project.Config.Library_Builder));
if Library_Builder = null then
Fail_Program
(Project_Tree,
"could not locate library builder """
& Get_Name_String (For_Project.Config.Library_Builder) & '"');
end if;
Library_Builder_Name :=
new String'(Ada.Directories.Base_Name (Library_Builder.all));
if Opt.CodePeer_Mode then
null;
elsif Is_Static (For_Project) then
Check_Archive_Builder;
elsif For_Project.Standalone_Library /= No then
Check_Object_Lister;
Check_Export_File;
Check_Library_Symbol_File;
end if;
Library_Needs_To_Be_Built :=
Opt.Force_Compilations or else For_Project.Need_Build;
if not Library_Needs_To_Be_Built and then
Opt.Verbosity_Level > Opt.Low
then
Put (" Checking library ");
Put (Get_Name_String (For_Project.Library_Name));
Put_Line (" ...");
end if;
Get_Objects;
-- Work occurs in the object directory
Change_To_Object_Directory (For_Project);
-- Get the name of the library exchange file
Get_Name_String (For_Project.Library_Name);
Add_Str_To_Name_Buffer (Library_Exchange_Suffix);
Exchange_File_Name := new String'(Name_Buffer (1 .. Name_Len));
if not Library_Needs_To_Be_Built then
declare
TS : constant Time_Stamp_Type :=
File_Stamp (Exchange_File_Name.all);
begin
if String (TS) < String (Latest_Object_TS) then
Library_Needs_To_Be_Built := True;
if Opt.Verbosity_Level > Opt.Low then
if TS = Empty_Time_Stamp then
Put (" -> library exchange file ");
Put (Exchange_File_Name.all);
Put_Line (" does not exist");
else
Put
(" -> object files more recent than library"
& " exchange file ");
Put_Line (Exchange_File_Name.all);
end if;
end if;
else
begin
Open (Exchange_File, In_File, Exchange_File_Name.all);
if End_Of_File (Exchange_File) then
if Opt.Verbosity_Level > Opt.Low then
Put (" -> library exchange file """);
Put (Exchange_File_Name.all);
Put_Line (""" is empty");
end if;
Library_Needs_To_Be_Built := True;
end if;
exception
when others =>
if Opt.Verbosity_Level > Opt.Low then
Put (" -> library exchange file """);
Put (Exchange_File_Name.all);
Put_Line (""" cannot be open");
end if;
Library_Needs_To_Be_Built := True;
end;
end if;
end;
end if;
if not Library_Needs_To_Be_Built then
-- The exchange file is open in input
-- Get the path of the library file that should be the first field
Get_Line (Exchange_File, Name_Buffer, Name_Len);
if Name_Buffer (1 .. Name_Len) /= Library_Label (Library_Path) then
Library_Needs_To_Be_Built := True;
Close (Exchange_File);
if Opt.Verbosity_Level > Opt.Low then
Put (" -> library exchange file ");
Put (Exchange_File_Name.all);
Put_Line (" has wrong format");
end if;
else
Get_Line (Exchange_File, Name_Buffer, Name_Len);
declare
Lib_File_Name : constant String :=
Base_Name (Name_Buffer (1 .. Name_Len));
Shared_Lib_Prefix : String_Access := new String'("lib");
Shared_Lib_Suffix : String_Access := new String'(".so");
Archive_Suffix : String_Access := new String'(".a");
begin
if Is_Static (For_Project) then
if For_Project.Config.Archive_Suffix /= No_File then
Archive_Suffix :=
new String'
(Get_Name_String (For_Project.Config.Archive_Suffix));
end if;
Expected_File_Name :=
new String'
("lib" &
Get_Name_String (For_Project.Library_Name) &
Archive_Suffix.all);
else
if For_Project.Config.Shared_Lib_Prefix /= No_File then
Shared_Lib_Prefix :=
new String'
(Get_Name_String
(For_Project.Config.Shared_Lib_Prefix));
end if;
if For_Project.Config.Shared_Lib_Suffix /= No_File then
Shared_Lib_Suffix :=
new String'
(Get_Name_String
(For_Project.Config.Shared_Lib_Suffix));
end if;
Expected_File_Name :=
new String'
(Shared_Lib_Prefix.all &
Get_Name_String (For_Project.Library_Name) &
Shared_Lib_Suffix.all);
end if;
if Lib_File_Name /= Expected_File_Name.all then
Library_Needs_To_Be_Built := True;
Close (Exchange_File);
if Opt.Verbosity_Level > Opt.Low then
Put_Line (" -> incorrect library file name");
Put_Line (" expected " & Expected_File_Name.all);
Put_Line (" actual " & Lib_File_Name);
end if;
end if;
end;
if not Library_Needs_To_Be_Built then
For_Project.Library_TS :=
File_Stamp (Name_Buffer (1 .. Name_Len));
if For_Project.Library_TS < Latest_Object_TS then
Library_Needs_To_Be_Built := True;
Close (Exchange_File);
if Opt.Verbosity_Level > Opt.Low then
Put_Line
(" -> "
& "object file(s) more recent than library file "
& Exchange_File_Name.all);
end if;
end if;
end if;
end if;
end if;
if not Library_Needs_To_Be_Built then
-- The next line should be the object file label, followed by the
-- object paths and time stamps.
Get_Line (Exchange_File, Name_Buffer, Name_Len);
if Name_Buffer (1 .. Name_Len) /= Library_Label (Object_Files) then
Library_Needs_To_Be_Built := True;
if Opt.Verbosity_Level > Opt.Low then
Put_Line
(" -> library exchange file " & Exchange_File_Name.all
& " has wrong format");
end if;
end if;
while not Library_Needs_To_Be_Built
and then not End_Of_File (Exchange_File)
loop
Get_Line (Exchange_File, Name_Buffer, Name_Len);
exit when Name_Buffer (1) = '[';
Object_Path := Name_Find;
Library_Needs_To_Be_Built := True;
if End_Of_File (Exchange_File) then
if Opt.Verbosity_Level > Opt.Low then
Put_Line
(" -> library exchange file " & Exchange_File_Name.all
& " has wrong format");
end if;
else
Get_Line (Exchange_File, Name_Buffer, Name_Len);
if Name_Len = Time_Stamp_Length then
Object_TS :=
Time_Stamp_Type (Name_Buffer (1 .. Name_Len));
Path_Found := False;
declare
Elem : Library_Object;
Cursor : Objects.Cursor := Library_Objs.First;
use Objects;
begin
-- Look in the Library_Objs set. If the path name is in
-- the set, indicate that it has been found.
-- The library need to be re-build if the time stamp is
-- different in the set.
while Cursor /= No_Element loop
Elem := Element (Cursor);
if Object_Path = Elem.Path then
Path_Found := True;
Library_Needs_To_Be_Built := Object_TS /= Elem.TS;
Elem.Known := True;
Library_Objs.Replace_Element (Cursor, Elem);
exit;
end if;
Next (Cursor);
end loop;
end;
-- If the object file is not found, it may be that the path
-- in the library is the same as the path of the object
-- files, but with different symbolic links. So, we try
-- again resolving the symbolic links.
if not Path_Found then
declare
Norm_Path : constant String :=
Normalize_Pathname
(Get_Name_String (Object_Path),
Resolve_Links => Opt.Follow_Links_For_Dirs);
Elem : Library_Object;
Cursor : Objects.Cursor := Library_Objs.First;
use Objects;
begin
while Cursor /= No_Element loop
Elem := Element (Cursor);
if Norm_Path =
Normalize_Pathname
(Get_Name_String (Elem.Path),
Resolve_Links => Opt.Follow_Links_For_Dirs)
then
Library_Needs_To_Be_Built :=
Object_TS /= Elem.TS;
Elem.Known := True;
Library_Objs.Replace_Element (Cursor, Elem);
exit;
end if;
Next (Cursor);
end loop;
end;
end if;
if Library_Needs_To_Be_Built and then
Opt.Verbosity_Level > Opt.Low
then
Put (" -> object file ");
Put (Get_Name_String (Object_Path));
Put_Line (" does not exist or have wrong time stamp");
end if;
else
if Opt.Verbosity_Level > Opt.Low then
Put_Line
(" -> library exchange file "
& Exchange_File_Name.all & " has wrong format");
end if;
end if;
end if;
end loop;
-- Check a possible different library version
if not Library_Needs_To_Be_Built
and then not Is_Static (For_Project)
and then For_Project.Config.Symbolic_Link_Supported
and then not End_Of_File (Exchange_File)
and then Name_Buffer (1 .. Name_Len) =
Library_Label (Gprexch.Library_Version)
then
Get_Line (Exchange_File, Name_Buffer, Name_Len);
if Name_Buffer (1 .. Name_Len) /=
Get_Name_String (For_Project.Lib_Internal_Name)
then
Library_Needs_To_Be_Built := True;
if Opt.Verbosity_Level > Opt.Low then
Put_Line (" -> different library version");
end if;
end if;
end if;
Close (Exchange_File);
if not Library_Needs_To_Be_Built then
declare
Cursor : Objects.Cursor := Library_Objs.First;
Elem : Library_Object;
use Objects;
begin
while Cursor /= No_Element loop
Elem := Element (Cursor);
if not Elem.Known then
Library_Needs_To_Be_Built := True;
if Opt.Verbosity_Level > Opt.Low then
Put
(" -> library was built without object file ");
Put_Line (Get_Name_String (Elem.Path));
end if;
exit;
end if;
Next (Cursor);
end loop;
end;
end if;
end if;
if not Library_Needs_To_Be_Built then
-- Check if in a project imported directly or indirectly the time
-- stamp of a library is greater than the time stamp of this library.
declare
List : Project_List;
Proj2 : Project_Id;
Lib_Timestamp1 : constant Time_Stamp_Type :=
For_Project.Library_TS;
begin
List := For_Project.All_Imported_Projects;
while List /= null loop
Proj2 := List.Project;
Wait_For_Dependency (Proj2);
if not Library_Needs_To_Be_Built
and then Proj2.Library
and then (Proj2.Was_Built
or else Lib_Timestamp1 < Proj2.Library_TS)
then
Library_Needs_To_Be_Built := True;
if Opt.Verbosity_Level > Opt.Low then
Put_Line
(" -> library file for project "
& Get_Name_String (Proj2.Display_Name)
& " is more recent than library file for project "
& Get_Name_String (For_Project.Display_Name));
end if;
end if;
exit when Library_Needs_To_Be_Built
and then Libs_Are_Building.Is_Empty;
List := List.Next;
end loop;
Dependencies_Ready := True;
end;
end if;
if not Library_Needs_To_Be_Built then
if Opt.Verbosity_Level > Opt.Low then
if For_Project = Main_Project then
Put ('"');
Put (Expected_File_Name.all);
Put_Line (""" up to date");
else
Put_Line (" -> up to date");
end if;
end if;
else
-- The current directory is already the correct object directory.
-- However, we call again Change_To_Object_Directory with
-- Must_Be_Writable set to True, to check if the object directory
-- is writable and to fail graciously if it not.
Change_To_Object_Directory (For_Project, Must_Be_Writable => True);
-- Create the library exchange file
begin
Create (Exchange_File, Out_File, Exchange_File_Name.all);
exception
when others =>
Fail_Program
(Project_Tree,
"unable to create library exchange file "
& Exchange_File_Name.all);
end;
if Opt.CodePeer_Mode then
Put_Line (Exchange_File, Library_Label (CodePeer_Mode));
end if;
if Opt.Quiet_Output then
Put_Line (Exchange_File, Library_Label (Quiet));
elsif Opt.Verbose_Mode then
if Opt.Verbosity_Level = Opt.Low then
Put_Line (Exchange_File, Library_Label (Verbose_Low));
else
Put_Line (Exchange_File, Library_Label (Verbose_Higher));
end if;
end if;
if No_SAL_Binding then
Put_Line (Exchange_File, Library_Label (Gprexch.No_SAL_Binding));
end if;
Write_Object_Files;
-- Library name
Put_Line
(Exchange_File,
Library_Label (Library_Name) & ASCII.LF
& Get_Name_String (For_Project.Library_Name));
-- Library version
Write_Name (Library_Version, For_Project.Lib_Internal_Name);
-- Library directory
Put_Line
(Exchange_File,
Library_Label (Library_Directory) & ASCII.LF
& Get_Name_String (For_Project.Library_Dir.Display_Name) & ASCII.LF
-- Project directory
& Library_Label (Project_Directory) & ASCII.LF
& Get_Name_String (For_Project.Directory.Display_Name));
if For_Project.Library_ALI_Dir /= No_Path_Information
and then
For_Project.Library_ALI_Dir.Name /= For_Project.Library_Dir.Name
then
Put_Line
(Exchange_File,
Library_Label (Library_Dependency_Directory) & ASCII.LF
& Get_Name_String (For_Project.Library_ALI_Dir.Display_Name));
end if;
Write_Object_Directory;
Write_Compilers;
Write_Compiler_Leading_Switches;
Write_Compiler_Trailing_Switches;
Write_Partial_Linker;
if No_Create then
Put_Line (Exchange_File, Library_Label (Gprexch.No_Create));
end if;
if Opt.CodePeer_Mode then
Put_Line (Exchange_File, Library_Label (Gprexch.CodePeer_Mode));
elsif Is_Static (For_Project) then
Put_Line
(Exchange_File, Library_Label (Static) & ASCII.LF
& Library_Label (Archive_Builder) & ASCII.LF
& Archive_Builder_Path.all);
for Opt of Archive_Builder_Opts loop
Put_Line (Exchange_File, Opt.Name);
end loop;
if not Archive_Builder_Append_Opts.Is_Empty then
Put_Line
(Exchange_File,
Library_Label (Archive_Builder_Append_Option));
for Option of Archive_Builder_Append_Opts loop
Put_Line (Exchange_File, Option.Name);
end loop;
end if;
Write_Filename (Archive_Suffix, For_Project.Config.Archive_Suffix);
if Archive_Indexer_Path /= null then
Put_Line
(Exchange_File,
Library_Label (Archive_Indexer) & ASCII.LF
& Archive_Indexer_Path.all);
for Option of Archive_Indexer_Opts loop
Put_Line (Exchange_File, Option.Name);
end loop;
end if;
else
-- Driver_Name
Write_Filename (Driver_Name, For_Project.Config.Shared_Lib_Driver);
-- Shared_Lib_Prefix
Write_Filename
(Shared_Lib_Prefix, For_Project.Config.Shared_Lib_Prefix);
-- Shared_Lib_Suffix
Write_Filename
(Shared_Lib_Suffix, For_Project.Config.Shared_Lib_Suffix);
Write_Shared_Lib_Minimum_Options;
Write_Library_Version;
-- Symbolic_Link_Supported
if For_Project.Config.Symbolic_Link_Supported then
Put_Line
(Exchange_File, Library_Label (Symbolic_Link_Supported));
end if;
-- Major_Minor_Id_Supported
if For_Project.Config.Lib_Maj_Min_Id_Supported then
Put_Line
(Exchange_File, Library_Label (Major_Minor_Id_Supported));
end if;
-- Relocatable
Put_Line (Exchange_File, Library_Label (Relocatable));
-- Auto_init
Write_Auto_Init;
-- Archive_Suffix
-- This is needed even in the case of dynamic libraries as they
-- may rely on static libraries (e.g. if they are encapsulated)
Write_Filename (Archive_Suffix, For_Project.Config.Archive_Suffix);
-- Gprexch.Install_Name
if Opt.Run_Path_Option then
Write_Name
(Gprexch.Install_Name,
For_Project.Config.Library_Install_Name_Option);
end if;
Write_Run_Path_Option;
Write_Leading_Library_Options;
Write_Library_Rpath_Options;
end if;
Write_Runtime_Library_Dir;
Write_Binding_Options;
Write_Library_Options (Library_Options_Success);
Write_Dependency_Files;
Write_Mapping_File;
Write_Toolchain_Version;
if not Is_Static (For_Project)
or else For_Project.Standalone_Library = Encapsulated
then
Process_Imported_Libraries
(For_Project, There_Are_SALs => Disregard);
Write_Imported_Libraries;
end if;
if For_Project.Standalone_Library /= No then
if For_Project.Lib_Auto_Init then
Put_Line (Exchange_File, Library_Label (Auto_Init));
end if;
Write_Interface_Dep_Files;
if For_Project.Other_Interfaces /= Nil_String then
Write_Other_Interfaces;
end if;
if For_Project.Library_Src_Dir /= No_Path_Information then
-- Copy_Source_Dir
Put_Line
(Exchange_File, Library_Label (Copy_Source_Dir) & ASCII.LF
& Get_Name_String
(For_Project.Library_Src_Dir.Display_Name));
Write_Sources;
end if;
-- Standalone mode
Put_Line
(Exchange_File, Library_Label (Standalone_Mode) & ASCII.LF
& Standalone'Image (For_Project.Standalone_Library));
if For_Project.Symbol_Data.Symbol_Policy = Restricted then
if Library_Symbol_File /= null then
Put_Line
(Exchange_File,
Library_Label (Gprexch.Library_Symbol_File) & ASCII.LF
& Library_Symbol_File.all);
elsif Object_Lister_Path /= null then
-- Write interface objects
Write_Interface_Obj_Files;
-- Write object lister
Put_Line
(Exchange_File,
Library_Label (Object_Lister) & ASCII.LF
& Object_Lister_Path.all);
for Option of Object_Lister_Opts loop
Put_Line (Exchange_File, Option.Name);
end loop;
Put_Line
(Exchange_File,
Library_Label (Gprexch.Object_Lister_Matcher) & ASCII.LF
& Object_Lister_Matcher.all);
end if;
if Export_File_Switch /= null then
-- Write export symbols format
Put_Line
(Exchange_File,
Library_Label (Export_File) & ASCII.LF
& GPR.Export_File_Format'Image (Export_File_Format)
& ASCII.LF
& Export_File_Switch.all);
end if;
end if;
elsif For_Project.Other_Interfaces /= Nil_String then
Write_Other_Interfaces;
end if;
Write_Response_Files;
if Opt.Keep_Temporary_Files then
Put_Line (Exchange_File, Library_Label (Keep_Temporary_Files));
end if;
if Build_Script_Name /= null then
Put_Line
(Exchange_File,
Library_Label (Script_Path) & ASCII.LF
& Build_Script_Name.all);
end if;
Close (Exchange_File);
declare
Arguments : constant Argument_List := (1 => Exchange_File_Name);
Success : Boolean;
begin
if Library_Options_Success then
if not Opt.Quiet_Output then
if Opt.Verbose_Mode then
Put_Line
(Library_Builder.all & " " & Exchange_File_Name.all);
else
Display
(Section => Build_Libraries,
Command => Library_Builder_Name.all,
Argument => Exchange_File_Name.all);
end if;
end if;
if not Dependencies_Ready then
declare
L : Project_List := For_Project.All_Imported_Projects;
begin
while L /= null loop
Wait_For_Dependency (L.Project);
L := L.Next;
end loop;
end;
end if;
Wait_For_Slots_Less_Than (Opt.Maximum_Binders);
if Stop_Spawning then
return;
end if;
declare
Pid : Process_Id;
MI : Main_Info;
begin
Pid := Non_Blocking_Spawn (Library_Builder.all, Arguments);
Success := Pid /= Invalid_Pid;
if Success then
MI.File := No_File;
MI.Project := For_Project;
MI.Tree := Project_Tree;
Libs_Are_Building.Insert (For_Project.Name);
Add_Process (Pid, (Binding, MI));
Display_Processes ("bind");
end if;
end;
else
Success := False;
end if;
if not Success then
Fail_Program
(Project_Tree,
"could not build library for project " & Project_Name);
end if;
end;
end if;
-- Restore the current working directory to its previous value
Change_Dir (Current_Dir);
end Build_Library;
----------------------------
-- Emit_Compiler_Switches --
----------------------------
procedure Emit_Compiler_Switches
(Exchange_File : Text_IO.File_Type; Index : Name_List_Index)
is
Node : Name_Node;
List : Name_List_Index := Index;
Previous_Was_X : Boolean := False;
begin
while List /= No_Name_List loop
Node := Project_Tree.Shared.Name_Lists.Table (List);
declare
Arg : constant String := Get_Name_String (Node.Name);
begin
if Opt.CodePeer_Mode then
if Previous_Was_X then
Put_Line (Exchange_File, "adascil");
-- Strip target specific -m switches in CodePeer mode.
elsif Arg'Length <= 2 or else Arg (1 .. 2) /= "-m" then
Put_Line (Exchange_File, Arg);
end if;
else
Put_Line (Exchange_File, Arg);
end if;
Previous_Was_X := Arg = "-x";
end;
List := Node.Next;
end loop;
end Emit_Compiler_Switches;
-----------------------------------
-- Is_Included_In_Global_Archive --
-----------------------------------
function Is_Included_In_Global_Archive
(Object_Name : File_Name_Type;
Project : Project_Id) return Boolean
is
Proj : Project_Id;
Source : Source_Id;
Iter : Source_Iterator;
begin
-- If a source is overriden in an extending project, then the object
-- file is not included in the global archive.
Proj := Project.Extended_By;
while Proj /= No_Project loop
Iter := For_Each_Source (Project_Tree, Proj);
loop
Source := GPR.Element (Iter);
exit when Source = No_Source;
if Object_To_Global_Archive (Source)
and then Source.Object = Object_Name
then
return False;
end if;
Next (Iter);
end loop;
Proj := Proj.Extended_By;
end loop;
Iter := For_Each_Source (Project_Tree, Project);
loop
Source := GPR.Element (Iter);
exit when Source = No_Source;
if Object_To_Global_Archive (Source)
and then Source.Object = Object_Name
then
return Source.Language.Config.Objects_Linked;
end if;
Next (Iter);
end loop;
return True;
end Is_Included_In_Global_Archive;
---------
-- Run --
---------
procedure Run is
Main : Main_Info;
procedure Do_Post (Project : Project_Id; Tree : Project_Tree_Ref);
-------------
-- Do_Post --
-------------
procedure Do_Post (Project : Project_Id; Tree : Project_Tree_Ref) is
begin
if Builder_Data (Tree).Need_Binding
and then not Stop_Spawning
then
Post_Compilation_Phase (Project, Tree);
end if;
end Do_Post;
procedure Post_Compile_All is new For_Project_And_Aggregated (Do_Post);
begin
Clear_Time_Stamp_Cache;
Libs_Are_Building.Clear;
Outstanding_Processes := 0;
Stop_Spawning := False;
if Main_Project.Qualifier = Aggregate_Library then
-- For an aggregate library we do not want to build separate
-- libraries if any, this means that at this point we want to
-- handle only the main aggregate library project.
if Builder_Data (Project_Tree).Need_Binding then
Post_Compilation_Phase (Main_Project, Project_Tree);
end if;
else
Post_Compile_All (Main_Project, Project_Tree);
end if;
Wait_For_Slots_Less_Than (1);
if Bad_Processes.Length = 1 then
Main := Bad_Processes.First_Element;
Fail_Program
(Main.Tree,
(if Main.File = No_File -- It was gprlib call
then "could not build library for project "
& Get_Name_String (Main.Project.Name)
else "unable to bind " & Get_Name_String (Main.File)),
Exit_Code => E_Subtool);
elsif not Bad_Processes.Is_Empty then
for Main of Bad_Processes loop
Put (" binding of ");
Put
(if Main.File = No_File -- gprlib call
then Get_Name_String (Main.Project.Name)
else Get_Name_String (Main.File));
Put_Line (" failed");
end loop;
Fail_Program
(Bad_Processes.Last_Element.Tree,
"*** post compilation phase failed",
Exit_Code => E_Subtool);
end if;
end Run;
----------------------------
-- Post_Compilation_Phase --
----------------------------
procedure Post_Compilation_Phase
(Main_Project : Project_Id; Project_Tree : Project_Tree_Ref)
is
use Ada.Calendar;
Exchange_File : Text_IO.File_Type;
Line : String (1 .. 1_000);
Last : Natural;
Proj_List : Project_List;
Shared_Libs : Boolean := False;
Bind_Exchange_TS : Time;
Bind_Object_TS : Time;
Binder_Driver_Needs_To_Be_Called : Boolean := False;
function Get_Project_Checksum
(Project : Project_Id) return Message_Digest;
-- Calculate checksum of the Project variables and attributes
There_Are_Stand_Alone_Libraries : Boolean := False;
-- Set to True if there are SALS in the project tree
procedure Bind_Language
(Main_Proj : Project_Id;
Main : String;
Main_Base_Name_Index : File_Name_Type;
Main_File : Main_Info;
Main_Id : File_Name_Type;
B_Data : Binding_Data);
-- Do the "binding" phase for the language describeb in B_Data
procedure Add_Dependency_Files
(For_Project : Project_Id;
Language : Language_Ptr;
Main_Source : Source_Id;
Dep_Files : out Boolean);
-- Put the dependency files of the project in the binder exchange file
--------------------------
-- Add_Dependency_Files --
--------------------------
procedure Add_Dependency_Files
(For_Project : Project_Id;
Language : Language_Ptr;
Main_Source : Source_Id;
Dep_Files : out Boolean)
is
Config : constant Language_Config := Language.Config;
Roots : Roots_Access;
Iter : Source_Iterator;
procedure Put_Dependency_File (Source : Source_Id);
-- Put in the exchange file the dependency file path name for source
-- Source, if applicable.
-------------------------
-- Put_Dependency_File --
-------------------------
procedure Put_Dependency_File (Source : Source_Id) is
begin
if Source.Language.Name = Language.Name
and then
((Config.Kind = File_Based and then Source.Kind = Impl)
or else
(Config.Kind = Unit_Based
and then Source.Unit not in No_Unit_Index
| Main_Source.Unit
and then (Source.Kind = Impl
or else Other_Part (Source) = No_Source)
and then not Is_Subunit (Source)))
and then Is_Included_In_Global_Archive
(Source.Object, Source.Project)
then
if Source.Project = For_Project
or not Source.Project.Library
or Config.Kind = File_Based
then
Add_Dep (Get_Name_String (Source.Dep_Path));
Dep_Files := True;
elsif Source.Project.Standalone_Library = No then
Get_Name_String
(Source.Project.Library_ALI_Dir.Display_Name);
Get_Name_String_And_Append (Name_Id (Source.Dep_Name));
Add_Dep (Name_Buffer (1 .. Name_Len));
Dep_Files := True;
end if;
end if;
end Put_Dependency_File;
-- Start of processing for Add_Dependency_Files
begin
Dep_Files := False;
Roots := Main_Source.Roots;
if Roots = null then
if Main_Source.Unit = No_Unit_Index then
if Main_Project.Qualifier = Aggregate_Library then
Iter := For_Each_Source (Project_Tree);
else
Iter := For_Each_Source
(Project_Tree, Encapsulated_Libs => False);
end if;
while GPR.Element (Iter) /= No_Source loop
Initialize_Source_Record (GPR.Element (Iter));
-- Do not bind the non compilable sources, such as those
-- that have been locally removed.
if Is_Compilable (GPR.Element (Iter)) then
Put_Dependency_File (GPR.Element (Iter));
end if;
Next (Iter);
end loop;
end if;
else
-- Put the Roots
while Roots /= null loop
if Roots.Root /= No_Source then
Put_Dependency_File (Roots.Root);
end if;
Roots := Roots.Next;
end loop;
end if;
end Add_Dependency_Files;
-------------------
-- Bind_Language --
-------------------
procedure Bind_Language
(Main_Proj : Project_Id;
Main : String;
Main_Base_Name_Index : File_Name_Type;
Main_File : Main_Info;
Main_Id : File_Name_Type;
B_Data : Binding_Data)
is
subtype Project_Check_String is String
(1 .. Time_Stamp_Type'Length + 1 + Message_Digest'Length);
-- Project timestamp and checksum of the project variables with a
-- space in between.
Empty_Check_String : constant Project_Check_String :=
(others => ASCII.NUL);
type Project_Check_Line is record
Project : Project_Id;
Line : Project_Check_String := Empty_Check_String;
end record;
function Hash (Item : Path_Name_Type) return Ada.Containers.Hash_Type
is (Ada.Containers.Hash_Type'Mod (Item));
function File_Stamp (File : Path_Name_Type) return Time is
(File_Time_Stamp (Get_Name_String (File)));
-- Returns file modification time
package Project_File_Paths is new Ada.Containers.Hashed_Maps
(Key_Type => Path_Name_Type,
Element_Type => Project_Check_Line,
Hash => Hash,
Equivalent_Keys => "=");
function Get_Project_Checkline
(Project : Project_Id) return Project_Check_String;
-- Returns project check line either from Projects container or
-- calculate it if absent.
Projects : Project_File_Paths.Map;
Project_Path : Path_Name_Type;
Position : Project_File_Paths.Cursor;
Counter : Natural := 0;
Main_Source : constant Source_Id := Main_File.Source;
Bind_Exchange : constant String_Access :=
Binder_Exchange_File_Name
(Main_Base_Name_Index, B_Data.Binder_Prefix);
Dep_Files : Boolean;
Lang_Index : Language_Ptr;
Object_File_Suffix_Label_Written : Boolean;
---------------------------
-- Get_Project_Checkline --
---------------------------
function Get_Project_Checkline
(Project : Project_Id) return Project_Check_String is
begin
Position := Projects.Find (Project.Path.Display_Name);
if Project_File_Paths.Has_Element (Position)
and then Project_File_Paths.Element (Position).Line (1)
/= ASCII.NUL
then
return Project_File_Paths.Element (Position).Line;
end if;
return String (Osint.File_Stamp (Project.Path.Display_Name)) & ' '
& Get_Project_Checksum (Project);
end Get_Project_Checkline;
begin
Binder_Driver_Needs_To_Be_Called := Opt.Force_Compilations;
-- First check if the binder driver needs to be called.
-- It needs to be called if
-- 1) there is no existing binder exchange file
-- 2) there is no binder generated object file
-- 3) there is a dependency file of the language that
-- is more recent than any of these two files
if not Binder_Driver_Needs_To_Be_Called and then
Opt.Verbosity_Level > Opt.Low
then
Put_Line
(" Checking binder generated files for " & Main & "...");
end if;
Bind_Exchange_TS :=
File_Stamp
(Path_Name_Type'(Create_Name (Bind_Exchange.all)));
if not Binder_Driver_Needs_To_Be_Called then
if Bind_Exchange_TS = Osint.Invalid_Time then
Binder_Driver_Needs_To_Be_Called := True;
if Opt.Verbosity_Level > Opt.Low then
Put_Line
(" -> binder exchange file " &
Bind_Exchange.all &
" does not exist");
end if;
else
begin
Open (Exchange_File, In_File, Bind_Exchange.all);
exception
when others =>
Binder_Driver_Needs_To_Be_Called := True;
if Opt.Verbosity_Level > Opt.Low then
Put_Line
(" -> could not open " &
"binder exchange file" &
Bind_Exchange.all);
end if;
end;
end if;
end if;
if not Binder_Driver_Needs_To_Be_Called then
begin
Get_Line (Exchange_File, Line, Last);
exception
when others =>
Binder_Driver_Needs_To_Be_Called := True;
if Opt.Verbosity_Level > Opt.Low then
Put_Line
(" -> previous gprbind failed, or " &
Bind_Exchange.all &
" corrupted");
end if;
end;
end if;
-- Check the generated object file
if not Binder_Driver_Needs_To_Be_Called then
if Line (1 .. Last) /= Binding_Label (Generated_Object_File)
or else End_Of_File (Exchange_File)
then
Binder_Driver_Needs_To_Be_Called := True;
if Opt.Verbosity_Level > Opt.Low then
Put_Line
(" -> previous gprbind failed, or " &
Bind_Exchange.all &
" corrupted");
end if;
else
Get_Line (Exchange_File, Line, Last);
Bind_Object_TS :=
File_Stamp
(Path_Name_Type'(Create_Name (Line (1 .. Last))));
-- Do not perform this check in CodePeer mode where there is
-- no object file per se.
if Bind_Object_TS = Osint.Invalid_Time
and not Opt.CodePeer_Mode
then
Binder_Driver_Needs_To_Be_Called := True;
if Opt.Verbosity_Level > Opt.Low then
Put_Line
(" -> binder generated object " &
Line (1 .. Last) &
" does not exist");
end if;
end if;
end if;
end if;
if not Binder_Driver_Needs_To_Be_Called then
if End_Of_File (Exchange_File) then
Binder_Driver_Needs_To_Be_Called := True;
else
Get_Line (Exchange_File, Line, Last);
if Line (1 .. Last) /= Binding_Label (Project_Files)
or else End_Of_File (Exchange_File)
then
Binder_Driver_Needs_To_Be_Called := True;
end if;
end if;
if Binder_Driver_Needs_To_Be_Called then
if Opt.Verbosity_Level > Opt.Low then
Put_Line
(" -> previous gprbind failed, or " &
Bind_Exchange.all & " corrupted");
end if;
else
-- Populate the hash table Project_File_Paths with
-- the paths of all project files in the closure
-- of the main project.
Projects.Insert
(Main_Proj.Path.Display_Name,
Project_Check_Line'(Main_Proj, Line => <>));
Proj_List := Main_Proj.All_Imported_Projects;
while Proj_List /= null loop
Projects.Insert
(Proj_List.Project.Path.Display_Name,
(Proj_List.Project, Line => <>));
Proj_List := Proj_List.Next;
end loop;
-- Get the project file paths from the exchange
-- file and check if they are the expected project
-- files with the same time stamps.
while not End_Of_File (Exchange_File) loop
Get_Line (Exchange_File, Name_Buffer, Name_Len);
exit when Name_Len > 0 and then Name_Buffer (1) = '[';
if End_Of_File (Exchange_File) then
Binder_Driver_Needs_To_Be_Called := True;
if Opt.Verbosity_Level > Opt.Low then
Put_Line
(" -> previous gprbind failed, "
& "or " & Bind_Exchange.all & " corrupted");
end if;
exit;
end if;
Project_Path := Name_Find;
Position := Projects.Find (Project_Path);
if Project_File_Paths.Has_Element (Position) then
Counter := Counter + 1;
pragma Assert
(Projects (Position).Line = Empty_Check_String);
Projects (Position).Line :=
String (Osint.File_Stamp (Project_Path))
& ' ' & Get_Project_Checksum
(Projects (Position).Project);
Get_Line (Exchange_File, Line, Last);
if Projects (Position).Line /= Line (1 .. Last) then
Binder_Driver_Needs_To_Be_Called := True;
if Opt.Verbosity_Level > Opt.Low then
Put_Line
(" -> project file "
& Get_Name_String (Project_Path)
& " has been modified");
end if;
exit;
end if;
else
Binder_Driver_Needs_To_Be_Called := True;
if Opt.Verbosity_Level > Opt.Low then
Put_Line
(" -> unknown project file "
& Get_Name_String (Project_Path));
end if;
exit;
end if;
end loop;
-- Check if there are still project file paths in
-- the hash table.
if not Binder_Driver_Needs_To_Be_Called
and then Counter < Natural (Projects.Length)
then
Binder_Driver_Needs_To_Be_Called := True;
if Opt.Verbosity_Level > Opt.Low then
Put_Line (" -> more project files");
end if;
end if;
end if;
end if;
if Is_Open (Exchange_File) then
Close (Exchange_File);
end if;
if not Binder_Driver_Needs_To_Be_Called then
Queue.Initialize (Opt.One_Compilation_Per_Obj_Dir, Force => True);
declare
Config : constant Language_Config :=
B_Data.Language.Config;
Source_Identity : Source_Id;
Roots : Roots_Access;
Source : Source_Id;
Iter : Source_Iterator;
begin
-- Put the root sources in the queue
if Main_Source.Language.Name = B_Data.Language.Name then
Queue.Insert
(Source => (Tree => Main_File.Tree,
Id => Main_File.Source,
Closure => False));
end if;
Roots := Main_Source.Roots;
while Roots /= null loop
Queue.Insert
(Source => (Tree => Main_File.Tree,
Id => Roots.Root,
Closure => False));
Roots := Roots.Next;
end loop;
-- If main is not unit base and there is no root,
-- check all sources with the language name of the
-- binder, except those that are not interfaces of
-- their project.
if Queue.Is_Empty then
Iter := For_Each_Source (Project_Tree);
Loop1 : loop
Source := GPR.Element (Iter);
exit Loop1 when Source = No_Source;
if Source.Language.Name = B_Data.Language.Name
and then not Source.Locally_Removed
and then Is_Compilable (Source)
and then
((Config.Kind = File_Based
and then Source.Kind = Impl)
or else
(Config.Kind = Unit_Based
and then Source.Unit /= No_Unit_Index
and then Source.Unit /= Main_Source.Unit
and then (Source.Kind = Impl
or else Other_Part (Source) = No_Source)
and then not Is_Subunit (Source)))
and then Source.In_Interfaces
then
declare
Proj : Project_Id;
Src : Source_Id;
Iter2 : Source_Iterator;
begin
-- If a source is overriden in an
-- extending project, then the object file
-- is not included in the global archive.
Proj := Source.Project.Extended_By;
Loop2 : while Proj /= No_Project loop
Iter2 := For_Each_Source (Project_Tree, Proj);
loop
Src := GPR.Element (Iter2);
exit when Src = No_Source;
exit Loop1 when
Src.Object = Source.Object;
Next (Iter2);
end loop;
Proj := Proj.Extended_By;
end loop Loop2;
end;
Queue.Insert
(Source => (Tree => Main_File.Tree,
Id => Source,
Closure => False));
end if;
Next (Iter);
end loop Loop1;
end if;
-- Get each file from the queue and check its
-- dependency file.
declare
Dep_TS : aliased File_Attributes := Unknown_Attributes;
Dep_File : File_Name_Type;
Dep_Path : Path_Name_Type;
The_ALI : ALI.ALI_Id;
Text : Text_Buffer_Ptr;
Found : Boolean;
Source : Queue.Source_Info;
begin
while not Queue.Is_Empty loop
Queue.Extract (Found, Source);
Source_Identity := Source.Id;
Initialize_Source_Record (Source_Identity);
-- Get the dependency file for this source
Dep_File := Source_Identity.Dep_Name;
Dep_Path := Source_Identity.Dep_Path;
Dep_TS := Source_Identity.Dep_TS;
-- For a library file, if there is no ALI file
-- in the object directory, check in the Library
-- ALI directory.
if not Is_Regular_File (Get_Name_String (Dep_Path))
and then Source_Identity.Project.Library
and then
Source_Identity.Project.Library_ALI_Dir /=
No_Path_Information
then
Set_Name_Buffer
(Get_Name_String
(Source_Identity.Project
.Library_ALI_Dir.Display_Name));
Add_Char_To_Name_Buffer (Directory_Separator);
Get_Name_String_And_Append (Dep_File);
Dep_TS := Unknown_Attributes;
if Is_Regular_File (Name_Buffer (1 .. Name_Len)) then
Dep_Path := Name_Find;
end if;
end if;
declare
Proj : Project_Id :=
Source_Identity.Project.Extended_By;
begin
while Proj /= No_Project loop
Name_Len := 0;
if Proj.Library
and then
Proj.Library_ALI_Dir /= No_Path_Information
then
Get_Name_String_And_Append
(Proj.Library_ALI_Dir.Display_Name);
else
Get_Name_String_And_Append
(Proj.Object_Directory.Display_Name);
end if;
Add_Char_To_Name_Buffer
(Directory_Separator);
Get_Name_String_And_Append (Dep_File);
-- Check if the dependency file exists in
-- the extended project, and if it does,
-- replace both Dep_Path and Dep_TS with
-- the information for it.
if Is_Regular_File (Name_Buffer (1 .. Name_Len))
then
Dep_Path := Name_Find;
end if;
Proj := Proj.Extended_By;
end loop;
end;
-- Check the time stamp against the binder
-- exchange file time stamp.
if File_Time_Stamp (Dep_Path, Dep_TS'Access)
= Empty_Time_Stamp
then
Binder_Driver_Needs_To_Be_Called := True;
if Opt.Verbosity_Level > Opt.Low then
Put (" -> cannot find ");
Put_Line (Get_Name_String (Dep_Path));
end if;
exit;
elsif File_Stamp (Dep_Path) > Bind_Exchange_TS then
Binder_Driver_Needs_To_Be_Called := True;
if Opt.Verbosity_Level > Opt.Low then
Put (" -> ");
Put (Get_Name_String (Dep_Path));
Put_Line
(" is more recent than the binder exchange file");
end if;
exit;
else
Text := Read_Library_Info_From_Full
(File_Name_Type (Dep_Path), Dep_TS'Access);
if Text /= null then
The_ALI :=
ALI.Scan_ALI
(File_Name_Type (Dep_Path),
Text,
Ignore_ED => False,
Err => True,
Read_Lines => "W");
Free (Text);
Queue.Insert_Withed_Sources_For
(The_ALI,
Project_Tree,
Excluding_Shared_SALs => True);
end if;
end if;
end loop;
end;
end;
end if;
if not Binder_Driver_Needs_To_Be_Called then
if Opt.Verbosity_Level > Opt.Low then
Put_Line (" -> up to date");
end if;
else
begin
Create (Exchange_File, Out_File, Bind_Exchange.all);
exception
when others =>
Fail_Program
(Project_Tree,
"unable to create binder exchange file "
& Bind_Exchange.all);
end;
-- Optional line: Quiet or Verbose
if Opt.Quiet_Output then
Put_Line (Exchange_File, Binding_Label (Quiet));
elsif Opt.Verbose_Mode then
if Opt.Verbosity_Level = Opt.Low then
Put_Line (Exchange_File, Binding_Label (Verbose_Low));
else
Put_Line (Exchange_File, Binding_Label (Verbose_Higher));
end if;
end if;
-- If -dn was used, indicate to gprbind that the
-- temporary response file, if created, should not
-- deleted.
if Opt.Keep_Temporary_Files then
Put_Line
(Exchange_File,
Binding_Label (Delete_Temp_Files) & ASCII.LF & "False");
end if;
-- If there are Stand-Alone Libraries, tell it to gprbind
if There_Are_Stand_Alone_Libraries then
Put_Line
(Exchange_File,
Binding_Label (Gprexch.There_Are_Stand_Alone_Libraries));
end if;
-- If the language is Ada, create a binder mapping file
-- and pass it to gprbind.
if B_Data.Language_Name = Name_Ada then
declare
Mapping_Path : constant Path_Name_Type :=
Create_Binder_Mapping_File (Project_Tree);
begin
if Mapping_Path /= No_Path then
Put_Line
(Exchange_File,
Binding_Label (Gprexch.Mapping_File) & ASCII.LF
& Get_Name_String (Mapping_Path));
end if;
end;
end if;
-- Send the Toolchain Version if there is one for the language
if B_Data.Language.Config.Toolchain_Version /= No_Name
or else
B_Data.Language.Config.Runtime_Library_Version /= No_Name
then
Put_Line
(Exchange_File,
Binding_Label (Toolchain_Version) & ASCII.LF
& Get_Name_String (B_Data.Language.Name));
if B_Data.Language.Config.Runtime_Library_Version /= No_Name
then
Put_Line
(Exchange_File,
Get_Name_String
(B_Data.Language.Config.Runtime_Library_Version));
else
Put_Line
(Exchange_File,
Get_Name_String
(B_Data.Language.Config.Toolchain_Version));
end if;
end if;
-- Send the object file suffix for each language where it
-- is declared.
Lang_Index := Main_Proj.Languages;
Object_File_Suffix_Label_Written := False;
while Lang_Index /= No_Language_Index loop
if Lang_Index.Config.Object_File_Suffix /= No_Name then
if not Object_File_Suffix_Label_Written then
Put_Line
(Exchange_File, Binding_Label
(Gprexch.Object_File_Suffix));
Object_File_Suffix_Label_Written := True;
end if;
Put_Line
(Exchange_File,
Get_Name_String (Lang_Index.Name) & ASCII.LF
& Get_Name_String (Lang_Index.Config.Object_File_Suffix));
end if;
Lang_Index := Lang_Index.Next;
end loop;
-- Optional line: shared libs
if Shared_Libs then
Put_Line (Exchange_File, Binding_Label (Gprexch.Shared_Libs));
end if;
-- First, the main base name
Put_Line
(Exchange_File,
Binding_Label (Gprexch.Main_Base_Name) & ASCII.LF
& Get_Name_String (Main_Base_Name_Index));
-- Then, the compiler path and required switches
declare
Config : Language_Config renames B_Data.Language.Config;
List : Name_List_Index;
Nam_Nod : Name_Node;
begin
-- Compiler path
Put_Line
(Exchange_File,
Binding_Label (Gprexch.Compiler_Path) & ASCII.LF
& Get_Compiler_Driver_Path
(Main_Proj, B_Data.Language).all);
-- Leading required switches, if any
List := Config.Compiler_Leading_Required_Switches;
if List /= No_Name_List then
Put_Line
(Exchange_File,
Binding_Label (Gprexch.Compiler_Leading_Switches));
Emit_Compiler_Switches (Exchange_File, List);
if Opt.CodePeer_Mode then
Put_Line (Exchange_File, "-gnatcC");
end if;
end if;
-- Trailing required switches, if any
List := Config.Compiler_Trailing_Required_Switches;
if List /= No_Name_List then
Put_Line
(Exchange_File,
Binding_Label
(Gprexch.Compiler_Trailing_Switches));
while List /= No_Name_List loop
Nam_Nod :=
Project_Tree.Shared.Name_Lists.Table (List);
Put_Line
(Exchange_File, Get_Name_String (Nam_Nod.Name));
List := Nam_Nod.Next;
end loop;
end if;
end;
-- Then, the Dependency files
if Main_Source.Unit /= No_Unit_Index then
Initialize_Source_Record (Main_Source);
Put_Line
(Exchange_File,
Binding_Label (Main_Dependency_File) & ASCII.LF
& Get_Name_String (Main_Source.Dep_Path));
end if;
-- Add the relevant dependency files, either those in
-- Roots () for the project, or all dependency
-- files in the project tree, if Roots () is not
-- specified .
Put_Line (Exchange_File, Binding_Label (Dependency_Files));
First_Dep := null;
Add_Dependency_Files
(Main_Proj, B_Data.Language, Main_Source, Dep_Files);
while First_Dep /= null loop
Put_Line (Exchange_File, First_Dep.Name.all);
First_Dep := First_Dep.Next;
end loop;
-- Put the options, if any
declare
The_Packages : constant Package_Id :=
Main_Proj.Decl.Packages;
Binder_Package : constant GPR.Package_Id :=
GPR.Util.Value_Of
(Name => Name_Binder,
In_Packages => The_Packages,
Shared => Project_Tree.Shared);
Config : constant Language_Config :=
B_Data.Language.Config;
Options_Instance : constant Bind_Option_Table_Ref :=
Binder_Options_HTable.Get
(B_Data.Language_Name);
Switches : Variable_Value;
Switch_List : String_List_Id;
Element : String_Element;
begin
-- First, check if there are binder options
-- specified in the main project file.
if Binder_Package /= No_Package then
declare
Defaults : constant Array_Element_Id :=
GPR.Util.Value_Of
(Name => Name_Default_Switches,
In_Arrays =>
Project_Tree.Shared.Packages.Table
(Binder_Package).Decl.Arrays,
Shared => Project_Tree.Shared);
Switches_Array : constant Array_Element_Id :=
GPR.Util.Value_Of
(Name => Name_Switches,
In_Arrays =>
Project_Tree.Shared.Packages.Table
(Binder_Package).Decl.Arrays,
Shared => Project_Tree.Shared);
begin
Switches :=
GPR.Util.Value_Of
(Index => Name_Id (Main_Id),
Src_Index => 0,
In_Array => Switches_Array,
Shared => Project_Tree.Shared,
Allow_Wildcards => True);
if Switches = Nil_Variable_Value then
Switches :=
GPR.Util.Value_Of
(Index =>
B_Data.Language_Name,
Src_Index => 0,
In_Array => Switches_Array,
Shared => Project_Tree.Shared,
Force_Lower_Case_Index => True);
end if;
if Switches = Nil_Variable_Value then
Switches :=
GPR.Util.Value_Of
(Index => All_Other_Names,
Src_Index => 0,
In_Array => Switches_Array,
Shared => Project_Tree.Shared,
Force_Lower_Case_Index => True);
end if;
if Switches = Nil_Variable_Value then
Switches :=
GPR.Util.Value_Of
(Index => B_Data.Language_Name,
Src_Index => 0,
In_Array => Defaults,
Shared => Project_Tree.Shared);
end if;
end;
end if;
-- If there are binder options, either minimum
-- binder options, or in the main project file or
-- on the command line, put them in the exchange
-- file.
if Config.Binder_Required_Switches /= No_Name_List
or else Switches.Kind = GPR.List
or else not All_Language_Binder_Options.Is_Empty
or else Options_Instance /= No_Bind_Option_Table
or else Opt.CodePeer_Mode
or else (B_Data.Language_Name = Name_Ada
and then Opt.No_Main_Subprogram)
then
Put_Line
(Exchange_File, Binding_Label (Gprexch.Binding_Options));
-- First, the required switches, if any
declare
List : Name_List_Index :=
Config.Binder_Required_Switches;
Elem : Name_Node;
begin
while List /= No_Name_List loop
Elem :=
Project_Tree.Shared.Name_Lists.Table (List);
Get_Name_String (Elem.Name);
if Name_Len > 0 then
Put_Line
(Exchange_File,
Name_Buffer (1 .. Name_Len));
end if;
List := Elem.Next;
end loop;
end;
-- Then, the eventual options in the main
-- project file.
if Switches.Kind = GPR.List then
declare
Option : String_Access;
begin
Switch_List := Switches.Values;
while Switch_List /= Nil_String loop
Element :=
Project_Tree.Shared.String_Elements.Table
(Switch_List);
Get_Name_String (Element.Value);
if Name_Len > 0 then
Option :=
new String'
(Name_Buffer (1 .. Name_Len));
Test_If_Relative_Path
(Option,
Main_Project_Dir.all,
No_Name);
Put_Line (Exchange_File, Option.all);
end if;
Switch_List := Element.Next;
end loop;
end;
end if;
-- Then -P if in CodePeer mode
if Opt.CodePeer_Mode then
Put_Line (Exchange_File, "-P");
end if;
-- Then those on the command line, for all
-- binder drivers, if any.
for Option of All_Language_Binder_Options loop
Put_Line (Exchange_File, Option);
end loop;
-- Then -z if specified
if B_Data.Language_Name = Name_Ada
and then Opt.No_Main_Subprogram
then
Put_Line (Exchange_File, "-z");
end if;
-- Finally those on the command line for the
-- binder driver of the language
if Options_Instance /= No_Bind_Option_Table then
for Option of Options_Instance.all loop
Put_Line (Exchange_File, Option);
end loop;
end if;
end if;
end;
if Build_Script_Name /= null then
Put_Line
(Exchange_File,
Binding_Label (Script_Path) & ASCII.LF
& Build_Script_Name.all);
end if;
-- Finally, the list of the project paths with their
-- time stamps.
Put_Line
(Exchange_File,
Binding_Label (Project_Files) & ASCII.LF
-- The main project file is always the first one, so that
-- gprbind may know the main project dir.
& Get_Name_String (Main_Proj.Path.Display_Name) & ASCII.LF
& Get_Project_Checkline (Main_Proj));
Proj_List := Main_Proj.All_Imported_Projects;
while Proj_List /= null loop
if Main_Proj.Standalone_Library = Encapsulated
or else not Proj_List.From_Encapsulated_Lib
then
declare
Project : Project_Id := Proj_List.Project;
begin
while Project.Virtual
and then Project.Extends /= No_Project
loop
Project := Project.Extends;
end loop;
Put_Line
(Exchange_File,
Get_Name_String (Project.Path.Display_Name));
Put_Line
(Exchange_File, Get_Project_Checkline (Project));
end;
end if;
Proj_List := Proj_List.Next;
end loop;
if Main_Source.Unit = No_Unit_Index and then not Dep_Files then
Close (Exchange_File);
begin
Create (Exchange_File, Out_File, Bind_Exchange.all);
exception
when others =>
Fail_Program
(Project_Tree,
"unable to create binder exchange file "
& Bind_Exchange.all);
end;
Put_Line (Exchange_File, Binding_Label (Nothing_To_Bind));
Close (Exchange_File);
if Opt.Verbosity_Level > Opt.Low then
Put_Line (" -> nothing to bind");
end if;
else
Close (Exchange_File);
if B_Data.Language.Config.Objects_Path /= No_Name then
declare
Env_Var : constant String :=
Get_Name_String
(B_Data.Language.Config.
Objects_Path);
Path_Name : String_Access :=
Main_Proj.Objects_Path;
begin
if Path_Name = null then
if Current_Verbosity = High then
Put_Line (Env_Var & " :");
end if;
Get_Directories
(Project_Tree => Project_Tree,
For_Project => Main_Proj,
Activity => Executable_Binding,
Languages => No_Names);
Path_Name := Create_Path_From_Dirs;
Main_Proj.Objects_Path := Path_Name;
end if;
Setenv (Env_Var, Path_Name.all);
if Opt.Verbosity_Level > Opt.Low then
Put (Env_Var);
Put (" = ");
Put_Line (Path_Name.all);
end if;
end;
elsif B_Data.Language.Config.Objects_Path_File /= No_Name then
declare
Env_Var : constant String :=
Get_Name_String
(B_Data.Language.Config.
Objects_Path_File);
Path_Name : Path_Name_Type :=
Main_Proj.Objects_Path_File_Without_Libs;
begin
if Path_Name = No_Path then
if Current_Verbosity = High then
Put_Line (Env_Var & " :");
end if;
Get_Directories
(Project_Tree => Project_Tree,
For_Project => Main_Proj,
Activity => Executable_Binding,
Languages => No_Names);
declare
FD : File_Descriptor;
Len : Integer;
Status : Boolean;
begin
GPR.Env.Create_New_Path_File
(Shared => Project_Tree.Shared,
Path_FD => FD,
Path_Name =>
Main_Proj.Objects_Path_File_Without_Libs);
if FD = Invalid_FD then
Fail_Program
(Project_Tree,
"could not create temporary path file");
end if;
Path_Name :=
Main_Proj.Objects_Path_File_Without_Libs;
for Index in
1 .. Gpr_Build_Util.Directories.Last
loop
Get_Name_String
(Gpr_Build_Util.Directories.Table (Index));
if Current_Verbosity = High then
Put_Line (Name_Buffer (1 .. Name_Len));
end if;
Name_Len := Name_Len + 1;
Name_Buffer (Name_Len) := ASCII.LF;
Len :=
Write (FD, Name_Buffer (1)'Address, Name_Len);
if Len /= Name_Len then
Fail_Program (Project_Tree, "disk full");
end if;
end loop;
Close (FD, Status);
if not Status then
Fail_Program (Project_Tree, "disk full");
end if;
end;
end if;
Setenv (Env_Var, Get_Name_String (Path_Name));
if Opt.Verbosity_Level > Opt.Low then
Put (Env_Var);
Put (" = ");
Put_Line (Get_Name_String (Path_Name));
end if;
end;
end if;
if not Opt.Quiet_Output then
if Opt.Verbose_Mode then
Set_Name_Buffer (B_Data.Binder_Driver_Path.all);
Add_Str_To_Name_Buffer (" ");
Add_Str_To_Name_Buffer (Bind_Exchange.all);
Put_Line (Name_Buffer (1 .. Name_Len));
else
Display
(Section => GPR.Bind,
Command => Ada.Directories.Base_Name
(Ada.Directories.Simple_Name
(B_Data.Binder_Driver_Path.all)),
Argument => Bind_Exchange.all);
end if;
end if;
declare
Pid : Process_Id;
begin
Pid := Non_Blocking_Spawn
(B_Data.Binder_Driver_Path.all, (1 => Bind_Exchange));
if Pid = Invalid_Pid then
Put ("Can't start binder ");
Put_Line (B_Data.Binder_Driver_Path.all);
Record_Failure (Main_File);
else
Add_Process (Pid, (Binding, Main_File));
Display_Processes ("bind");
end if;
end;
end if;
end if;
end Bind_Language;
--------------------------
-- Get_Project_Checksum --
--------------------------
function Get_Project_Checksum
(Project : Project_Id) return Message_Digest
is
procedure Update_Vars (Items : Variable_Id);
Chk : Context;
Pkg : Package_Id := Project.Decl.Packages;
Tbl : Package_Table.Table_Ptr renames
Project_Tree.Shared.Packages.Table;
-----------------
-- Update_Vars --
-----------------
procedure Update_Vars (Items : Variable_Id) is
Vars : Variable_Id := Items;
Strs : String_List_Id;
Var : Variable;
Str : String_Element;
begin
while Vars /= No_Variable loop
Var := Project_Tree.Shared.Variable_Elements.Table (Vars);
Update (Chk, Get_Name_String (Var.Name));
case Var.Value.Kind is
when Single =>
Update (Chk, Get_Name_String (Var.Value.Value));
if Var.Value.Index /= 0 then
Update (Chk, Var.Value.Index'Img);
end if;
when List =>
Strs := Var.Value.Values;
while Strs /= Nil_String loop
Str := Project_Tree.Shared.String_Elements.Table
(Strs);
Update (Chk, Get_Name_String (Str.Value));
if Str.Index /= 0 then
Update (Chk, Str.Index'Img);
end if;
Strs := Str.Next;
end loop;
when Undefined => null;
end case;
Vars := Var.Next;
end loop;
end Update_Vars;
begin
Update_Vars (Project.Decl.Variables);
Update_Vars (Project.Decl.Attributes);
while Pkg /= No_Package loop
Update_Vars (Tbl (Pkg).Decl.Variables);
Update_Vars (Tbl (Pkg).Decl.Attributes);
Pkg := Tbl (Pkg).Next;
end loop;
Update (Chk, Hex_Image (Project.Checksum));
return Digest (Chk);
end Get_Project_Checksum;
-- Start of processing for Post_Compilation_Phase
begin
-- Build the libraries, if any
-- First, get the libraries in building order in table Library_Projs
Process_Imported_Libraries
(Main_Project,
There_Are_SALs => There_Are_Stand_Alone_Libraries,
And_Project_Itself => True);
if not Library_Projs.Is_Empty then
declare
Lib_Projs : array (1 .. Library_Projs.Last_Index) of
Library_Project;
Proj : Library_Project;
begin
-- Copy the list of library projects in local array Lib_Projs,
-- as procedure Build_Library uses table Library_Projs.
for J in Lib_Projs'Range loop
Lib_Projs (J) := Library_Projs (J);
end loop;
for J in Lib_Projs'Range loop
Proj := Lib_Projs (J);
if not Proj.Is_Aggregated then
-- Try building a library only if no error occurred in
-- library project and projects it depends on.
-- Do not actually create the library for aggregate projects
-- or in CodePeer mode or when generating C or Java byte
-- code, since there is no notion of library is this case,
-- only the rest of the processing (creation and compilation
-- of binder file in particular, possibly copying ALI files)
-- is useful.
if not Project_Compilation_Failed (Proj.Proj) then
if Proj.Proj.Extended_By = No_Project then
if not Proj.Proj.Externally_Built then
while Libs_Are_Building.Contains (Proj.Proj.Name)
loop
Wait_For_Slots_Less_Than (Outstanding_Processes);
end loop;
Build_Library
(Proj.Proj, Project_Tree,
No_Create =>
Proj.Is_Aggregated
or else Opt.CodePeer_Mode
or else No_Link_Target (Target_Name.all));
exit when Stop_Spawning;
end if;
if not Is_Static (Proj.Proj) then
Shared_Libs := True;
end if;
end if;
end if;
end if;
end loop;
end;
end if;
-- If no main is specified, there is nothing else to do
if Mains.Number_Of_Mains (Project_Tree) = 0 then
return;
end if;
-- Check if there is a need to call a binder driver
Find_Binding_Languages (Project_Tree, Main_Project);
-- Proceed to bind (or rebind if needed) for each main
Mains.Reset;
Wait_For_Slots_Less_Than (1);
loop
declare
Main_File : constant Main_Info := Mains.Next_Main;
begin
exit when Main_File = No_Main_Info;
if Main_File.Tree /= Project_Tree
or else Project_Compilation_Failed (Main_File.Project)
then
-- Will be processed later, or do not need any processing in
-- the case of compilation errors in the project.
null;
elsif
not Builder_Data (Main_File.Tree).There_Are_Binder_Drivers
then
if Current_Verbosity = High then
Debug_Output ("Post-compilation, no binding required for",
Debug_Name (Main_File.Tree));
end if;
else
declare
Main : constant String :=
Get_Name_String (Main_File.File);
Main_Id : constant File_Name_Type :=
Create_Name (Base_Name (Main));
Main_Base_Name_Index : constant File_Name_Type :=
Base_Name_Index_For
(Main, Main_File.Index,
Main_File.Source.Language.Config
.Multi_Unit_Object_Separator);
Main_Proj : constant Project_Id :=
Ultimate_Extending_Project_Of
(Main_File.Source.Project);
B_Data : Binding_Data :=
Builder_Data (Main_File.Tree).Binding;
begin
while B_Data /= null loop
if B_Data.Language.Config.Compiler_Driver /= Empty_File
then
Wait_For_Slots_Less_Than (Opt.Maximum_Binders);
exit when Stop_Spawning;
Change_To_Object_Directory (Main_Proj);
Bind_Language
(Main_Proj, Main, Main_Base_Name_Index,
Main_File, Main_Id, B_Data);
exit when Stop_Spawning;
end if;
B_Data := B_Data.Next;
end loop;
end;
end if;
end;
end loop;
end Post_Compilation_Phase;
------------------------------
-- Wait_For_Slots_Less_Then --
------------------------------
procedure Wait_For_Slots_Less_Than (Count : Positive) is
Data : Process_Data;
OK : Boolean;
begin
while Outstanding_Processes >= Count loop
Await_Process (Data, OK);
if Data /= No_Process_Data then
Libs_Are_Building.Exclude (Data.Main.Project.Name);
if OK then
Data.Main.Project.Was_Built := True;
else
Exit_Code := E_Subtool;
Record_Failure (Data.Main);
end if;
end if;
Display_Processes ("bind");
end loop;
end Wait_For_Slots_Less_Than;
end Gprbuild.Post_Compile;