aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/gnatcmd.adb
diff options
context:
space:
mode:
authorArnaud Charlet <charlet@gcc.gnu.org>2016-04-20 12:40:48 +0200
committerArnaud Charlet <charlet@gcc.gnu.org>2016-04-20 12:40:48 +0200
commit0c61772a122cc888d0aafffbaa35d4c95cc7abcc (patch)
treed453a67df3e66d1b84843f68fa59727adf489147 /gcc/ada/gnatcmd.adb
parent61d1b085b96c6f9aa6cc952e7161c4f0e41794c8 (diff)
downloadgcc-0c61772a122cc888d0aafffbaa35d4c95cc7abcc.zip
gcc-0c61772a122cc888d0aafffbaa35d4c95cc7abcc.tar.gz
gcc-0c61772a122cc888d0aafffbaa35d4c95cc7abcc.tar.bz2
[multiple changes]
2016-04-20 Vincent Celier <celier@adacore.com> * gnatcmd.adb: Do not invoke gprls when the invocation of "gnat ls" includes the switch -V. * clean.adb: "<target>-gnatclean -P" now calls "gprclean --target=<target>" * make.adb: "<target>-gnatmake -P" now calls "gprbuild --target=<target>" 2016-04-20 Hristian Kirtchev <kirtchev@adacore.com> * sem_ch12.adb (Qualify_Type): Do not perform partial qualification when the immediate scope is a generic unit. From-SVN: r235260
Diffstat (limited to 'gcc/ada/gnatcmd.adb')
-rw-r--r--gcc/ada/gnatcmd.adb603
1 files changed, 598 insertions, 5 deletions
diff --git a/gcc/ada/gnatcmd.adb b/gcc/ada/gnatcmd.adb
index 0d36566..2432f89 100644
--- a/gcc/ada/gnatcmd.adb
+++ b/gcc/ada/gnatcmd.adb
@@ -23,19 +23,35 @@
-- --
------------------------------------------------------------------------------
+with Csets;
with Gnatvsn;
+with Makeutl; use Makeutl;
with Namet; use Namet;
with Opt; use Opt;
with Osint; use Osint;
+with Output; use Output;
+with Prj; use Prj;
+with Prj.Env;
+with Prj.Ext; use Prj.Ext;
+with Prj.Pars;
+with Prj.Tree; use Prj.Tree;
+with Prj.Util; use Prj.Util;
+with Sdefault;
+with Sinput.P;
+with Snames; use Snames;
+with Stringt;
with Switch; use Switch;
with Table;
with Targparm; use Targparm;
+with Tempdir;
+with Types; use Types;
with Ada.Characters.Handling; use Ada.Characters.Handling;
with Ada.Command_Line; use Ada.Command_Line;
with Ada.Text_IO; use Ada.Text_IO;
-with GNAT.OS_Lib; use GNAT.OS_Lib;
+with GNAT.Directory_Operations; use GNAT.Directory_Operations;
+with GNAT.OS_Lib; use GNAT.OS_Lib;
procedure GNATCmd is
Gprbuild : constant String := "gprbuild";
@@ -82,6 +98,25 @@ procedure GNATCmd is
Pp => Pretty);
-- Mapping of alternate commands to commands
+ Call_GPR_Tool : Boolean := False;
+ -- True when a GPR tool should be called, if available
+
+ Project_Node_Tree : Project_Node_Tree_Ref;
+ Project_File : String_Access;
+ Project : Prj.Project_Id;
+ Current_Verbosity : Prj.Verbosity := Prj.Default;
+ Tool_Package_Name : Name_Id := No_Name;
+
+ Project_Tree : constant Project_Tree_Ref :=
+ new Project_Tree_Data (Is_Root_Tree => True);
+ -- The project tree
+
+ All_Projects : Boolean := False;
+
+ Temp_File_Name : Path_Name_Type := No_Path;
+ -- The name of the temporary text file to put a list of source/object
+ -- files to pass to a tool.
+
package First_Switches is new Table.Table
(Table_Component_Type => String_Access,
Table_Index_Type => Integer,
@@ -222,16 +257,177 @@ procedure GNATCmd is
Unixsws => null)
);
+ subtype SA is String_Access;
+
+ Naming_String : constant SA := new String'("naming");
+ Gnatls_String : constant SA := new String'("gnatls");
+
+ Packages_To_Check_By_Gnatls : constant String_List_Access :=
+ new String_List'((Naming_String, Gnatls_String));
+
+ Packages_To_Check : String_List_Access := Prj.All_Packages;
+
-----------------------
-- Local Subprograms --
-----------------------
+ procedure Check_Files;
+ -- For GNAT LIST -V, check if a project file is specified, without any file
+ -- arguments and without a switch -files=. If it is the case, invoke the
+ -- GNAT tool with the proper list of files, derived from the sources of
+ -- the project.
+
procedure Output_Version;
-- Output the version of this program
procedure Usage;
-- Display usage
+ -----------------
+ -- Check_Files --
+ -----------------
+
+ procedure Check_Files is
+ Add_Sources : Boolean := True;
+ Unit : Prj.Unit_Index;
+ Subunit : Boolean := False;
+ FD : File_Descriptor := Invalid_FD;
+ Status : Integer;
+ Success : Boolean;
+
+ procedure Add_To_Response_File
+ (File_Name : String;
+ Check_File : Boolean := True);
+ -- Include the file name passed as parameter in the response file for
+ -- the tool being called. If the response file can not be written then
+ -- the file name is passed in the parameter list of the tool. If the
+ -- Check_File parameter is True then the procedure verifies the
+ -- existence of the file before adding it to the response file.
+
+ --------------------------
+ -- Add_To_Response_File --
+ --------------------------
+
+ procedure Add_To_Response_File
+ (File_Name : String;
+ Check_File : Boolean := True)
+ is
+ begin
+ Name_Len := 0;
+
+ Add_Str_To_Name_Buffer (File_Name);
+
+ if not Check_File or else
+ Is_Regular_File (Name_Buffer (1 .. Name_Len))
+ then
+ if FD /= Invalid_FD then
+ Name_Len := Name_Len + 1;
+ Name_Buffer (Name_Len) := ASCII.LF;
+
+ Status := Write (FD, Name_Buffer (1)'Address, Name_Len);
+
+ if Status /= Name_Len then
+ Osint.Fail ("disk full");
+ end if;
+ else
+ Last_Switches.Increment_Last;
+ Last_Switches.Table (Last_Switches.Last) :=
+ new String'(File_Name);
+ end if;
+ end if;
+ end Add_To_Response_File;
+
+ -- Start of processing for Check_Files
+
+ begin
+ -- Check if there is at least one argument that is not a switch
+
+ for Index in 1 .. Last_Switches.Last loop
+ if Last_Switches.Table (Index) (1) /= '-'
+ or else (Last_Switches.Table (Index).all'Length > 7
+ and then Last_Switches.Table (Index) (1 .. 7) = "-files=")
+ then
+ Add_Sources := False;
+ exit;
+ end if;
+ end loop;
+
+ -- If all arguments are switches and there is no switch -files=, add the
+ -- path names of all the sources of the main project.
+
+ if Add_Sources then
+ Tempdir.Create_Temp_File (FD, Temp_File_Name);
+ Last_Switches.Increment_Last;
+ Last_Switches.Table (Last_Switches.Last) :=
+ new String'("-files=" & Get_Name_String (Temp_File_Name));
+
+ Unit := Units_Htable.Get_First (Project_Tree.Units_HT);
+ while Unit /= No_Unit_Index loop
+
+ -- We only need to put the library units, body or spec, but not
+ -- the subunits.
+
+ if Unit.File_Names (Impl) /= null
+ and then not Unit.File_Names (Impl).Locally_Removed
+ then
+ -- There is a body, check if it is for this project
+
+ if All_Projects
+ or else Unit.File_Names (Impl).Project = Project
+ then
+ Subunit := False;
+
+ if Unit.File_Names (Spec) = null
+ or else Unit.File_Names (Spec).Locally_Removed
+ then
+ -- We have a body with no spec: we need to check if
+ -- this is a subunit, because gnatls will complain
+ -- about subunits.
+
+ declare
+ Src_Ind : constant Source_File_Index :=
+ Sinput.P.Load_Project_File
+ (Get_Name_String
+ (Unit.File_Names (Impl).Path.Name));
+ begin
+ Subunit := Sinput.P.Source_File_Is_Subunit (Src_Ind);
+ end;
+ end if;
+
+ if not Subunit then
+ Add_To_Response_File
+ (Get_Name_String (Unit.File_Names (Impl).Display_File),
+ Check_File => False);
+ end if;
+ end if;
+
+ elsif Unit.File_Names (Spec) /= null
+ and then not Unit.File_Names (Spec).Locally_Removed
+ then
+ -- We have a spec with no body. Check if it is for this project
+
+ if All_Projects
+ or else Unit.File_Names (Spec).Project = Project
+ then
+ Add_To_Response_File
+ (Get_Name_String (Unit.File_Names (Spec).Display_File),
+ Check_File => False);
+ end if;
+ end if;
+
+ Unit := Units_Htable.Get_Next (Project_Tree.Units_HT);
+ end loop;
+
+ if FD /= Invalid_FD then
+ Close (FD, Success);
+
+ if not Success then
+ Osint.Fail ("disk full");
+ end if;
+ end if;
+ end if;
+ end Check_Files;
+
--------------------
-- Output_Version --
--------------------
@@ -293,8 +489,23 @@ procedure GNATCmd is
-- Start of processing for GNATCmd
begin
+ -- All output from GNATCmd is debugging or error output: send to stderr
+
+ Set_Standard_Error;
+
-- Initializations
+ Csets.Initialize;
+ Snames.Initialize;
+ Stringt.Initialize;
+
+ Prj.Tree.Initialize (Root_Environment, Gnatmake_Flags);
+
+ Project_Node_Tree := new Project_Node_Tree_Data;
+ Prj.Tree.Initialize (Project_Node_Tree);
+
+ Prj.Initialize (Project_Tree);
+
Last_Switches.Init;
Last_Switches.Set_Last (0);
@@ -485,21 +696,27 @@ begin
or else The_Command = List
then
declare
- Project_File_Used : Boolean := False;
Switch : String_Access;
+ Dash_V_Switch : constant String := "-V";
begin
for J in 1 .. Last_Switches.Last loop
Switch := Last_Switches.Table (J);
+
+ if The_Command = List and then Switch.all = Dash_V_Switch
+ then
+ Call_GPR_Tool := False;
+ exit;
+ end if;
+
if Switch'Length >= 2
and then Switch (Switch'First .. Switch'First + 1) = "-P"
then
- Project_File_Used := True;
- exit;
+ Call_GPR_Tool := True;
end if;
end loop;
- if Project_File_Used then
+ if Call_GPR_Tool then
case The_Command is
when Make | Compile | Bind | Link =>
if Locate_Exec_On_Path (Gprbuild) /= null then
@@ -602,6 +819,382 @@ begin
end;
end if;
+ if The_Command = List and then not Call_GPR_Tool then
+ Tool_Package_Name := Name_Gnatls;
+ Packages_To_Check := Packages_To_Check_By_Gnatls;
+
+ -- Check that the switches are consistent. Detect project file
+ -- related switches.
+
+ Inspect_Switches : declare
+ Arg_Num : Positive := 1;
+ Argv : String_Access;
+
+ procedure Remove_Switch (Num : Positive);
+ -- Remove a project related switch from table Last_Switches
+
+ -------------------
+ -- Remove_Switch --
+ -------------------
+
+ procedure Remove_Switch (Num : Positive) is
+ begin
+ Last_Switches.Table (Num .. Last_Switches.Last - 1) :=
+ Last_Switches.Table (Num + 1 .. Last_Switches.Last);
+ Last_Switches.Decrement_Last;
+ end Remove_Switch;
+
+ -- Start of processing for Inspect_Switches
+
+ begin
+ while Arg_Num <= Last_Switches.Last loop
+ Argv := Last_Switches.Table (Arg_Num);
+
+ if Argv (Argv'First) = '-' then
+ if Argv'Length = 1 then
+ Fail ("switch character cannot be followed by a blank");
+ end if;
+
+ -- --subdirs=... Specify Subdirs
+
+ if Argv'Length > Makeutl.Subdirs_Option'Length
+ and then
+ Argv
+ (Argv'First ..
+ Argv'First + Makeutl.Subdirs_Option'Length - 1) =
+ Makeutl.Subdirs_Option
+ then
+ Subdirs :=
+ new String'
+ (Argv (Argv'First + Makeutl.Subdirs_Option'Length ..
+ Argv'Last));
+
+ Remove_Switch (Arg_Num);
+
+ -- -aPdir Add dir to the project search path
+
+ elsif Argv'Length > 3
+ and then Argv (Argv'First + 1 .. Argv'First + 2) = "aP"
+ then
+ Prj.Env.Add_Directories
+ (Root_Environment.Project_Path,
+ Argv (Argv'First + 3 .. Argv'Last));
+
+ -- Pass -aPdir to gnatls, but not to other tools
+
+ if The_Command = List then
+ Arg_Num := Arg_Num + 1;
+ else
+ Remove_Switch (Arg_Num);
+ end if;
+
+ -- -eL Follow links for files
+
+ elsif Argv.all = "-eL" then
+ Follow_Links_For_Files := True;
+ Follow_Links_For_Dirs := True;
+
+ Remove_Switch (Arg_Num);
+
+ -- -vPx Specify verbosity while parsing project files
+
+ elsif Argv'Length >= 3
+ and then Argv (Argv'First + 1 .. Argv'First + 2) = "vP"
+ then
+ if Argv'Length = 4
+ and then Argv (Argv'Last) in '0' .. '2'
+ then
+ case Argv (Argv'Last) is
+ when '0' =>
+ Current_Verbosity := Prj.Default;
+ when '1' =>
+ Current_Verbosity := Prj.Medium;
+ when '2' =>
+ Current_Verbosity := Prj.High;
+ when others =>
+
+ -- Cannot happen
+
+ raise Program_Error;
+ end case;
+ else
+ Fail ("invalid verbosity level: "
+ & Argv (Argv'First + 3 .. Argv'Last));
+ end if;
+
+ Remove_Switch (Arg_Num);
+
+ -- -Pproject_file Specify project file to be used
+
+ elsif Argv (Argv'First + 1) = 'P' then
+
+ -- Only one -P switch can be used
+
+ if Project_File /= null then
+ Fail
+ (Argv.all
+ & ": second project file forbidden (first is """
+ & Project_File.all & """)");
+
+ elsif Argv'Length = 2 then
+
+ -- There is space between -P and the project file
+ -- name. -P cannot be the last option.
+
+ if Arg_Num = Last_Switches.Last then
+ Fail ("project file name missing after -P");
+
+ else
+ Remove_Switch (Arg_Num);
+ Argv := Last_Switches.Table (Arg_Num);
+
+ -- After -P, there must be a project file name,
+ -- not another switch.
+
+ if Argv (Argv'First) = '-' then
+ Fail ("project file name missing after -P");
+
+ else
+ Project_File := new String'(Argv.all);
+ end if;
+ end if;
+
+ else
+ -- No space between -P and project file name
+
+ Project_File :=
+ new String'(Argv (Argv'First + 2 .. Argv'Last));
+ end if;
+
+ Remove_Switch (Arg_Num);
+
+ -- -Xexternal=value Specify an external reference to be
+ -- used in project files
+
+ elsif Argv'Length >= 5
+ and then Argv (Argv'First + 1) = 'X'
+ then
+ if not Check (Root_Environment.External,
+ Argv (Argv'First + 2 .. Argv'Last))
+ then
+ Fail
+ (Argv.all & " is not a valid external assignment.");
+ end if;
+
+ Remove_Switch (Arg_Num);
+
+ elsif
+ The_Command = List
+ and then Argv'Length = 2
+ and then Argv (2) = 'U'
+ then
+ All_Projects := True;
+ Remove_Switch (Arg_Num);
+
+ else
+ Arg_Num := Arg_Num + 1;
+ end if;
+
+ else
+ Arg_Num := Arg_Num + 1;
+ end if;
+ end loop;
+ end Inspect_Switches;
+ end if;
+
+ -- Add the default project search directories now, after the directories
+ -- that have been specified by switches -aP<dir>.
+
+ Prj.Env.Initialize_Default_Project_Path
+ (Root_Environment.Project_Path,
+ Target_Name => Sdefault.Target_Name.all);
+
+ -- If there is a project file specified, parse it, get the switches
+ -- for the tool and setup PATH environment variables.
+
+ if Project_File /= null then
+ Prj.Pars.Set_Verbosity (To => Current_Verbosity);
+
+ Prj.Pars.Parse
+ (Project => Project,
+ In_Tree => Project_Tree,
+ In_Node_Tree => Project_Node_Tree,
+ Project_File_Name => Project_File.all,
+ Env => Root_Environment,
+ Packages_To_Check => Packages_To_Check);
+
+ -- Prj.Pars.Parse calls Set_Standard_Output, reset to stderr
+
+ Set_Standard_Error;
+
+ if Project = Prj.No_Project then
+ Fail ("""" & Project_File.all & """ processing failed");
+
+ elsif Project.Qualifier = Aggregate then
+ Fail ("aggregate projects are not supported");
+
+ elsif Aggregate_Libraries_In (Project_Tree) then
+ Fail ("aggregate library projects are not supported");
+ end if;
+
+ -- Check if a package with the name of the tool is in the project
+ -- file and if there is one, get the switches, if any, and scan them.
+
+ declare
+ Pkg : constant Prj.Package_Id :=
+ Prj.Util.Value_Of
+ (Name => Tool_Package_Name,
+ In_Packages => Project.Decl.Packages,
+ Shared => Project_Tree.Shared);
+
+ Element : Package_Element;
+
+ Switches_Array : Array_Element_Id;
+
+ The_Switches : Prj.Variable_Value;
+ Current : Prj.String_List_Id;
+ The_String : String_Element;
+
+ Main : String_Access := null;
+
+ begin
+ if Pkg /= No_Package then
+ Element := Project_Tree.Shared.Packages.Table (Pkg);
+
+ -- Package Gnatls has a single attribute Switches, that is not
+ -- an associative array.
+
+ if The_Command = List then
+ The_Switches :=
+ Prj.Util.Value_Of
+ (Variable_Name => Snames.Name_Switches,
+ In_Variables => Element.Decl.Attributes,
+ Shared => Project_Tree.Shared);
+
+ -- Packages Binder (for gnatbind), Cross_Reference (for
+ -- gnatxref), Linker (for gnatlink), Finder (for gnatfind),
+ -- have an attributed Switches, an associative array, indexed
+ -- by the name of the file.
+
+ -- They also have an attribute Default_Switches, indexed by the
+ -- name of the programming language.
+
+ else
+ -- First check if there is a single main
+
+ for J in 1 .. Last_Switches.Last loop
+ if Last_Switches.Table (J) (1) /= '-' then
+ if Main = null then
+ Main := Last_Switches.Table (J);
+ else
+ Main := null;
+ exit;
+ end if;
+ end if;
+ end loop;
+
+ if Main /= null then
+ Switches_Array :=
+ Prj.Util.Value_Of
+ (Name => Name_Switches,
+ In_Arrays => Element.Decl.Arrays,
+ Shared => Project_Tree.Shared);
+ Name_Len := 0;
+
+ -- If the single main has been specified as an absolute
+ -- path, use only the simple file name. If the absolute
+ -- path is incorrect, an error will be reported by the
+ -- underlying tool and it does not make a difference
+ -- what switches are used.
+
+ if Is_Absolute_Path (Main.all) then
+ Add_Str_To_Name_Buffer (File_Name (Main.all));
+ else
+ Add_Str_To_Name_Buffer (Main.all);
+ end if;
+
+ The_Switches := Prj.Util.Value_Of
+ (Index => Name_Find,
+ Src_Index => 0,
+ In_Array => Switches_Array,
+ Shared => Project_Tree.Shared);
+ end if;
+
+ if The_Switches.Kind = Prj.Undefined then
+ Switches_Array :=
+ Prj.Util.Value_Of
+ (Name => Name_Default_Switches,
+ In_Arrays => Element.Decl.Arrays,
+ Shared => Project_Tree.Shared);
+ The_Switches := Prj.Util.Value_Of
+ (Index => Name_Ada,
+ Src_Index => 0,
+ In_Array => Switches_Array,
+ Shared => Project_Tree.Shared);
+ end if;
+ end if;
+
+ -- If there are switches specified in the package of the
+ -- project file corresponding to the tool, scan them.
+
+ case The_Switches.Kind is
+ when Prj.Undefined =>
+ null;
+
+ when Prj.Single =>
+ declare
+ Switch : constant String :=
+ Get_Name_String (The_Switches.Value);
+ begin
+ if Switch'Length > 0 then
+ First_Switches.Increment_Last;
+ First_Switches.Table (First_Switches.Last) :=
+ new String'(Switch);
+ end if;
+ end;
+
+ when Prj.List =>
+ Current := The_Switches.Values;
+ while Current /= Prj.Nil_String loop
+ The_String := Project_Tree.Shared.String_Elements.
+ Table (Current);
+
+ declare
+ Switch : constant String :=
+ Get_Name_String (The_String.Value);
+ begin
+ if Switch'Length > 0 then
+ First_Switches.Increment_Last;
+ First_Switches.Table (First_Switches.Last) :=
+ new String'(Switch);
+ end if;
+ end;
+
+ Current := The_String.Next;
+ end loop;
+ end case;
+ end if;
+ end;
+
+ if The_Command = Bind or else The_Command = Link then
+ if Project.Object_Directory.Name = No_Path then
+ Fail ("project " & Get_Name_String (Project.Display_Name)
+ & " has no object directory");
+ end if;
+
+ Change_Dir (Get_Name_String (Project.Object_Directory.Name));
+ end if;
+
+ -- Set up the env vars for project path files
+
+ Prj.Env.Set_Ada_Paths
+ (Project, Project_Tree, Including_Libraries => True);
+
+ if The_Command = List then
+ Check_Files;
+ end if;
+ end if;
+
-- Gather all the arguments and invoke the executable
declare