diff options
author | no-author <no-author@gcc.gnu.org> | 2004-05-11 21:47:35 +0000 |
---|---|---|
committer | no-author <no-author@gcc.gnu.org> | 2004-05-11 21:47:35 +0000 |
commit | 1f5fc57715343ff68d261d0ee73791d1796a9aea (patch) | |
tree | 7623057c8b40aebd4acc70a3ddd0dab3e96e41fd | |
parent | 2e540937dc1e51f8237bec86eca1b97aa82c0773 (diff) |
This commit was manufactured by cvs2svn to create branch
'tree-ssa-20020619-branch'.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/tree-ssa-20020619-branch@81720 138bc75d-0d04-0410-961f-82ee72b054a4
30 files changed, 6030 insertions, 0 deletions
diff --git a/gcc/ada/gprmake.adb b/gcc/ada/gprmake.adb new file mode 100644 index 00000000000..dc8a659b0b3 --- /dev/null +++ b/gcc/ada/gprmake.adb @@ -0,0 +1,36 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- G P R M A K E -- +-- -- +-- B o d y -- +-- -- +-- Copyright (C) 2004 Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 2, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- 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, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +-- The driver for the gprmake tool. + +with Makegpr; + +procedure Gprmake is +begin + -- The code is in Makegpr + + Makegpr.Gprmake; +end Gprmake; diff --git a/gcc/ada/makegpr.adb b/gcc/ada/makegpr.adb new file mode 100644 index 00000000000..a881bc30d49 --- /dev/null +++ b/gcc/ada/makegpr.adb @@ -0,0 +1,3574 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- M A K E G P R -- +-- -- +-- B o d y -- +-- -- +-- Copyright (C) 2004 Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 2, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- 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, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +with Ada.Command_Line; use Ada.Command_Line; +with Ada.Strings.Fixed; use Ada.Strings.Fixed; +with Ada.Text_IO; use Ada.Text_IO; +with Ada.Unchecked_Deallocation; + +with Csets; +with Gnatvsn; + +with GNAT.Directory_Operations; use GNAT.Directory_Operations; +with GNAT.Dynamic_Tables; +with GNAT.Expect; use GNAT.Expect; +with GNAT.HTable; +with GNAT.OS_Lib; use GNAT.OS_Lib; +with GNAT.Regpat; use GNAT.Regpat; + +with Makeutl; use Makeutl; +with MLib.Tgt; use MLib.Tgt; +with Namet; use Namet; +with Output; use Output; +with Opt; use Opt; +with Osint; use Osint; +with Prj; use Prj; +with Prj.Com; use Prj.Com; +with Prj.Pars; +with Prj.Util; use Prj.Util; +with Snames; use Snames; +with System; +with System.Case_Util; use System.Case_Util; +with Table; +with Types; use Types; + +package body Makegpr is + + Max_In_Archives : constant := 50; + -- The maximum number of arguments for a single invocation of the + -- Archive Indexer (ar). + + Cpp_Linker : constant String := "c++linker"; + -- The name of a linking script, built one the fly, when there are C++ + -- sources and the C++ compiler is not g++. + + No_Argument : constant Argument_List := (1 .. 0 => null); + + FD : Process_Descriptor; + -- The process descriptor used when invoking a non GNU compiler with -M + -- and getting the output with GNAT.Expect. + + Line_Matcher : constant Pattern_Matcher := + Compile ("^.*?\n", Single_Line); + -- The pattern when using GNAT.Expect for the invocation of a non GNU + -- compiler with -M. + + Name_Ide : Name_Id; + Name_Compiler_Command : Name_Id; + -- Names of package IDE and its attribute Compiler_Command. + -- Set up by Initialize. + + Unique_Compile : Boolean := False; + -- True when switch -u is used on the command line + + type Source_Index_Rec is record + Id : Other_Source_Id; + Found : Boolean := False; + end record; + -- Used as component of Source_Indexes, to check if an archive need to + -- be rebuilt. + + type Source_Index_Array is array (Positive range <>) of Source_Index_Rec; + type Source_Indexes_Ref is access Source_Index_Array; + + procedure Free is new Ada.Unchecked_Deallocation + (Source_Index_Array, Source_Indexes_Ref); + + Initial_Source_Index_Count : constant Positive := 20; + Source_Indexes : Source_Indexes_Ref := + new Source_Index_Array (1 .. Initial_Source_Index_Count); + -- A list of the Other_Source_Ids of a project file, with an indication + -- that they have been found in the archive dependency file. + + Last_Source : Natural := 0; + -- The index of the last valid component of Source_Indexes + + Compiler_Names : array (Programming_Language) of String_Access; + -- The names of the compilers to be used. Set up by Get_Compiler. + -- Used to display the commands spawned. + + Compiler_Paths : array (Programming_Language) of String_Access; + -- The path names of the compiler to be used. Set up by Get_Compiler. + -- Used to spawn compiling/linking processes. + + Compiler_Is_Gcc : array (Programming_Language) of Boolean; + -- An indication that a compiler is a GCC compiler, to be able to use + -- specific GCC switches. + + Archive_Builder_Path : String_Access := null; + -- The path name of the archive builder (ar). To be used when spawning + -- ar commands. + + Archive_Indexer_Path : String_Access := null; + -- The path name of the archive indexer (ranlib), if it exists. + + Copyright_Output : Boolean := False; + Usage_Output : Boolean := False; + -- Flags to avoid multiple displays of the Copyright notice and of the + -- Usage. + + Output_File_Name : String_Access := null; + -- The name given after a switch -o + + Output_File_Name_Expected : Boolean := False; + -- True when last switch was -o + + Project_File_Name : String_Access := null; + -- The name of the project file specified with switch -P + + Project_File_Name_Expected : Boolean := False; + -- True when last switch was -P + + Naming_String : aliased String := "naming"; + Builder_String : aliased String := "builder"; + Compiler_String : aliased String := "compiler"; + Binder_String : aliased String := "binder"; + Linker_String : aliased String := "linker"; + -- Name of packages to be checked when parsing/processing project files + + List_Of_Packages : aliased String_List := + (Naming_String 'Access, + Builder_String 'Access, + Compiler_String 'Access, + Binder_String 'Access, + Linker_String 'Access); + Packages_To_Check : constant String_List_Access := List_Of_Packages'Access; + -- List of the packages to be checked when parsing/processing project + -- files. + + Main_Project : Project_Id; + -- The project id of the main project + + type Processor is (None, Linker, Compiler); + Current_Processor : Processor := None; + -- This variable changes when switches -*args are used + + Current_Language : Programming_Language := Lang_Ada; + -- The compiler language to consider when Processor is Compiler + + package Comp_Opts is new GNAT.Dynamic_Tables + (Table_Component_Type => String_Access, + Table_Index_Type => Integer, + Table_Low_Bound => 1, + Table_Initial => 20, + Table_Increment => 100); + Options : array (Programming_Language) of Comp_Opts.Instance; + -- Tables to store compiling options for the different compilers + + package Linker_Options is new Table.Table + (Table_Component_Type => String_Access, + Table_Index_Type => Integer, + Table_Low_Bound => 1, + Table_Initial => 20, + Table_Increment => 100, + Table_Name => "Makegpr.Linker_Options"); + -- Table to store the linking options + + package Ada_Mains is new Table.Table + (Table_Component_Type => String_Access, + Table_Index_Type => Integer, + Table_Low_Bound => 1, + Table_Initial => 20, + Table_Increment => 100, + Table_Name => "Makegpr.Ada_Mains"); + -- Table to store the Ada mains, either specified on the command line + -- or found in attribute Main of the main project file. + + package Other_Mains is new Table.Table + (Table_Component_Type => Other_Source, + Table_Index_Type => Integer, + Table_Low_Bound => 1, + Table_Initial => 20, + Table_Increment => 100, + Table_Name => "Makegpr.Other_Mains"); + -- Table to store the mains of languages other than Ada, either specified + -- on the command line or found in attribute Main of the main project file. + + package Sources_Compiled is new GNAT.HTable.Simple_HTable + (Header_Num => Header_Num, + Element => Boolean, + No_Element => False, + Key => Name_Id, + Hash => Hash, + Equal => "="); + + Initial_Argument_Count : constant Positive := 20; + type Boolean_Array is array (Positive range <>) of Boolean; + type Booleans is access Boolean_Array; + + procedure Free is new Ada.Unchecked_Deallocation (Boolean_Array, Booleans); + + Arguments : Argument_List_Access := + new Argument_List (1 .. Initial_Argument_Count); + -- Used to store lists of arguments to be used when spawning a process + + Arguments_Displayed : Booleans := + new Boolean_Array (1 .. Initial_Argument_Count); + -- For each argument in Arguments, indicate if the argument should be + -- displayed when procedure Display_Command is called. + + Last_Argument : Natural := 0; + -- Index of the last valid argument in Arguments + + package Cache_Args is new Table.Table + (Table_Component_Type => String_Access, + Table_Index_Type => Integer, + Table_Low_Bound => 1, + Table_Initial => 200, + Table_Increment => 50, + Table_Name => "Makegpr.Cache_Args"); + -- A table to cache arguments, to avoid multiple allocation of the same + -- strings. It is not possible to use a hash table, because String is + -- an unconstrained type. + + -- Various switches used when spawning processes: + + Dash_B_String : aliased String := "-B"; + Dash_B : constant String_Access := Dash_B_String'Access; + Dash_c_String : aliased String := "-c"; + Dash_c : constant String_Access := Dash_c_String'Access; + Dash_cargs_String : aliased String := "-cargs"; + Dash_cargs : constant String_Access := Dash_cargs_String'Access; + Dash_f_String : aliased String := "-f"; + Dash_f : constant String_Access := Dash_f_String'Access; + Dash_k_String : aliased String := "-k"; + Dash_k : constant String_Access := Dash_k_String'Access; + Dash_largs_String : aliased String := "-largs"; + Dash_largs : constant String_Access := Dash_largs_String'Access; + Dash_M_String : aliased String := "-M"; + Dash_M : constant String_Access := Dash_M_String'Access; + Dash_margs_String : aliased String := "-margs"; + Dash_margs : constant String_Access := Dash_margs_String'Access; + Dash_o_String : aliased String := "-o"; + Dash_o : constant String_Access := Dash_o_String'Access; + Dash_P_String : aliased String := "-P"; + Dash_P : constant String_Access := Dash_P_String'Access; + Dash_q_String : aliased String := "-q"; + Dash_q : constant String_Access := Dash_q_String'Access; + Dash_u_String : aliased String := "-u"; + Dash_u : constant String_Access := Dash_u_String'Access; + Dash_v_String : aliased String := "-v"; + Dash_v : constant String_Access := Dash_v_String'Access; + Dash_vP1_String : aliased String := "-vP1"; + Dash_vP1 : constant String_Access := Dash_vP1_String'Access; + Dash_vP2_String : aliased String := "-vP2"; + Dash_vP2 : constant String_Access := Dash_vP2_String'Access; + Dash_x_String : aliased String := "-x"; + Dash_x : constant String_Access := Dash_x_String'Access; + r_String : aliased String := "r"; + r : constant String_Access := r_String'Access; + + CPATH : constant String := "CPATH"; + -- The environment variable to set when compiler is a GCC compiler + -- to indicate the include directory path. + + Current_Include_Paths : array (Programming_Language) of String_Access; + -- A cache for the paths of included directories, to avoid setting + -- env var CPATH unnecessarily. + + C_Plus_Plus_Is_Used : Boolean := False; + -- True when there are sources in C++ + + Link_Options_Switches : Argument_List_Access := null; + -- The link options coming from the attributes Linker'Linker_Options in + -- project files imported, directly or indirectly, by the main project. + + Total_Number_Of_Errors : Natural := 0; + -- Used when Keep_Going is True (switch -k) to keep the total number + -- of compilation/linking errors, to report at the end of execution. + + Error_Header : constant String := "*** ERROR: "; + -- The beginning of error message, when Keep_Going is True + + Need_To_Relink : Boolean := False; + -- True when an executable of a language other than Ada need to be linked + + Path_Option : String_Access; + -- The path option switch, when supported + + package Lib_Path is new Table.Table + (Table_Component_Type => Character, + Table_Index_Type => Integer, + Table_Low_Bound => 1, + Table_Initial => 200, + Table_Increment => 50, + Table_Name => "Makegpr.Lib_Path"); + -- A table to compute the path to put in the path option switch, when it + -- is supported. + + procedure Add_Archives (For_Gnatmake : Boolean); + -- Add to Arguments the list of archives for linking an executable + + procedure Add_Argument (Arg : String_Access; Display : Boolean); + procedure Add_Argument (Arg : String; Display : Boolean); + -- Add an argument to Arguments. Reallocate if necessary. + + procedure Add_Arguments (Args : Argument_List; Display : Boolean); + -- Add a list of arguments to Arguments. Reallocate if necessary + + procedure Add_Option (Arg : String); + -- Add a switch for the Ada, C or C++ compiler, or for the linker. + -- The table where this option is stored depends on the values of + -- Current_Processor and Current_Language. + + procedure Add_Search_Directories + (Data : Project_Data; Language : Programming_Language); + -- Either add to the Arguments the necessary -I switches needed to + -- compile, or, when compiler is gcc/g++, set up the C*INCLUDE_PATH + -- environment variable, if necessary. + + procedure Add_Source_Id (Id : Other_Source_Id); + -- Add a source id to Source_Indexes, with Found set to False + + procedure Add_Switches + (Data : Project_Data; + Proc : Processor; + Language : Other_Programming_Language; + File_Name : Name_Id); + -- Add to Arguments the switches, if any, for a source (attribute Switches) + -- or language (attribute Default_Switches), coming from package Compiler + -- or Linker (depending on Proc) of a specified project file. + + procedure Build_Archive (Project : Project_Id; Unconditionally : Boolean); + -- Build the archive for a specified project. If Unconditionally is + -- False, first check if the archive is up to date, and build it only + -- if it is not. + + procedure Check_Compilation_Needed + (Source : Other_Source; + Need_To_Compile : out Boolean); + -- Check if a source of a language other than Ada needs to be compiled or + -- recompiled. + + procedure Check_For_C_Plus_Plus; + -- Check if C++ is used in at least one project + + procedure Compile + (Source_Id : Other_Source_Id; + Data : Project_Data; + Local_Errors : in out Boolean); + + procedure Compile_Individual_Sources; + -- Compile the sources specified on the command line, when in + -- Unique_Compile mode. + + procedure Compile_Link_With_Gnatmake (Mains_Specified : Boolean); + -- Compile/Link with gnatmake when there are Ada sources in the main + -- project. Arguments may already contain options to be used by + -- gnatmake. Used for both Ada mains and mains of other languages. + -- When Compile_Only is True, do not use the linking options + + procedure Compile_Sources; + -- Compile the sources of languages other than Ada, if necessary + + procedure Copyright; + -- Output the Copyright notice + + procedure Create_Archive_Dependency_File + (Name : String; + First_Source : Other_Source_Id); + -- ??? needs comment + + procedure Display_Command (Name : String; Path : String_Access); + -- Display the command for a spawned process, if in Verbose_Mode or + -- not in Quiet_Output. + + procedure Get_Compiler (For_Language : Programming_Language); + -- Find the compiler name and path name for a specified programming + -- language, if not already done. Results are in the corresponding + -- elements of arrays Compiler_Names and Compiler_Paths. Name of compiler + -- is found in package IDE of the main project, or defaulted. + -- Fail if compiler cannot be found on the path. For the Ada language, + -- gnatmake, rather than the Ada compiler is returned. + + procedure Get_Imported_Directories + (Project : Project_Id; + Data : in out Project_Data); + -- Find the necessary switches -I to be used when compiling sources + -- of languages other than Ada, in a specified project file. Cache the + -- result in component Imported_Directories_Switches of the project data. + -- For gcc/g++ compilers, get the value of the C*_INCLUDE_PATH, instead. + + procedure Initialize; + -- Do the necessary package initialization and process the command line + -- arguments. + + procedure Link_Executables; + -- Link executables + + procedure Report_Error (S1 : String; S2 : String := ""; S3 : String := ""); + -- Report an error. If Keep_Going is False, just call Osint.Fail. + -- If Keep_Going is True, display the error and increase the total number + -- of errors. + + procedure Report_Total_Errors (Kind : String); + -- If Total_Number_Of_Errors is not zero, report it, and fail + + procedure Scan_Arg (Arg : String); + -- Process one command line argument + + function Strip_CR_LF (Text : String) return String; + -- Needs comment ??? + + procedure Usage; + -- Display the usage + + ------------------ + -- Add_Archives -- + ------------------ + + procedure Add_Archives (For_Gnatmake : Boolean) is + Last_Arg : constant Natural := Last_Argument; + -- The position of the last argument before adding the archives. + -- Used to reverse the order of the arguments added when processing + -- the archives. + + procedure Recursive_Add_Archives (Project : Project_Id); + -- Recursive procedure to add the archive of a project file, if any, + -- then call itself for the project imported. + + ---------------------------- + -- Recursive_Add_Archives -- + ---------------------------- + + procedure Recursive_Add_Archives (Project : Project_Id) is + Data : Project_Data; + Imported : Project_List; + Prj : Project_Id; + + begin + -- Nothing to do when there is no project specified + + if Project /= No_Project then + Data := Projects.Table (Project); + + -- Nothing to do if the project has already been processed + + if not Data.Seen then + + -- Mark the project as processed, to avoid processing it again + + Projects.Table (Project).Seen := True; + + Recursive_Add_Archives (Data.Extends); + + Imported := Data.Imported_Projects; + + -- Call itself recursively for all imported projects + + while Imported /= Empty_Project_List loop + Prj := Project_Lists.Table (Imported).Project; + + if Prj /= No_Project then + while Projects.Table (Prj).Extended_By /= No_Project loop + Prj := Projects.Table (Prj).Extended_By; + end loop; + + Recursive_Add_Archives (Prj); + end if; + + Imported := Project_Lists.Table (Imported).Next; + end loop; + + -- If there is sources of language other than Ada in this + -- project, add the path of the archive to Arguments. + + if Data.Sources_Present then + if Data.Library then + + -- If it is a library project file, nothing to do if + -- gnatmake will be invoked, because gnatmake will take + -- care of it, even if the library is not an Ada library. + + if not For_Gnatmake then + if Data.Library_Kind = Static then + Add_Argument + (Get_Name_String (Data.Library_Dir) & + Directory_Separator & + "lib" & Get_Name_String (Data.Library_Name) & + '.' & Archive_Ext, + Verbose_Mode); + + else + -- As we first insert in the reverse order, + -- -L<dir> is put after -l<lib> + + Add_Argument + ("-l" & Get_Name_String (Data.Library_Name), + Verbose_Mode); + + Get_Name_String (Data.Library_Dir); + + Add_Argument + ("-L" & Name_Buffer (1 .. Name_Len), + Verbose_Mode); + + -- If there is a run path option, prepend this + -- directory to the library path. It is probable + -- that the order of the directories in the path + -- option is not important, but just in case + -- put the directories in the same order as the + -- libraries. + + if Path_Option /= null then + -- If it is not the first directory, make room + -- at the beginning of the table, including + -- for a path separator. + + if Lib_Path.Last > 0 then + declare + Increment : constant Positive := + Name_Len + 1; + Prev_Last : constant Positive := + Lib_Path.Last; + + begin + Lib_Path.Set_Last (Prev_Last + Increment); + + for Index in reverse 1 .. Prev_Last loop + Lib_Path.Table (Index + Increment) := + Lib_Path.Table (Index); + end loop; + + Lib_Path.Table (Increment) := + Path_Separator; + end; + + else + -- If it is the first directory, just set + -- Last to the length of the directory. + + Lib_Path.Set_Last (Name_Len); + end if; + + -- Put the directory at the beginning of the + -- table. + + for Index in 1 .. Name_Len loop + Lib_Path.Table (Index) := Name_Buffer (Index); + end loop; + end if; + end if; + end if; + + else + -- For a non library project, just add the path name of + -- the archive. + + Add_Argument + (Get_Name_String (Data.Object_Directory) & + Directory_Separator & + "lib" & Get_Name_String (Data.Name) & + '.' & Archive_Ext, + Verbose_Mode); + end if; + end if; + end if; + end if; + end Recursive_Add_Archives; + + begin + -- First, mark all projects as not processed + + for Project in 1 .. Projects.Last loop + Projects.Table (Project).Seen := False; + end loop; + + -- Take care of the run path option + + if Path_Option = null then + Path_Option := MLib.Linker_Library_Path_Option; + end if; + + Lib_Path.Set_Last (0); + + -- Add archives in the reverse order + + Recursive_Add_Archives (Main_Project); + + -- And reverse the order + + declare + First : Positive := Last_Arg + 1; + Last : Natural := Last_Argument; + Temp : String_Access; + + begin + while First < Last loop + Temp := Arguments (First); + Arguments (First) := Arguments (Last); + Arguments (Last) := Temp; + First := First + 1; + Last := Last - 1; + end loop; + end; + end Add_Archives; + + ------------------ + -- Add_Argument -- + ------------------ + + procedure Add_Argument (Arg : String_Access; Display : Boolean) is + begin + -- Nothing to do if no argument is specified or if argument is empty + + if Arg /= null or else Arg'Length = 0 then + + -- Reallocate arrays if necessary + + if Last_Argument = Arguments'Last then + declare + New_Arguments : constant Argument_List_Access := + new Argument_List + (1 .. Last_Argument + + Initial_Argument_Count); + + New_Arguments_Displayed : constant Booleans := + new Boolean_Array + (1 .. Last_Argument + + Initial_Argument_Count); + + begin + New_Arguments (Arguments'Range) := Arguments.all; + + -- To avoid deallocating the strings, nullify all components + -- of Arguments before calling Free. + + Arguments.all := (others => null); + + Free (Arguments); + Arguments := New_Arguments; + + New_Arguments_Displayed (Arguments_Displayed'Range) := + Arguments_Displayed.all; + Free (Arguments_Displayed); + Arguments_Displayed := New_Arguments_Displayed; + end; + end if; + + -- Add the argument and its display indication + + Last_Argument := Last_Argument + 1; + Arguments (Last_Argument) := Arg; + Arguments_Displayed (Last_Argument) := Display; + end if; + end Add_Argument; + + procedure Add_Argument (Arg : String; Display : Boolean) is + Argument : String_Access := null; + + begin + -- Nothing to do if argument is empty + + if Arg'Length > 0 then + -- Check if the argument is already in the Cache_Args table. + -- If it is already there, reuse the allocated value. + + for Index in 1 .. Cache_Args.Last loop + if Cache_Args.Table (Index).all = Arg then + Argument := Cache_Args.Table (Index); + exit; + end if; + end loop; + + -- If the argument is not in the cache, create a new entry in the + -- cache. + + if Argument = null then + Argument := new String'(Arg); + Cache_Args.Increment_Last; + Cache_Args.Table (Cache_Args.Last) := Argument; + end if; + + -- And add the argument + + Add_Argument (Argument, Display); + end if; + end Add_Argument; + + ------------------- + -- Add_Arguments -- + ------------------- + + procedure Add_Arguments (Args : Argument_List; Display : Boolean) is + begin + -- Reallocate the arrays, if necessary + + if Last_Argument + Args'Length > Arguments'Last then + declare + New_Arguments : constant Argument_List_Access := + new Argument_List + (1 .. Last_Argument + Args'Length + Initial_Argument_Count); + New_Arguments_Displayed : constant Booleans := + new Boolean_Array + (1 .. Last_Argument + Args'Length + Initial_Argument_Count); + + begin + New_Arguments (1 .. Last_Argument) := + Arguments (1 .. Last_Argument); + + -- To avoid deallocating the strings, nullify all components + -- of Arguments before calling Free. + + Arguments.all := (others => null); + Free (Arguments); + + Arguments := New_Arguments; + New_Arguments_Displayed (1 .. Last_Argument) := + Arguments_Displayed (1 .. Last_Argument); + Free (Arguments_Displayed); + Arguments_Displayed := New_Arguments_Displayed; + end; + end if; + + -- Add the new arguments and the display indications + + Arguments (Last_Argument + 1 .. Last_Argument + Args'Length) := Args; + Arguments_Displayed (Last_Argument + 1 .. Last_Argument + Args'Length) := + (others => Display); + Last_Argument := Last_Argument + Args'Length; + end Add_Arguments; + + ---------------- + -- Add_Option -- + ---------------- + + procedure Add_Option (Arg : String) is + Option : constant String_Access := new String'(Arg); + + begin + case Current_Processor is + when None => + null; + + when Linker => + + -- Add option to the linker table + + Linker_Options.Increment_Last; + Linker_Options.Table (Linker_Options.Last) := Option; + + when Compiler => + + -- Add option to the compiler option table, depending on the + -- value of Current_Language. + + Comp_Opts.Increment_Last (Options (Current_Language)); + Options (Current_Language).Table + (Comp_Opts.Last (Options (Current_Language))) := Option; + + end case; + end Add_Option; + + ------------------- + -- Add_Source_Id -- + ------------------- + + procedure Add_Source_Id (Id : Other_Source_Id) is + begin + -- Reallocate the array, if necessary + + if Last_Source = Source_Indexes'Last then + declare + New_Indexes : constant Source_Indexes_Ref := + new Source_Index_Array + (1 .. Source_Indexes'Last + + Initial_Source_Index_Count); + begin + New_Indexes (Source_Indexes'Range) := Source_Indexes.all; + Free (Source_Indexes); + Source_Indexes := New_Indexes; + end; + end if; + + Last_Source := Last_Source + 1; + Source_Indexes (Last_Source) := (Id, False); + end Add_Source_Id; + + ---------------------------- + -- Add_Search_Directories -- + ---------------------------- + + procedure Add_Search_Directories + (Data : Project_Data; + Language : Programming_Language) + is + begin + -- If a GNU compiler is used, set the CPATH environment variable, + -- if it does not already has the correct value. + + if Compiler_Is_Gcc (Language) then + if Current_Include_Paths (Language) /= Data.Include_Path then + Current_Include_Paths (Language) := Data.Include_Path; + Setenv (CPATH, Data.Include_Path.all); + end if; + + else + Add_Arguments (Data.Imported_Directories_Switches.all, Verbose_Mode); + end if; + end Add_Search_Directories; + + ------------------ + -- Add_Switches -- + ------------------ + + procedure Add_Switches + (Data : Project_Data; + Proc : Processor; + Language : Other_Programming_Language; + File_Name : Name_Id) + is + Switches : Variable_Value; + -- The switches, if any, for the file/language + + Pkg : Package_Id; + -- The id of the package where to look for the switches + + Defaults : Array_Element_Id; + -- The Default_Switches associative array + + Switches_Array : Array_Element_Id; + -- The Switches associative array + + Element_Id : String_List_Id; + Element : String_Element; + + begin + -- First, choose the proper package + + case Proc is + when None => + raise Program_Error; + + when Linker => + Pkg := Value_Of (Name_Linker, Data.Decl.Packages); + + when Compiler => + Pkg := Value_Of (Name_Compiler, Data.Decl.Packages); + end case; + + -- Get the Switches ("file name"), if they exist + + Switches_Array := Prj.Util.Value_Of + (Name => Name_Switches, + In_Arrays => + Packages.Table (Pkg).Decl.Arrays); + + Switches := + Prj.Util.Value_Of + (Index => File_Name, + Src_Index => 0, + In_Array => Switches_Array); + + -- Otherwise, get the Default_Switches ("language"), if they exist + + if Switches = Nil_Variable_Value then + Defaults := Prj.Util.Value_Of + (Name => Name_Default_Switches, + In_Arrays => Packages.Table (Pkg).Decl.Arrays); + Switches := Prj.Util.Value_Of + (Index => Lang_Name_Ids (Language), + Src_Index => 0, + In_Array => Defaults); + end if; + + -- If there are switches, add them to Arguments + + if Switches /= Nil_Variable_Value then + Element_Id := Switches.Values; + + while Element_Id /= Nil_String loop + Element := String_Elements.Table (Element_Id); + + if Element.Value /= No_Name then + Add_Argument (Get_Name_String (Element.Value), True); + end if; + + Element_Id := Element.Next; + end loop; + end if; + end Add_Switches; + + ------------------- + -- Build_Archive -- + ------------------- + + procedure Build_Archive (Project : Project_Id; Unconditionally : Boolean) is + Data : constant Project_Data := Projects.Table (Project); + Source_Id : Other_Source_Id; + Source : Other_Source; + Success : Boolean; + + Archive_Name : constant String := + "lib" & Get_Name_String (Data.Name) & '.' & Archive_Ext; + -- The name of the archive file for this project + + Archive_Dep_Name : constant String := + "lib" & Get_Name_String (Data.Name) & ".deps"; + -- The name of the archive dependency file for this project + + Need_To_Rebuild : Boolean := Unconditionally; + -- When True, archive will be rebuilt + + File : Prj.Util.Text_File; + + Object_Name : Name_Id; + Time_Stamp : Time_Stamp_Type; + + Saved_Last_Argument : Natural; + + begin + -- First, make sure that the archive builder (ar) is on the path + + if Archive_Builder_Path = null then + Archive_Builder_Path := Locate_Exec_On_Path (Archive_Builder); + + if Archive_Builder_Path = null then + Osint.Fail + ("unable to locate archive builder """, + Archive_Builder, + """"); + end if; + + -- If there is an archive indexer (ranlib), try to locate it on the + -- path. Don't fail if it is not found. + + if Archive_Indexer /= "" then + Archive_Indexer_Path := Locate_Exec_On_Path (Archive_Indexer); + end if; + end if; + + -- If Unconditionally is False, check if the archive need to be built + + if not Need_To_Rebuild then + if Verbose_Mode then + Write_Str (" Checking "); + Write_Line (Archive_Name); + end if; + + -- If the archive does not exist, of course it needs to be built + + if not Is_Regular_File (Archive_Name) then + Need_To_Rebuild := True; + + if Verbose_Mode then + Write_Line (" -> archive does not exist"); + end if; + + -- Archive does exist + + else + -- Check the archive dependency file + + Open (File, Archive_Dep_Name); + + -- If the archive dependency file does not exist, we need to + -- to rebuild the archive and to create its dependency file. + + if not Is_Valid (File) then + Need_To_Rebuild := True; + + if Verbose_Mode then + Write_Str (" -> archive dependency file "); + Write_Str (Archive_Dep_Name); + Write_Line (" does not exist"); + end if; + + else + -- Put all sources of language other than Ada in + -- Source_Indexes. + + Last_Source := 0; + Source_Id := Data.First_Other_Source; + + while Source_Id /= No_Other_Source loop + Add_Source_Id (Source_Id); + Source_Id := Other_Sources.Table (Source_Id).Next; + end loop; + + -- Read the dependency file, line by line + + while not End_Of_File (File) loop + Get_Line (File, Name_Buffer, Name_Len); + + -- First line is the name of an object file + + Object_Name := Name_Find; + Source_Id := No_Other_Source; + + -- Check if this object file is for a source of this project + + for S in 1 .. Last_Source loop + if (not Source_Indexes (S).Found) and then + Other_Sources.Table + (Source_Indexes (S).Id).Object_Name = + Object_Name + then + -- We have found the object file: get the source + -- data, and mark it as found. + + Source_Id := Source_Indexes (S).Id; + Source := Other_Sources.Table (Source_Id); + Source_Indexes (S).Found := True; + exit; + end if; + end loop; + + -- If it is not for a source of this project, then the + -- archive needs to be rebuilt. + + if Source_Id = No_Other_Source then + Need_To_Rebuild := True; + if Verbose_Mode then + Write_Str (" -> "); + Write_Str (Get_Name_String (Object_Name)); + Write_Line (" is not an object of the project"); + end if; + + exit; + end if; + + -- The second line is the time stamp of the object file. + -- If there is no next line, then the dependency file is + -- truncated, and the archive need to be rebuilt. + + if End_Of_File (File) then + Need_To_Rebuild := True; + + if Verbose_Mode then + Write_Str (" -> archive dependency file "); + Write_Line (" is truncated"); + end if; + + exit; + end if; + + Get_Line (File, Name_Buffer, Name_Len); + + -- If the line has the wrong number of character, then + -- the dependency file is incorrectly formatted, and the + -- archive needs to be rebuilt. + + if Name_Len /= Time_Stamp_Length then + Need_To_Rebuild := True; + + if Verbose_Mode then + Write_Str (" -> archive dependency file "); + Write_Line (" is incorrectly formatted (time stamp)"); + end if; + + exit; + end if; + + Time_Stamp := Time_Stamp_Type (Name_Buffer (1 .. Name_Len)); + + -- If the time stamp in the dependency file is different + -- from the time stamp of the object file, then the archive + -- needs to be rebuilt. + + if Time_Stamp /= Source.Object_TS then + Need_To_Rebuild := True; + + if Verbose_Mode then + Write_Str (" -> time stamp of "); + Write_Str (Get_Name_String (Object_Name)); + Write_Str (" is incorrect in the archive"); + Write_Line (" dependency file"); + end if; + + exit; + end if; + end loop; + + Close (File); + + if not Need_To_Rebuild then + + -- Now, check if all object files of the project have been + -- accounted for. If any of them is not in the dependency + -- file, the archive needs to be rebuilt. + + for Index in 1 .. Last_Source loop + if not Source_Indexes (Index).Found then + Need_To_Rebuild := True; + + if Verbose_Mode then + Source_Id := Source_Indexes (Index).Id; + Source := Other_Sources.Table (Source_Id); + Write_Str (" -> "); + Write_Str (Get_Name_String (Source.Object_Name)); + Write_Str (" is not in the archive "); + Write_Line ("dependency file"); + end if; + + exit; + end if; + end loop; + end if; + + if (not Need_To_Rebuild) and Verbose_Mode then + Write_Line (" -> up to date"); + end if; + end if; + end if; + end if; + + -- Build the archive if necessary + + if Need_To_Rebuild then + + -- If an archive is built, then linking will need to occur + -- unconditionally. + + Need_To_Relink := True; + + Last_Argument := 0; + + -- If it is a library project file, we need to build the library + -- in the library directory. + + if Data.Library then + + -- If there are sources in Ada, then gnatmake will build the + -- library, so nothing to do. + + if not Data.Languages (Lang_Ada) then + + -- Get all the object files of the project + + Source_Id := Data.First_Other_Source; + + while Source_Id /= No_Other_Source loop + Source := Other_Sources.Table (Source_Id); + Add_Argument + (Get_Name_String (Source.Object_Name), Verbose_Mode); + Source_Id := Source.Next; + end loop; + + -- If it is a library, it need to be built it the same way + -- Ada libraries are built. + + if Data.Library_Kind = Static then + MLib.Build_Library + (Ofiles => Arguments (1 .. Last_Argument), + Afiles => No_Argument, + Output_File => Get_Name_String (Data.Library_Name), + Output_Dir => Get_Name_String (Data.Library_Dir)); + + else + MLib.Tgt.Build_Dynamic_Library + (Ofiles => Arguments (1 .. Last_Argument), + Foreign => Arguments (1 .. Last_Argument), + Afiles => No_Argument, + Options => No_Argument, + Interfaces => No_Argument, + Lib_Filename => Get_Name_String (Data.Library_Name), + Lib_Dir => Get_Name_String (Data.Library_Dir), + Symbol_Data => No_Symbols, + Driver_Name => No_Name, + Lib_Address => "", + Lib_Version => "", + Relocatable => Data.Library_Kind = Relocatable, + Auto_Init => False); + end if; + end if; + + -- Create fake empty archive, so we can check its time stamp later + + declare + Archive : Ada.Text_IO.File_Type; + use Ada.Text_IO; + begin + Create (Archive, Out_File, Archive_Name); + Close (Archive); + end; + + Create_Archive_Dependency_File + (Archive_Dep_Name, Data.First_Other_Source); + + return; + end if; + + -- Start with the options found in MLib.Tgt (usually just "rc") + + Add_Arguments (Archive_Builder_Options.all, True); + + -- Followed by the archive name + + Add_Argument (Archive_Name, True); + + -- Followed by all the object files of the project + + Source_Id := Data.First_Other_Source; + + while Source_Id /= No_Other_Source loop + Source := Other_Sources.Table (Source_Id); + Add_Argument (Get_Name_String (Source.Object_Name), Verbose_Mode); + Source_Id := Source.Next; + end loop; + + -- Spawn the archive builder (ar) + + Saved_Last_Argument := Last_Argument; + + Last_Argument := Max_In_Archives; + + loop + if Last_Argument > Saved_Last_Argument then + Last_Argument := Saved_Last_Argument; + end if; + + Display_Command (Archive_Builder, Archive_Builder_Path); + + Spawn + (Archive_Builder_Path.all, + Arguments (1 .. Last_Argument), + Success); + + exit when not Success; + + exit when Last_Argument = Saved_Last_Argument; + + Arguments (1) := r; + Arguments (3 .. Saved_Last_Argument - Last_Argument + 2) := + Arguments (Last_Argument + 1 .. Saved_Last_Argument); + Saved_Last_Argument := Saved_Last_Argument - Last_Argument + 2; + end loop; + + if Success then + + -- If the archive was built, run the archive indexer (ranlib), + -- if there is one. + + if Archive_Indexer_Path /= null then + Last_Argument := 0; + Add_Argument (Archive_Name, True); + + Display_Command (Archive_Indexer, Archive_Indexer_Path); + + Spawn (Archive_Indexer_Path.all, Arguments (1 .. 1), Success); + + if not Success then + + -- Running ranlib failed, delete the dependency file, + -- if it exists. + + if Is_Regular_File (Archive_Dep_Name) then + Delete_File (Archive_Dep_Name, Success); + end if; + + -- And report the error + + Report_Error + ("running" & Archive_Indexer & " for project """, + Get_Name_String (Data.Name), + """ failed"); + return; + end if; + end if; + + -- The archive was correctly built, create its dependency file + + Create_Archive_Dependency_File + (Archive_Dep_Name, Data.First_Other_Source); + + else + -- Building the archive failed, delete the dependency file, if + -- one exists. + + if Is_Regular_File (Archive_Dep_Name) then + Delete_File (Archive_Dep_Name, Success); + end if; + + -- And report the error + + Report_Error + ("building archive for project """, + Get_Name_String (Data.Name), + """ failed"); + end if; + end if; + end Build_Archive; + + ------------------------------ + -- Check_Compilation_Needed -- + ------------------------------ + + procedure Check_Compilation_Needed + (Source : Other_Source; + Need_To_Compile : out Boolean) + is + Source_Name : constant String := Get_Name_String (Source.File_Name); + Source_Path : constant String := Get_Name_String (Source.Path_Name); + Object_Name : constant String := Get_Name_String (Source.Object_Name); + Dep_Name : constant String := Get_Name_String (Source.Dep_Name); + + Source_In_Dependencies : Boolean := False; + -- Set to True if the source was find in the dependency file of its + -- object file. + + Dep_File : Prj.Util.Text_File; + Start : Natural; + Finish : Natural; + + begin + -- Assume the worst, so that statement "return;" may be used if there + -- is any problem. + + Need_To_Compile := True; + + if Verbose_Mode then + Write_Str (" Checking "); + Write_Str (Source_Name); + Write_Line (" ... "); + end if; + + -- If the object file does not exist, of course the source need to be + -- compiled. + + if Source.Object_TS = Empty_Time_Stamp then + if Verbose_Mode then + Write_Str (" -> object file "); + Write_Str (Object_Name); + Write_Line (" does not exist"); + end if; + + return; + end if; + + -- If the object file has been created before the last modification + -- of the source, the source need to be recompiled. + + if Source.Object_TS < Source.Source_TS then + if Verbose_Mode then + Write_Str (" -> object file "); + Write_Str (Object_Name); + Write_Line (" has time stamp earlier than source"); + end if; + + return; + end if; + + -- If there is no dependency file, then the source needs to be + -- recompiled and the dependency file need to be created. + + if Source.Dep_TS = Empty_Time_Stamp then + if Verbose_Mode then + Write_Str (" -> dependency file "); + Write_Str (Dep_Name); + Write_Line (" does not exist"); + end if; + + return; + end if; + + -- The source needs to be recompiled if the source has been modified + -- after the dependency file has been created. + + if Source.Dep_TS < Source.Source_TS then + if Verbose_Mode then + Write_Str (" -> dependency file "); + Write_Str (Dep_Name); + Write_Line (" has time stamp earlier than source"); + end if; + + return; + end if; + + -- Look for all dependencies + + Open (Dep_File, Dep_Name); + + -- If dependency file cannot be open, we need to recompile the source + + if not Is_Valid (Dep_File) then + if Verbose_Mode then + Write_Str (" -> could not open dependency file "); + Write_Line (Dep_Name); + end if; + + return; + end if; + + declare + End_Of_File_Reached : Boolean := False; + + begin + loop + if End_Of_File (Dep_File) then + End_Of_File_Reached := True; + exit; + end if; + + Get_Line (Dep_File, Name_Buffer, Name_Len); + + exit when Name_Len > 0 and then Name_Buffer (1) /= '#'; + end loop; + + -- If dependency file contains only empty lines or comments, then + -- the dependencies are unknown, and the source needs to be + -- recompiled. + + if End_Of_File_Reached then + if Verbose_Mode then + Write_Str (" -> dependency file "); + Write_Str (Dep_Name); + Write_Line (" is empty"); + end if; + + Close (Dep_File); + return; + end if; + end; + + Start := 1; + Finish := Index (Name_Buffer (1 .. Name_Len), ": "); + + -- The first line must start with the name of the object file, followed + -- by a colon (:). + + if Finish = 0 or else Name_Buffer (1 .. Finish - 1) /= Object_Name then + if Verbose_Mode then + Write_Str (" -> dependency file "); + Write_Str (Dep_Name); + Write_Line (" has wrong format"); + end if; + + Close (Dep_File); + return; + + else + Start := Finish + 2; + + -- Process each line + + Line_Loop : loop + declare + Line : constant String := Name_Buffer (1 .. Name_Len); + Last : constant Natural := Name_Len; + + begin + Name_Loop : loop + + -- Find the beginning of the next source path name + + while Start < Last and then Line (Start) = ' ' loop + Start := Start + 1; + end loop; + + -- Go to next line when there is a continuation character \ + -- at the end of the line. + + exit Name_Loop when Start = Last + and then Line (Start) = '\'; + + -- We should not be at the end of the line, without + -- a continuation character \. + + if Start = Last then + if Verbose_Mode then + Write_Str (" -> dependency file "); + Write_Str (Dep_Name); + Write_Line (" has wrong format"); + end if; + + Close (Dep_File); + return; + end if; + + -- Look for the end of the source path name + + Finish := Start; + while Finish < Last and then Line (Finish + 1) /= ' ' loop + Finish := Finish + 1; + end loop; + + -- Check this source + + declare + Src_Name : constant String := + Normalize_Pathname + (Name => Line (Start .. Finish), + Case_Sensitive => False); + Src_TS : Time_Stamp_Type; + + begin + -- If it is original source, set Source_In_Dependencies + + if Src_Name = Source_Path then + Source_In_Dependencies := True; + end if; + + Name_Len := 0; + Add_Str_To_Name_Buffer (Src_Name); + Src_TS := File_Stamp (Name_Find); + + -- If the source does not exist, we need to recompile + + if Src_TS = Empty_Time_Stamp then + if Verbose_Mode then + Write_Str (" -> source "); + Write_Str (Src_Name); + Write_Line (" does not exist"); + end if; + + Close (Dep_File); + return; + + -- If the source has been modified after the object file, + -- we need to recompile. + + elsif Src_TS > Source.Object_TS then + if Verbose_Mode then + Write_Str (" -> source "); + Write_Str (Src_Name); + Write_Line + (" has time stamp later than object file"); + end if; + + Close (Dep_File); + return; + end if; + end; + + -- If the source path name ends the line, we are done. + + exit Line_Loop when Finish = Last; + + -- Go get the next source on the line + + Start := Finish + 1; + end loop Name_Loop; + end; + + -- If we are here, we had a continuation character \ at the end + -- of the line, so we continue with the next line. + + Get_Line (Dep_File, Name_Buffer, Name_Len); + Start := 1; + end loop Line_Loop; + end if; + + Close (Dep_File); + + -- If the original sources were not in the dependency file, then we + -- need to recompile. It may mean that we are using a different source + -- (different variant) for this object file. + + if not Source_In_Dependencies then + if Verbose_Mode then + Write_Str (" -> source "); + Write_Str (Source_Path); + Write_Line (" is not in the dependencies"); + end if; + + return; + end if; + + -- If we are here, then everything is OK, and we don't need + -- to recompile. + + if Verbose_Mode then + Write_Line (" -> up to date"); + end if; + + Need_To_Compile := False; + end Check_Compilation_Needed; + + --------------------------- + -- Check_For_C_Plus_Plus -- + --------------------------- + + procedure Check_For_C_Plus_Plus is + begin + C_Plus_Plus_Is_Used := False; + + for Project in 1 .. Projects.Last loop + if Projects.Table (Project).Languages (Lang_C_Plus_Plus) then + C_Plus_Plus_Is_Used := True; + exit; + end if; + end loop; + end Check_For_C_Plus_Plus; + + ------------- + -- Compile -- + ------------- + + procedure Compile + (Source_Id : Other_Source_Id; + Data : in Project_Data; + Local_Errors : in out Boolean) + is + Source : Other_Source := Other_Sources.Table (Source_Id); + Success : Boolean; + + begin + -- If the compiler is not know yet, get its path name + + if Compiler_Names (Source.Language) = null then + Get_Compiler (Source.Language); + end if; + + -- For non GCC compilers, get the dependency file, calling first the + -- compiler with the switch -M. + + if not Compiler_Is_Gcc (Source.Language) then + Last_Argument := 0; + + -- Add the source name, preceded by -M + + Add_Argument (Dash_M, True); + Add_Argument (Get_Name_String (Source.Path_Name), True); + + -- Add the compiling switches for this source found in + -- package Compiler of the project file, if they exist. + + Add_Switches + (Data, Compiler, Source.Language, Source.File_Name); + + -- Add the compiling switches for the language specified + -- on the command line, if any. + + for + J in 1 .. Comp_Opts.Last (Options (Source.Language)) + loop + Add_Argument (Options (Source.Language).Table (J), True); + end loop; + + -- Finally, add the imported directory switches for this + -- project file. + + Add_Search_Directories (Data, Source.Language); + + -- And invoke the compiler using GNAT.Expect + + Display_Command + (Compiler_Names (Source.Language).all, + Compiler_Paths (Source.Language)); + + begin + Non_Blocking_Spawn + (FD, + Compiler_Paths (Source.Language).all, + Arguments (1 .. Last_Argument), + Buffer_Size => 0, + Err_To_Out => True); + + declare + Dep_File : Ada.Text_IO.File_Type; + Result : Expect_Match; + Status : Integer; + + begin + -- Create the dependency file + + Create (Dep_File, Out_File, Get_Name_String (Source.Dep_Name)); + + loop + Expect (FD, Result, Line_Matcher); + + exit when Result = Expect_Timeout; + + declare + S : constant String := Strip_CR_LF (Expect_Out (FD)); + + begin + -- Each line of the output is put in the dependency + -- file, including errors. If there are errors, the + -- syntax of the dependency file will be incorrect and + -- recompilation will occur automatically the next time + -- the dependencies are checked. + + Put_Line (Dep_File, S); + end; + end loop; + + -- If we are here, it means we had a timeout, so the + -- dependency file may be incomplete. It is safer to + -- delete it, otherwise the dependencies may be wrong. + + Close (FD, Status); + Close (Dep_File); + Delete_File (Get_Name_String (Source.Dep_Name), Success); + + exception + when Process_Died => + + -- This is the normal outcome. Just close the file + + Close (FD, Status); + Close (Dep_File); + + when others => + + -- Something wrong happened. It is safer to delete the + -- dependency file, otherwise the dependencies may be wrong. + + Close (FD, Status); + + if Is_Open (Dep_File) then + Close (Dep_File); + end if; + + Delete_File (Get_Name_String (Source.Dep_Name), Success); + end; + + exception + -- If we cannot spawn the compiler, then the dependencies are + -- not updated. It is safer then to delete the dependency file, + -- otherwise the dependencies may be wrong. + + when Invalid_Process => + Delete_File (Get_Name_String (Source.Dep_Name), Success); + end; + end if; + + Last_Argument := 0; + + -- For GCC compilers, make sure the language is always specified to + -- to the GCC driver, in case the extension is not recognized by the + -- GCC driver as a source of the language. + + if Compiler_Is_Gcc (Source.Language) then + Add_Argument (Dash_x, Verbose_Mode); + Add_Argument + (Lang_Names (Source.Language), Verbose_Mode); + end if; + + -- Specify the source to be compiled + + Add_Argument (Dash_c, True); + Add_Argument (Get_Name_String (Source.Path_Name), True); + + -- If non static library project, compile with the PIC option if there + -- is one (when there is no PIC option, function MLib.Tgt.PIC_Option + -- returns an empty string, and Add_Argument with an empty string has + -- no effect). + + if Data.Library and then Data.Library_Kind /= Static then + Add_Argument (PIC_Option, True); + end if; + + -- Indicate the name of the object + + Add_Argument (Dash_o, True); + Add_Argument (Get_Name_String (Source.Object_Name), True); + + -- When compiler is GCC, use the magic switch that creates + -- the dependency file in the correct format. + + if Compiler_Is_Gcc (Source.Language) then + Add_Argument + ("-Wp,-MD," & Get_Name_String (Source.Dep_Name), + Verbose_Mode); + end if; + + -- Add the compiling switches for this source found in + -- package Compiler of the project file, if they exist. + + Add_Switches + (Data, Compiler, Source.Language, Source.File_Name); + + -- Add the compiling switches for the language specified + -- on the command line, if any. + + for + J in 1 .. Comp_Opts.Last (Options (Source.Language)) + loop + Add_Argument (Options (Source.Language).Table (J), True); + end loop; + + -- Finally, add the imported directory switches for this + -- project file (or, for gcc compilers, set up the CPATH env var + -- if needed). + + Add_Search_Directories (Data, Source.Language); + + -- And invoke the compiler + + Display_Command + (Compiler_Names (Source.Language).all, + Compiler_Paths (Source.Language)); + + Spawn + (Compiler_Paths (Source.Language).all, + Arguments (1 .. Last_Argument), + Success); + + if Success then + + -- Compilation was successful, update the time stamp + -- of the object file. + + Source.Object_TS := File_Stamp (Source.Object_Name); + + -- Do some sanity checks + + if Source.Object_TS = Empty_Time_Stamp then + Local_Errors := True; + Report_Error + ("object file ", + Get_Name_String (Source.Object_Name), + " has not been created"); + + elsif Source.Object_TS < Source.Source_TS then + Local_Errors := True; + Report_Error + ("object file ", + Get_Name_String (Source.Object_Name), + " has not been modified"); + + else + -- Everything looks fine, update the Other_Sources table + + Other_Sources.Table (Source_Id) := Source; + end if; + + else + Local_Errors := True; + Report_Error + ("compilation of ", + Get_Name_String (Source.Path_Name), + " failed"); + end if; + end Compile; + + -------------------------------- + -- Compile_Individual_Sources -- + -------------------------------- + + procedure Compile_Individual_Sources is + Data : Project_Data := Projects.Table (Main_Project); + Source_Id : Other_Source_Id; + Source : Other_Source; + Source_Name : Name_Id; + Project_Name : String := Get_Name_String (Data.Name); + Dummy : Boolean := False; + + Ada_Is_A_Language : constant Boolean := Data.Languages (Lang_Ada); + + begin + Ada_Mains.Init; + + To_Mixed (Project_Name); + + Compile_Only := True; + + Get_Imported_Directories (Main_Project, Data); + Projects.Table (Main_Project) := Data; + + if not Data.Sources_Present then + if Ada_Is_A_Language then + Mains.Reset; + + loop + declare + Main : constant String := Mains.Next_Main; + begin + exit when Main'Length = 0; + Ada_Mains.Increment_Last; + Ada_Mains.Table (Ada_Mains.Last) := new String'(Main); + end; + end loop; + + else + Osint.Fail + ("project ", Project_Name, " contains no source"); + end if; + + else + Mains.Reset; + + loop + declare + Main : constant String := Mains.Next_Main; + begin + Name_Len := Main'Length; + exit when Name_Len = 0; + Name_Buffer (1 .. Name_Len) := Main; + Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); + Source_Name := Name_Find; + + if not Sources_Compiled.Get (Source_Name) then + Sources_Compiled.Set (Source_Name, True); + + Source_Id := Data.First_Other_Source; + + while Source_Id /= No_Other_Source loop + Source := Other_Sources.Table (Source_Id); + exit when Source.File_Name = Source_Name; + Source_Id := Source.Next; + end loop; + + if Source_Id = No_Other_Source then + if Ada_Is_A_Language then + Ada_Mains.Increment_Last; + Ada_Mains.Table (Ada_Mains.Last) := + new String'(Main); + + else + Report_Error + (Main, + " is not a valid source of project ", + Project_Name); + end if; + + else + Compile (Source_Id, Data, Dummy); + end if; + end if; + end; + end loop; + end if; + + if Ada_Mains.Last > 0 then + + -- Invoke gnatmake for all sources that are not of a non Ada language + + Last_Argument := 0; + + Add_Argument (Dash_u, True); + + for Index in 1 .. Ada_Mains.Last loop + Add_Argument (Ada_Mains.Table (Index), True); + end loop; + + Compile_Link_With_Gnatmake (Mains_Specified => False); + end if; + end Compile_Individual_Sources; + + -------------------------------- + -- Compile_Link_With_Gnatmake -- + -------------------------------- + + procedure Compile_Link_With_Gnatmake (Mains_Specified : Boolean) is + Data : constant Project_Data := Projects.Table (Main_Project); + Success : Boolean; + + begin + -- Array Arguments may already contain some arguments, so we don't + -- set Last_Argument to 0. + + -- Get the gnatmake to invoke + + Get_Compiler (Lang_Ada); + + -- Specify the project file + + Add_Argument (Dash_P, True); + Add_Argument (Get_Name_String (Data.Path_Name), True); + + -- If Mains_Specified is True, find the mains in package Mains + + if Mains_Specified then + Mains.Reset; + + loop + declare + Main : constant String := Mains.Next_Main; + begin + exit when Main'Length = 0; + Add_Argument (Main, True); + end; + end loop; + end if; + + -- Specify output file name, if any was specified on the command line + + if Output_File_Name /= null then + Add_Argument (Dash_o, True); + Add_Argument (Output_File_Name, True); + end if; + + -- Transmit to gnatmake some switches + + -- -c + + if Compile_Only then + Add_Argument (Dash_c, True); + end if; + + -- -k + + if Keep_Going then + Add_Argument (Dash_k, True); + end if; + + -- -f + + if Force_Compilations then + Add_Argument (Dash_f, True); + end if; + + -- -v + + if Verbose_Mode then + Add_Argument (Dash_v, True); + end if; + + -- -q + + if Quiet_Output then + Add_Argument (Dash_q, True); + end if; + + -- -vP1 and -vP2 + + case Current_Verbosity is + when Default => + null; + + when Medium => + Add_Argument (Dash_vP1, True); + + when High => + Add_Argument (Dash_vP2, True); + end case; + + -- If there are compiling options for Ada, transmit them to gnatmake + + if Comp_Opts.Last (Options (Lang_Ada)) /= 0 then + Add_Argument (Dash_cargs, True); + + for Arg in 1 .. Comp_Opts.Last (Options (Lang_Ada)) loop + Add_Argument (Options (Lang_Ada).Table (Arg), True); + end loop; + end if; + + if not Compile_Only then + -- If there are linking options from the command line, transmit them + -- to gnatmake. + + if Linker_Options.Last /= 0 then + Add_Argument (Dash_largs, True); + + for Arg in 1 .. Linker_Options.Last loop + Add_Argument (Linker_Options.Table (Arg), True); + end loop; + + else + Add_Argument (Dash_largs, Verbose_Mode); + end if; + + -- Add the archives + + Add_Archives (For_Gnatmake => True); + end if; + + -- And invoke gnatmake + + Display_Command + (Compiler_Names (Lang_Ada).all, Compiler_Paths (Lang_Ada)); + + Spawn + (Compiler_Paths (Lang_Ada).all, + Arguments (1 .. Last_Argument), + Success); + + -- Report an error if call to gnatmake failed + + if not Success then + Report_Error + ("invocation of ", Compiler_Names (Lang_Ada).all, " failed"); + end if; + + end Compile_Link_With_Gnatmake; + + --------------------- + -- Compile_Sources -- + --------------------- + + procedure Compile_Sources is + Data : Project_Data; + Source_Id : Other_Source_Id; + Source : Other_Source; + + Local_Errors : Boolean := False; + -- Set to True when there is a compilation error. Used only when + -- Keep_Going is True, to inhibit the building of the archive. + + Need_To_Compile : Boolean; + -- Set to True when a source needs to be compiled/recompiled. + + Need_To_Rebuild_Archive : Boolean := Force_Compilations; + -- True when the archive needs to be built/rebuilt unconditionally + + begin + -- For each project file + + for Project in 1 .. Projects.Last loop + Local_Errors := False; + Data := Projects.Table (Project); + + if not Data.Virtual then + + -- If the imported directory switches are unknown, compute them + + if not Data.Include_Data_Set then + Get_Imported_Directories (Project, Data); + Data.Include_Data_Set := True; + Projects.Table (Project) := Data; + end if; + + -- Nothing to do when no sources of language other than Ada + + if Data.Sources_Present then + Need_To_Rebuild_Archive := Force_Compilations; + + -- Compilation will occur in the object directory + + Change_Dir (Get_Name_String (Data.Object_Directory)); + + Source_Id := Data.First_Other_Source; + + -- Process each source one by one + + while Source_Id /= No_Other_Source loop + Source := Other_Sources.Table (Source_Id); + Need_To_Compile := Force_Compilations; + + -- Check if compilation is needed + + if not Need_To_Compile then + Check_Compilation_Needed (Source, Need_To_Compile); + end if; + + -- Proceed, if compilation is needed + + if Need_To_Compile then + + -- If a source is compiled/recompiled, of course the + -- archive will need to be built/rebuilt. + + Need_To_Rebuild_Archive := True; + Compile (Source_Id, Data, Local_Errors); + end if; + + -- Next source, if any + + Source_Id := Source.Next; + end loop; + + -- If there was no compilation error, build/rebuild the archive + -- if necessary. + + if not Local_Errors then + Build_Archive (Project, Need_To_Rebuild_Archive); + end if; + end if; + end if; + end loop; + end Compile_Sources; + + --------------- + -- Copyright -- + --------------- + + procedure Copyright is + begin + -- Only output the Copyright notice once + + if not Copyright_Output then + Copyright_Output := True; + Write_Eol; + Write_Str ("GPRMAKE "); + Write_Str (Gnatvsn.Gnat_Version_String); + Write_Str (" Copyright 2004 Free Software Foundation, Inc."); + Write_Eol; + end if; + end Copyright; + + ------------------------------------ + -- Create_Archive_Dependency_File -- + ------------------------------------ + + procedure Create_Archive_Dependency_File + (Name : String; + First_Source : Other_Source_Id) + is + Source_Id : Other_Source_Id := First_Source; + Source : Other_Source; + Dep_File : Ada.Text_IO.File_Type; + use Ada.Text_IO; + + begin + Create (Dep_File, Out_File, Name); + + while Source_Id /= No_Other_Source loop + Source := Other_Sources.Table (Source_Id); + Put_Line (Dep_File, Get_Name_String (Source.Object_Name)); + Put_Line (Dep_File, String (Source.Object_TS)); + Source_Id := Source.Next; + end loop; + + Close (Dep_File); + + exception + when others => + if Is_Open (Dep_File) then + Close (Dep_File); + end if; + end Create_Archive_Dependency_File; + + --------------------- + -- Display_Command -- + --------------------- + + procedure Display_Command (Name : String; Path : String_Access) is + begin + -- Only display the command in Verbose Mode (-v) or when + -- not in Quiet Output (no -q). + + if Verbose_Mode or (not Quiet_Output) then + -- In Verbose Mode output the full path of the spawned process + + if Verbose_Mode then + Write_Str (Path.all); + + else + Write_Str (Name); + end if; + + -- Display only the arguments for which the display flag is set + -- (in Verbose Mode, the display flag is set for all arguments) + + for Arg in 1 .. Last_Argument loop + if Arguments_Displayed (Arg) then + Write_Char (' '); + Write_Str (Arguments (Arg).all); + end if; + end loop; + + Write_Eol; + end if; + end Display_Command; + + ------------------ + -- Get_Compiler -- + ------------------ + + procedure Get_Compiler (For_Language : Programming_Language) is + Data : constant Project_Data := Projects.Table (Main_Project); + + Ide : constant Package_Id := + Value_Of (Name_Ide, In_Packages => Data.Decl.Packages); + -- The id of the package IDE in the project file + + Compiler : constant Variable_Value := + Value_Of + (Name => Lang_Name_Ids (For_Language), + Index => 0, + Attribute_Or_Array_Name => Name_Compiler_Command, + In_Package => Ide); + -- The value of Compiler_Command ("language") in package IDE, if defined + + begin + -- No need to do it again if the compiler is known for this language + + if Compiler_Names (For_Language) = null then + + -- If compiler command is not defined for this language in package + -- IDE, use the default compiler for this language. + + if Compiler = Nil_Variable_Value then + Compiler_Names (For_Language) := + Default_Compiler_Names (For_Language); + + else + Compiler_Names (For_Language) := + new String'(Get_Name_String (Compiler.Value)); + end if; + + -- Check we have a GCC compiler (name ends with "gcc" or "g++") + + declare + Comp_Name : constant String := Compiler_Names (For_Language).all; + Last3 : String (1 .. 3); + begin + if Comp_Name'Length >= 3 then + Last3 := Comp_Name (Comp_Name'Last - 2 .. Comp_Name'Last); + Compiler_Is_Gcc (For_Language) := + (Last3 = "gcc") or (Last3 = "g++"); + else + Compiler_Is_Gcc (For_Language) := False; + end if; + end; + + -- Locate the compiler on the path + + Compiler_Paths (For_Language) := + Locate_Exec_On_Path (Compiler_Names (For_Language).all); + + -- Fail if compiler cannot be found + + if Compiler_Paths (For_Language) = null then + if For_Language = Lang_Ada then + Osint.Fail + ("unable to locate """, + Compiler_Names (For_Language).all, + """"); + + else + Osint.Fail + ("unable to locate " & Lang_Display_Names (For_Language).all, + " compiler """, Compiler_Names (For_Language).all & '"'); + end if; + end if; + end if; + end Get_Compiler; + + ------------------------------ + -- Get_Imported_Directories -- + ------------------------------ + + procedure Get_Imported_Directories + (Project : Project_Id; + Data : in out Project_Data) + is + Imported_Projects : Project_List := Data.Imported_Projects; + + Path_Length : Natural := 0; + Position : Natural := 0; + + procedure Add (Source_Dirs : String_List_Id); + -- Add a list of source directories + + procedure Recursive_Get_Dirs (Prj : Project_Id); + -- Recursive procedure to get the source directories of this project + -- file and of the project files it imports, in the correct order. + + --------- + -- Add -- + --------- + + procedure Add (Source_Dirs : String_List_Id) is + Element_Id : String_List_Id := Source_Dirs; + Element : String_Element; + Add_Arg : Boolean := True; + begin + -- Add each source directory path name, preceded by "-I" to + -- Arguments. + + while Element_Id /= Nil_String loop + Element := String_Elements.Table (Element_Id); + + if Element.Value /= No_Name then + Get_Name_String (Element.Value); + + if Name_Len > 0 then + declare + Arg : constant String := + "-I" & Name_Buffer (1 .. Name_Len); + begin + -- Check if directory is already in the list. + -- If it is, no need to put it again. + + for Index in 1 .. Last_Argument loop + if Arguments (Index).all = Arg then + Add_Arg := False; + exit; + end if; + end loop; + + if Add_Arg then + if Path_Length /= 0 then + Path_Length := Path_Length + 1; + end if; + + Path_Length := Path_Length + Name_Len; + + Add_Argument (Arg, True); + end if; + end; + end if; + end if; + + Element_Id := Element.Next; + end loop; + end Add; + + ------------------------ + -- Recursive_Get_Dirs -- + ------------------------ + + procedure Recursive_Get_Dirs (Prj : Project_Id) is + Data : Project_Data; + Imported : Project_List; + + begin + -- Nothing to do if project is undefined + + if Prj /= No_Project then + Data := Projects.Table (Prj); + + -- Nothing to do if project has already been processed + + if not Data.Seen then + + -- Mark the project as processed, to avoid multiple processing + -- of the same project. + + Projects.Table (Prj).Seen := True; + + -- Add the source directories of this project + + if not Data.Virtual then + Add (Data.Source_Dirs); + end if; + + Recursive_Get_Dirs (Data.Extends); + + Imported := Data.Imported_Projects; + + -- Call itself for all imported projects, if any + + while Imported /= Empty_Project_List loop + Recursive_Get_Dirs (Project_Lists.Table (Imported).Project); + Imported := Project_Lists.Table (Imported).Next; + end loop; + end if; + end if; + end Recursive_Get_Dirs; + + begin + -- First, mark all project as not processed + + for J in 1 .. Projects.Last loop + Projects.Table (J).Seen := False; + end loop; + + -- Empty Arguments + + Last_Argument := 0; + + -- Process this project individually, project data are already known + + Projects.Table (Project).Seen := True; + + Add (Data.Source_Dirs); + + Recursive_Get_Dirs (Data.Extends); + + while Imported_Projects /= Empty_Project_List loop + Recursive_Get_Dirs (Project_Lists.Table (Imported_Projects).Project); + Imported_Projects := Project_Lists.Table (Imported_Projects).Next; + end loop; + + Data.Imported_Directories_Switches := + new Argument_List'(Arguments (1 .. Last_Argument)); + + -- Create the Include_Path, from the Arguments + + Data.Include_Path := new String (1 .. Path_Length); + Data.Include_Path (1 .. Arguments (1)'Length - 2) := + Arguments (1)(Arguments (1)'First + 2 .. Arguments (1)'Last); + Position := Arguments (1)'Length - 2; + + for Arg in 2 .. Last_Argument loop + Position := Position + 1; + Data.Include_Path (Position) := Path_Separator; + Data.Include_Path + (Position + 1 .. Position + Arguments (Arg)'Length - 2) := + Arguments (Arg)(Arguments (Arg)'First + 2 .. Arguments (Arg)'Last); + Position := Position + Arguments (Arg)'Length - 2; + end loop; + + Last_Argument := 0; + end Get_Imported_Directories; + + ------------- + -- Gprmake -- + ------------- + + procedure Gprmake is + begin + Initialize; + + if Verbose_Mode then + Write_Eol; + Write_Str ("Parsing Project File """); + Write_Str (Project_File_Name.all); + Write_Str ("""."); + Write_Eol; + end if; + + -- Parse and process the project files for other languages + -- (not for Ada). + + Prj.Pars.Parse + (Project => Main_Project, + Project_File_Name => Project_File_Name.all, + Packages_To_Check => Packages_To_Check, + Process_Languages => Other_Languages); + + -- Fail if parsing/processing was unsuccessful + + if Main_Project = No_Project then + Osint.Fail ("""", Project_File_Name.all, """ processing failed"); + end if; + + if Verbose_Mode then + Write_Eol; + Write_Str ("Parsing of Project File """); + Write_Str (Project_File_Name.all); + Write_Str (""" is finished."); + Write_Eol; + end if; + + -- If -f was specified, we will certainly need to link (except when + -- -u or -c were specified, of course). + + Need_To_Relink := Force_Compilations; + + if Unique_Compile then + if Mains.Number_Of_Mains = 0 then + Osint.Fail + ("No source specified to compile in 'unique compile' mode"); + + else + Compile_Individual_Sources; + Report_Total_Errors ("compilation"); + end if; + + else + -- First compile sources and build archives, if necessary + + Compile_Sources; + + -- When Keep_Going is True, if we had some errors, fail now, + -- reporting the number of compilation errors. + -- Do not attempt to link. + + Report_Total_Errors ("compilation"); + + -- If -c was not specified, link the executables, if there are any. + + if not Compile_Only then + Check_For_C_Plus_Plus; + Link_Executables; + end if; + + -- When Keep_Going is True, if we had some errors, fail, reporting + -- the number of linking errors. + + Report_Total_Errors ("linking"); + end if; + end Gprmake; + + ---------------- + -- Initialize -- + ---------------- + + procedure Initialize is + Next_Arg : Positive; + + begin + -- Do some necessary package initializations + + Csets.Initialize; + Namet.Initialize; + Snames.Initialize; + Prj.Initialize; + Mains.Delete; + + -- Set Name_Ide and Name_Compiler_Command + + Name_Len := 0; + Add_Str_To_Name_Buffer ("ide"); + Name_Ide := Name_Find; + + Name_Len := 0; + Add_Str_To_Name_Buffer ("compiler_command"); + Name_Compiler_Command := Name_Find; + + Next_Arg := 1; + + -- Get the command line arguments + + Scan_Args : while Next_Arg <= Argument_Count loop + Scan_Arg (Argument (Next_Arg)); + Next_Arg := Next_Arg + 1; + end loop Scan_Args; + + -- Fail if command line ended with "-P" + + if Project_File_Name_Expected then + Osint.Fail ("project file name missing after -P"); + + -- Or if it ended with "-o" + + elsif Output_File_Name_Expected then + Osint.Fail ("output file name missing after -o"); + end if; + + -- If no project file was specified, display the usage and fail + + if Project_File_Name = null then + Usage; + Exit_Program (E_Success); + end if; + + -- To be able of finding libgnat.a in MLib.Tgt, we need to have the + -- default search dirs established in Osint. + + Osint.Add_Default_Search_Dirs; + end Initialize; + + ---------------------- + -- Link_Executables -- + ---------------------- + + procedure Link_Executables is + Data : constant Project_Data := Projects.Table (Main_Project); + + Mains_Specified : constant Boolean := Mains.Number_Of_Mains /= 0; + -- True if main sources were specified on the command line + + Object_Dir : constant String := Get_Name_String (Data.Object_Directory); + -- Path of the object directory of the main project + + Source_Id : Other_Source_Id; + Source : Other_Source; + Success : Boolean; + + Linker_Name : String_Access; + Linker_Path : String_Access; + -- The linker name and path, when linking is not done by gnatlink + + Link_Done : Boolean := False; + -- Set to True when the linker is invoked directly (not through + -- gnatmake) to be able to report if mains were up to date at the end + -- of execution. + + procedure Add_C_Plus_Plus_Link_For_Gnatmake; + -- Add the --LINK= switch for gnatlink, depending on the C++ compiler + + procedure Choose_C_Plus_Plus_Link_Process; + -- If the C++ compiler is not g++, create the correct script to link + + --------------------------------------- + -- Add_C_Plus_Plus_Link_For_Gnatmake -- + --------------------------------------- + + procedure Add_C_Plus_Plus_Link_For_Gnatmake is + begin + if Compiler_Is_Gcc (Lang_C_Plus_Plus) then + Add_Argument + ("--LINK=" & Compiler_Names (Lang_C_Plus_Plus).all, + Verbose_Mode); + + else + Add_Argument + ("--LINK=" & + Object_Dir & Directory_Separator & + Cpp_Linker, + Verbose_Mode); + end if; + end Add_C_Plus_Plus_Link_For_Gnatmake; + + ------------------------------------- + -- Choose_C_Plus_Plus_Link_Process -- + ------------------------------------- + + procedure Choose_C_Plus_Plus_Link_Process is + begin + if Compiler_Names (Lang_C_Plus_Plus) = null then + Get_Compiler (Lang_C_Plus_Plus); + end if; + + if not Compiler_Is_Gcc (Lang_C_Plus_Plus) then + Change_Dir (Object_Dir); + + declare + procedure Set_Executable (Name : System.Address); + pragma Import + (C, Set_Executable, "__gnat_set_executable"); + + Name : constant String := Cpp_Linker & ASCII.NUL; + + File : Ada.Text_IO.File_Type; + use Ada.Text_IO; + + begin + Create (File, Out_File, Cpp_Linker); + + Put_Line (File, "#!/bin/sh"); + + Put_Line (File, "LIBGCC=`gcc -print-libgcc-file-name`"); + Put_Line + (File, + Compiler_Names (Lang_C_Plus_Plus).all & + " $* ${LIBGCC}"); + + Close (File); + Set_Executable (Name (Name'First)'Address); + end; + end if; + end Choose_C_Plus_Plus_Link_Process; + + begin + -- If no mains specified, get mains from attribute Main, if it exists + + if not Mains_Specified then + declare + Element_Id : String_List_Id := Data.Mains; + Element : String_Element; + + begin + while Element_Id /= Nil_String loop + Element := String_Elements.Table (Element_Id); + + if Element.Value /= No_Name then + Mains.Add_Main (Get_Name_String (Element.Value)); + end if; + + Element_Id := Element.Next; + end loop; + end; + end if; + + if Mains.Number_Of_Mains = 0 then + -- If the attribute Main is an empty list or not specified, + -- there is nothing to do. + + if Verbose_Mode then + Write_Line ("No main to link"); + end if; + return; + end if; + + -- Check if -o was used for several mains + + if Output_File_Name /= null and then Mains.Number_Of_Mains > 1 then + Osint.Fail ("cannot specify an executable name for several mains"); + end if; + + -- Check how we are going to do the link + + if not Data.Sources_Present then + -- Only Ada sources in the main project, and even maybe not + + if not Data.Languages (Lang_Ada) then + -- Fail if the main project has no source of any language + + Osint.Fail + ("project """, + Get_Name_String (Data.Name), + """ has no sources, so no main can be linked"); + + else + -- Only Ada sources in the main project, call gnatmake directly + + Last_Argument := 0; + + -- Choose the correct linker if there is C++ code in other + -- projects. + + if C_Plus_Plus_Is_Used then + Choose_C_Plus_Plus_Link_Process; + Add_Argument (Dash_largs, Verbose_Mode); + Add_C_Plus_Plus_Link_For_Gnatmake; + Add_Argument (Dash_margs, Verbose_Mode); + end if; + + Compile_Link_With_Gnatmake (Mains_Specified); + end if; + + else + -- There are other language sources. First check if there are also + -- sources in Ada. + + if Data.Languages (Lang_Ada) then + -- There is a mix of Ada and other language sources in the main + -- project. Any main that is not a source of the other languages + -- will be deemed to be an Ada main. + -- + -- Find the mains of the other languages and the Ada mains. + + Mains.Reset; + Ada_Mains.Set_Last (0); + Other_Mains.Set_Last (0); + + -- For each main + + loop + declare + Main : constant String := Mains.Next_Main; + Main_Id : Name_Id; + begin + exit when Main'Length = 0; + + -- Get the main file name + + Name_Len := 0; + Add_Str_To_Name_Buffer (Main); + Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); + Main_Id := Name_Find; + Source_Id := Data.First_Other_Source; + + -- Check if it is a source of a language other than Ada + + while Source_Id /= No_Other_Source loop + Source := Other_Sources.Table (Source_Id); + exit when Source.File_Name = Main_Id; + Source_Id := Source.Next; + end loop; + + -- If it is not, put it in the list of Ada mains + + if Source_Id = No_Other_Source then + Ada_Mains.Increment_Last; + Ada_Mains.Table (Ada_Mains.Last) := new String'(Main); + + -- Otherwise, put it in the list of other mains + + else + Other_Mains.Increment_Last; + Other_Mains.Table (Other_Mains.Last) := Source; + end if; + end; + end loop; + + -- If C++ is one of the other language, create the shell script + -- to do the link. + + if C_Plus_Plus_Is_Used then + Choose_C_Plus_Plus_Link_Process; + end if; + + -- Call gnatmake with the necessary switches for each non-Ada + -- main, if there are some. + + for Main in 1 .. Other_Mains.Last loop + declare + Source : constant Other_Source := Other_Mains.Table (Main); + begin + Last_Argument := 0; + + -- Add -o if -o was specified + + if Output_File_Name = null then + Add_Argument (Dash_o, True); + Add_Argument + (Get_Name_String + (Executable_Of + (Project => Main_Project, + Main => Other_Mains.Table (Main).File_Name, + Index => 0, + Ada_Main => False)), + True); + end if; + + -- Call gnatmake with the -B switch + + Add_Argument (Dash_B, True); + + -- Add to the linking options the object file of the source + + Add_Argument (Dash_largs, Verbose_Mode); + Add_Argument + (Get_Name_String (Source.Object_Name), Verbose_Mode); + + -- If C++ is one of the language, add the --LINK switch + -- to the linking switches. + + if C_Plus_Plus_Is_Used then + Add_C_Plus_Plus_Link_For_Gnatmake; + end if; + + -- Add -margs so that the following switches are for + -- gnatmake + + Add_Argument (Dash_margs, Verbose_Mode); + + -- And link with gnatmake + + Compile_Link_With_Gnatmake (Mains_Specified => False); + end; + end loop; + + -- If there are also Ada mains, call gnatmake for all these mains + + if Ada_Mains.Last /= 0 then + Last_Argument := 0; + + -- Put all the Ada mains as the first arguments + + for Main in 1 .. Ada_Mains.Last loop + Add_Argument (Ada_Mains.Table (Main).all, True); + end loop; + + -- If C++ is one of the languages, add the --LINK switch to + -- the linking switches. + + if Data.Languages (Lang_C_Plus_Plus) then + Add_Argument (Dash_largs, Verbose_Mode); + Add_C_Plus_Plus_Link_For_Gnatmake; + Add_Argument (Dash_margs, Verbose_Mode); + end if; + + -- And link with gnatmake + + Compile_Link_With_Gnatmake (Mains_Specified => False); + end if; + + else + -- No Ada source in main project + + -- First, get the linker to invoke + + if Data.Languages (Lang_C_Plus_Plus) then + Get_Compiler (Lang_C_Plus_Plus); + Linker_Name := Compiler_Names (Lang_C_Plus_Plus); + Linker_Path := Compiler_Paths (Lang_C_Plus_Plus); + + else + Get_Compiler (Lang_C); + Linker_Name := Compiler_Names (Lang_C); + Linker_Path := Compiler_Paths (Lang_C); + end if; + + Link_Done := False; + + Mains.Reset; + + -- Get each main, check if it is a source of the main project, + -- and if it is, invoke the linker. + + loop + declare + Main : constant String := Mains.Next_Main; + Main_Id : Name_Id; + begin + exit when Main'Length = 0; + + -- Get the file name of the main + + Name_Len := 0; + Add_Str_To_Name_Buffer (Main); + Canonical_Case_File_Name (Name_Buffer (1 .. Name_Len)); + Main_Id := Name_Find; + Source_Id := Data.First_Other_Source; + + -- Check if it is a source of the main project file + + while Source_Id /= No_Other_Source loop + Source := Other_Sources.Table (Source_Id); + exit when Source.File_Name = Main_Id; + Source_Id := Source.Next; + end loop; + + -- Report an error if it is not + + if Source_Id = No_Other_Source then + Report_Error + (Main, "is not a source of project ", + Get_Name_String (Data.Name)); + + else + declare + Executable_Name : constant String := + Get_Name_String + (Executable_Of + (Project => Main_Project, + Main => Main_Id, + Index => 0, + Ada_Main => False)); + -- File name of the executable + + Executable_Path : constant String := + Get_Name_String + (Data.Exec_Directory) & + Directory_Separator & + Executable_Name; + -- Path name of the executable + + Exec_Time_Stamp : Time_Stamp_Type; + + begin + -- Now, check if the executable is up to date. + -- It is considered up to date if its time stamp is + -- not earlier that the time stamp of any archive. + -- Only do that if we don't know if we need to link. + + if not Need_To_Relink then + + -- Get the time stamp of the executable + + Name_Len := 0; + Add_Str_To_Name_Buffer (Executable_Path); + Exec_Time_Stamp := File_Stamp (Name_Find); + + if Verbose_Mode then + Write_Str (" Checking executable "); + Write_Line (Executable_Name); + end if; + + -- If executable does not exist, we need to link + + if Exec_Time_Stamp = Empty_Time_Stamp then + Need_To_Relink := True; + + if Verbose_Mode then + Write_Line (" -> not found"); + end if; + + else + -- Otherwise, get the time stamps of each + -- archive. If one of them is found later than + -- the executable, we need to relink. + + declare + Prj_Data : Project_Data; + + begin + for Prj in 1 .. Projects.Last loop + Prj_Data := Projects.Table (Prj); + + -- There is an archive only in project + -- files with sources other than Ada + -- sources. + + if Data.Sources_Present then + declare + Archive_Path : constant String := + Get_Name_String + (Prj_Data.Object_Directory) & + Directory_Separator & + "lib" & + Get_Name_String (Prj_Data.Name) & + '.' & Archive_Ext; + Archive_TS : Time_Stamp_Type; + begin + Name_Len := 0; + Add_Str_To_Name_Buffer + (Archive_Path); + Archive_TS := File_Stamp (Name_Find); + + -- If the archive is later than the + -- executable, we need to relink. + + if Archive_TS /= Empty_Time_Stamp + and then + Exec_Time_Stamp < Archive_TS + then + Need_To_Relink := True; + + if Verbose_Mode then + Write_Str (" -> "); + Write_Str (Archive_Path); + Write_Str (" has time stamp "); + Write_Str ("later than "); + Write_Line ("executable"); + end if; + + exit; + end if; + end; + end if; + end loop; + end; + end if; + + -- If Need_To_Relink is False, we are done + + if Verbose_Mode and (not Need_To_Relink) then + Write_Line (" -> up to date"); + end if; + + end if; + + -- Prepare to link + + if Need_To_Relink then + Link_Done := True; + + Last_Argument := 0; + + -- Specify the executable path name + + Add_Argument (Dash_o, True); + Add_Argument + (Get_Name_String (Data.Exec_Directory) & + Directory_Separator & + Get_Name_String + (Executable_Of + (Project => Main_Project, + Main => Main_Id, + Index => 0, + Ada_Main => False)), + True); + + -- Specify the object file of the main source + + Add_Argument + (Object_Dir & Directory_Separator & + Get_Name_String (Source.Object_Name), + True); + + -- Add the switches specified in attribute + -- Linker_Options of packages Linker. + + if Link_Options_Switches = null then + Link_Options_Switches := + new Argument_List' + (Linker_Options_Switches (Main_Project)); + end if; + + Add_Arguments (Link_Options_Switches.all, True); + + -- Add the linking options specified on the + -- command line. + + for Arg in 1 .. Linker_Options.Last loop + Add_Argument (Linker_Options.Table (Arg), True); + end loop; + + -- Add all the archives, in a correct order + + Add_Archives (For_Gnatmake => False); + + -- If there are shared libraries and the run path + -- option is supported, add the run path switch. + + if Lib_Path.Last > 0 then + Add_Argument + (Path_Option.all & + String (Lib_Path.Table (1 .. Lib_Path.Last)), + Verbose_Mode); + end if; + + -- And invoke the linker + + Display_Command (Linker_Name.all, Linker_Path); + Spawn + (Linker_Path.all, + Arguments (1 .. Last_Argument), + Success); + + if not Success then + Report_Error ("could not link ", Main); + end if; + end if; + end; + end if; + end; + end loop; + + -- If no linking was done, report it, except in Quiet Output + + if (Verbose_Mode or (not Quiet_Output)) and (not Link_Done) then + Osint.Write_Program_Name; + + if Mains.Number_Of_Mains = 1 then + -- If there is only one executable, report its name too + + Write_Str (": """); + Mains.Reset; + + declare + Main : constant String := Mains.Next_Main; + Main_Id : Name_Id; + begin + Name_Len := 0; + Add_Str_To_Name_Buffer (Main); + Main_Id := Name_Find; + Write_Str + (Get_Name_String + (Executable_Of + (Project => Main_Project, + Main => Main_Id, + Index => 0, + Ada_Main => False))); + Write_Line (""" up to date"); + end; + + else + Write_Line (": all executables up to date"); + end if; + end if; + end if; + end if; + end Link_Executables; + + ------------------ + -- Report_Error -- + ------------------ + + procedure Report_Error + (S1 : String; + S2 : String := ""; + S3 : String := "") + is + begin + -- If Keep_Going is True, output the error message, preceded by the + -- error header. + + if Keep_Going then + Total_Number_Of_Errors := Total_Number_Of_Errors + 1; + Write_Str (Error_Header); + Write_Str (S1); + Write_Str (S2); + Write_Str (S3); + Write_Eol; + + else + -- Otherwise, just fail + + Osint.Fail (S1, S2, S3); + end if; + end Report_Error; + + ------------------------- + -- Report_Total_Errors -- + ------------------------- + + procedure Report_Total_Errors (Kind : String) is + begin + if Total_Number_Of_Errors /= 0 then + if Total_Number_Of_Errors = 1 then + Osint.Fail + ("One ", Kind, " error"); + + else + Osint.Fail + ("Total of" & Total_Number_Of_Errors'Img, + ' ' & Kind & " errors"); + end if; + end if; + end Report_Total_Errors; + + -------------- + -- Scan_Arg -- + -------------- + + procedure Scan_Arg (Arg : String) is + begin + pragma Assert (Arg'First = 1); + + if Arg'Length = 0 then + return; + end if; + + -- If preceding switch was -P, a project file name need to be specified, + -- not a switch. + + if Project_File_Name_Expected then + if Arg (1) = '-' then + Osint.Fail ("project file name missing after -P"); + else + Project_File_Name_Expected := False; + Project_File_Name := new String'(Arg); + end if; + + -- If preceding switch was -o, an executable name need to be specidied, + -- not a switch. + + elsif Output_File_Name_Expected then + if Arg (1) = '-' then + Osint.Fail ("output file name missing after -o"); + else + Output_File_Name_Expected := False; + Output_File_Name := new String'(Arg); + end if; + + -- Set the processor/language for the following switches + + -- -c???args: Compiler arguments + + elsif Arg'Length >= 6 and then + Arg (Arg'First .. Arg'First + 1) = "-c" and then + Arg (Arg'Last - 3 .. Arg'Last) = "args" + + then + declare + OK : Boolean := False; + Args_String : constant String := + Arg (Arg'First + 2 .. Arg'Last - 4); + + begin + for Lang in Programming_Language loop + if Args_String = Lang_Args (Lang).all then + OK := True; + Current_Language := Lang; + exit; + end if; + end loop; + + if OK then + Current_Processor := Compiler; + + else + Osint.Fail ("illegal option """, Arg, """"); + end if; + end; + + elsif Arg = "-largs" then + Current_Processor := Linker; + + -- -gargs: gprmake + + elsif Arg = "-gargs" then + Current_Processor := None; + + -- A special test is needed for the -o switch within a -largs since + -- that is another way to specify the name of the final executable. + + elsif Current_Processor = Linker and then Arg = "-o" then + Osint.Fail + ("switch -o not allowed within a -largs. Use -o directly."); + + -- If current processor is not gprmake dirrectly, store the option in + -- the appropriate table. + + elsif Current_Processor /= None then + Add_Option (Arg); + + -- Switches start with '-' + + elsif Arg (1) = '-' then + if Arg = "-c" then + Compile_Only := True; + + elsif Arg = "-f" then + Force_Compilations := True; + + elsif Arg = "-h" then + Usage; + + elsif Arg = "-k" then + Keep_Going := True; + + elsif Arg = "-o" then + if Output_File_Name /= null then + Osint.Fail ("cannot specify several -o switches"); + + else + Output_File_Name_Expected := True; + end if; + + elsif Arg'Length >= 2 and then Arg (2) = 'P' then + if Project_File_Name /= null then + Osint.Fail ("cannot have several project files specified"); + + elsif Arg'Length = 2 then + Project_File_Name_Expected := True; + + else + Project_File_Name := new String'(Arg (3 .. Arg'Last)); + end if; + + elsif Arg = "-q" then + Quiet_Output := True; + + elsif Arg = "-u" then + Unique_Compile := True; + Compile_Only := True; + + elsif Arg = "-v" then + Verbose_Mode := True; + + elsif Arg'Length = 4 and then Arg (1 .. 3) = "-vP" + and then Arg (4) in '0' .. '2' + then + case Arg (4) is + when '0' => + Current_Verbosity := Prj.Default; + when '1' => + Current_Verbosity := Prj.Medium; + when '2' => + Current_Verbosity := Prj.High; + when others => + null; + end case; + + elsif Arg'Length >= 3 and then Arg (2) = 'X' + and then Is_External_Assignment (Arg) + then + -- Is_External_Assignment has side effects + -- when it returns True; + + null; + + else + Osint.Fail ("illegal option """, Arg, """"); + end if; + + else + -- Not a switch: must be a main + + Mains.Add_Main (Arg); + end if; + end Scan_Arg; + + ----------------- + -- Strip_CR_LF -- + ----------------- + + function Strip_CR_LF (Text : String) return String is + + To : String (1 .. Text'Length); + Index_To : Natural := 0; + + begin + for Index in Text'Range loop + if (Text (Index) /= ASCII.CR) and then (Text (Index) /= ASCII.LF) then + Index_To := Index_To + 1; + To (Index_To) := Text (Index); + end if; + end loop; + + return To (1 .. Index_To); + end Strip_CR_LF; + + ----------- + -- Usage -- + ----------- + + procedure Usage is + begin + if not Usage_Output then + Usage_Output := True; + Copyright; + + Write_Str ("Usage: "); + Osint.Write_Program_Name; + Write_Str (" -P<project file> [opts] [name] {"); + + for Lang in Programming_Language loop + Write_Str ("[-c"); + Write_Str (Lang_Args (Lang).all); + Write_Str ("args opts] "); + end loop; + + Write_Str ("[-largs opts] [-gargs opts]}"); + Write_Eol; + Write_Eol; + Write_Str (" name is zero or more file names"); + Write_Eol; + Write_Eol; + + -- GPRMAKE switches + + Write_Str ("gprmake switches:"); + Write_Eol; + + -- Line for -c + + Write_Str (" -c Compile only"); + Write_Eol; + + -- Line for -f + + Write_Str (" -f Force recompilations"); + Write_Eol; + + -- Line for -k + + Write_Str (" -k Keep going after compilation errors"); + Write_Eol; + + -- Line for -o + + Write_Str (" -o name Choose an alternate executable name"); + Write_Eol; + + -- Line for -P + + Write_Str (" -Pproj Use GNAT Project File proj"); + Write_Eol; + + -- Line for -q + + Write_Str (" -q Be quiet/terse"); + Write_Eol; + + -- Line for -u + + Write_Str + (" -u Unique compilation. Only compile the given files"); + Write_Eol; + + -- Line for -v + + Write_Str (" -v Verbose output"); + Write_Eol; + + -- Line for -vPx + + Write_Str (" -vPx Specify verbosity when parsing Project Files"); + Write_Eol; + + -- Line for -X + + Write_Str (" -Xnm=val Specify an external reference for " & + "Project Files"); + Write_Eol; + Write_Eol; + + -- Lines for -c*args + + for Lang in Programming_Language loop + declare + Column : Positive := 13 + Lang_Args (Lang)'Length; + -- " -cargs opts" is the minimum and is 13 character long + + begin + Write_Str (" -c"); + Write_Str (Lang_Args (Lang).all); + Write_Str ("args opts"); + + loop + Write_Char (' '); + Column := Column + 1; + exit when Column >= 17; + end loop; + + Write_Str ("opts are passed to the "); + Write_Str (Lang_Display_Names (Lang).all); + Write_Str (" compiler"); + Write_Eol; + end; + end loop; + + -- Line for -largs + + Write_Str (" -largs opts opts are passed to the linker"); + Write_Eol; + + -- Line for -gargs + + Write_Str (" -gargs opts opts directly interpreted by gprmake"); + Write_Eol; + Write_Eol; + + end if; + end Usage; + +begin + Makeutl.Do_Fail := Report_Error'Access; +end Makegpr; diff --git a/gcc/ada/makegpr.ads b/gcc/ada/makegpr.ads new file mode 100644 index 00000000000..fc751e86411 --- /dev/null +++ b/gcc/ada/makegpr.ads @@ -0,0 +1,35 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- M A K E G P R -- +-- -- +-- S p e c -- +-- -- +-- Copyright (C) 2004 Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 2, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- 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, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +-- The following package implements the facilities to compile, bind and/or +-- link a set of Ada and non Ada sources, specified in Project Files. + +package Makegpr is + + procedure Gprmake; + -- The driver of gprmake. + +end Makegpr; diff --git a/gcc/config/mips/4130.md b/gcc/config/mips/4130.md new file mode 100644 index 00000000000..eddc405de34 --- /dev/null +++ b/gcc/config/mips/4130.md @@ -0,0 +1,136 @@ +;; +;; Pipeline description for the VR4130 family. +;; +;; The processor issues each 8-byte aligned pair of instructions together, +;; stalling the second instruction if it depends on the first. Thus, if we +;; want two instructions to issue in parallel, we need to make sure that the +;; first one is 8-byte aligned. +;; +;; For the purposes of this pipeline description, we treat the processor +;; like a standard two-way superscalar architecture. If scheduling were +;; the last pass to run, we could use the scheduler hooks to vary the +;; issue rate depending on whether an instruction is at an aligned or +;; unaligned address. Unfortunately, delayed branch scheduling and +;; hazard avoidance are done after the final scheduling pass, and they +;; can change the addresses of many instructions. +;; +;; We get around this in two ways: +;; +;; (1) By running an extra pass at the end of compilation. This pass goes +;; through the function looking for pairs of instructions that could +;; execute in parallel. It makes sure that the first instruction in +;; each pair is suitably aligned, inserting nops if necessary. Doing +;; this gives the same kind of pipeline behavior we would see on a +;; normal superscalar target. +;; +;; This pass is generally a speed improvement, but the extra nops will +;; obviously make the program bigger. It is therefore unsuitable for +;; -Os (at the very least). +;; +;; (2) By modifying the scheduler hooks so that, where possible: +;; +;; (a) dependent instructions are separated by a non-dependent +;; instruction; +;; +;; (b) instructions that use the multiplication unit are separated +;; by non-multiplication instructions; and +;; +;; (c) memory access instructions are separated by non-memory +;; instructions. +;; +;; The idea is to keep conflicting instructions apart wherever possible +;; and thus make the schedule less dependent on alignment. + +(define_automaton "vr4130_main, vr4130_muldiv, vr4130_mulpre") + +(define_cpu_unit "vr4130_alu1, vr4130_alu2, vr4130_dcache" "vr4130_main") +(define_cpu_unit "vr4130_muldiv" "vr4130_muldiv") + +;; This is a fake unit for pre-reload scheduling of multiplications. +;; It enforces the true post-reload repeat rate. +(define_cpu_unit "vr4130_mulpre" "vr4130_mulpre") + +;; The scheduling hooks use this attribute for (b) above. +(define_attr "vr4130_class" "mul,mem,alu" + (cond [(eq_attr "type" "load,store") + (const_string "mem") + + (eq_attr "type" "mfhilo,mthilo,imul,imadd,idiv") + (const_string "mul")] + (const_string "alu"))) + +(define_insn_reservation "vr4130_multi" 1 + (and (eq_attr "cpu" "r4130") + (eq_attr "type" "multi,unknown")) + "vr4130_alu1 + vr4130_alu2 + vr4130_dcache + vr4130_muldiv") + +(define_insn_reservation "vr4130_int" 1 + (and (eq_attr "cpu" "r4130") + (eq_attr "type" "const,arith,shift,slt,nop")) + "vr4130_alu1 | vr4130_alu2") + +(define_insn_reservation "vr4130_load" 3 + (and (eq_attr "cpu" "r4130") + (eq_attr "type" "load")) + "vr4130_dcache") + +(define_insn_reservation "vr4130_store" 1 + (and (eq_attr "cpu" "r4130") + (eq_attr "type" "store")) + "vr4130_dcache") + +(define_insn_reservation "vr4130_mfhilo" 3 + (and (eq_attr "cpu" "r4130") + (eq_attr "type" "mfhilo")) + "vr4130_muldiv") + +(define_insn_reservation "vr4130_mthilo" 1 + (and (eq_attr "cpu" "r4130") + (eq_attr "type" "mthilo")) + "vr4130_muldiv") + +;; The product is available in LO & HI after one cycle. Moving the result +;; into an integer register will take an additional three cycles, see mflo +;; & mfhi above. Note that the same latencies and repeat rates apply if we +;; use "mtlo; macc" instead of "mult; mflo". +(define_insn_reservation "vr4130_mulsi" 4 + (and (eq_attr "cpu" "r4130") + (and (eq_attr "type" "imul") + (eq_attr "mode" "SI"))) + "vr4130_muldiv + (vr4130_mulpre * 2)") + +;; As for vr4130_mulsi, but the product is available in LO and HI +;; after 3 cycles. +(define_insn_reservation "vr4130_muldi" 6 + (and (eq_attr "cpu" "r4130") + (and (eq_attr "type" "imul") + (eq_attr "mode" "DI"))) + "(vr4130_muldiv * 3) + (vr4130_mulpre * 4)") + +;; maccs can execute in consecutive cycles without stalling, but it +;; is 3 cycles before the integer destination can be read. +(define_insn_reservation "vr4130_macc" 3 + (and (eq_attr "cpu" "r4130") + (eq_attr "type" "imadd")) + "vr4130_muldiv") + +(define_bypass 1 "vr4130_mulsi,vr4130_macc" "vr4130_macc" "mips_linked_madd_p") +(define_bypass 1 "vr4130_mulsi,vr4130_macc" "vr4130_mfhilo") +(define_bypass 3 "vr4130_muldi" "vr4130_mfhilo") + +(define_insn_reservation "vr4130_divsi" 36 + (and (eq_attr "cpu" "r4130") + (and (eq_attr "type" "idiv") + (eq_attr "mode" "SI"))) + "vr4130_muldiv * 36") + +(define_insn_reservation "vr4130_divdi" 72 + (and (eq_attr "cpu" "r4130") + (and (eq_attr "type" "idiv") + (eq_attr "mode" "DI"))) + "vr4130_muldiv * 72") + +(define_insn_reservation "vr4130_branch" 0 + (and (eq_attr "cpu" "r4130") + (eq_attr "type" "branch,jump,call")) + "vr4130_alu1 | vr4130_alu2") diff --git a/gcc/testsuite/g++.dg/ext/altivec-8.C b/gcc/testsuite/g++.dg/ext/altivec-8.C new file mode 100644 index 00000000000..9f4892df860 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/altivec-8.C @@ -0,0 +1,20 @@ +/* { dg-do compile { target powerpc*-*-* } } */ +/* { dg-options "-maltivec" } */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ + +/* This test case exercises intrinsic/argument combinations that, + while not in the Motorola AltiVec PIM, have nevertheless crept + into the AltiVec vernacular over the years. */ + +#include <altivec.h> + +void foo (void) +{ + vector bool int boolVec1 = (vector bool int) vec_splat_u32(3); + vector bool short boolVec2 = (vector bool short) vec_splat_u16(3); + vector bool char boolVec3 = (vector bool char) vec_splat_u8(3); + + boolVec1 = vec_sld( boolVec1, boolVec1, 4 ); + boolVec2 = vec_sld( boolVec2, boolVec2, 2 ); + boolVec3 = vec_sld( boolVec3, boolVec3, 1 ); +} diff --git a/gcc/testsuite/g++.dg/ext/altivec-9.C b/gcc/testsuite/g++.dg/ext/altivec-9.C new file mode 100644 index 00000000000..cb7e4bb4e72 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/altivec-9.C @@ -0,0 +1,13 @@ +/* Test for AltiVec function vec_ld, passing a pointer to const vector */ +/* { dg-do compile { target powerpc*-*-* } } */ +/* { dg-options "-maltivec" } */ + +#include <altivec.h> + +typedef vector unsigned char vuc_t; +const vuc_t* p; +vector unsigned char test_vec_ld() +{ + return vec_ld(0,p); +} + diff --git a/gcc/testsuite/g++.dg/ext/spe1.C b/gcc/testsuite/g++.dg/ext/spe1.C new file mode 100644 index 00000000000..b9ae5e7d135 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/spe1.C @@ -0,0 +1,9 @@ +/* { dg-do compile { target powerpc-*-eabi* } } */ +/* { dg-options "-mcpu=8540 -mabi=spe -O0" } */ + +typedef int v2si __attribute__ ((vector_size (8))); + +/* The two specializations must be considered different. */ +template <class T> class X { }; +template <> class X<__ev64_opaque__> { }; +template <> class X<v2si> { }; diff --git a/gcc/testsuite/g++.dg/opt/pr15054.C b/gcc/testsuite/g++.dg/opt/pr15054.C new file mode 100644 index 00000000000..cfc48cf2498 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/pr15054.C @@ -0,0 +1,36 @@ +// PR middle-end/15054 +// This used to abort due to overlapping stack temporaries. + +// { dg-do run } +// { dg-options "-O" } + +extern "C" void abort (void); + +struct pointer +{ + void* ptr; + + pointer(void* x = 0) : ptr(x) {} + pointer(const pointer& x) : ptr(x.ptr) {} +}; + +struct element +{ + int canary; + + element() : canary(123) { } + ~element() { pointer(); if (canary != 123) abort (); } +}; + +inline pointer +insert(const element& x) +{ + return pointer(new element(x)); +} + +int +main (void) +{ + insert(element()); + return 0; +} diff --git a/gcc/testsuite/g++.dg/other/pragma-re-2.C b/gcc/testsuite/g++.dg/other/pragma-re-2.C new file mode 100644 index 00000000000..44d1b50f699 --- /dev/null +++ b/gcc/testsuite/g++.dg/other/pragma-re-2.C @@ -0,0 +1,25 @@ +/* PR c++/14962 */ +/* Originator: <phil@fsel.com> */ + +/* { dg-do compile { target *-*-solaris* } } */ +/* { dg-final { scan-assembler "new_name" } } */ +/* { dg-final { scan-assembler-not "old_name" } } */ + +#ifndef __PRAGMA_REDEFINE_EXTNAME +#error +#endif + +extern "C" { + +struct old_name { int i; }; + +#pragma redefine_extname old_name new_name + +int old_name(void); + +} + +int foo(void) +{ + return old_name(); +} diff --git a/gcc/testsuite/g++.dg/template/member5.C b/gcc/testsuite/g++.dg/template/member5.C new file mode 100644 index 00000000000..45dcd6c6c66 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/member5.C @@ -0,0 +1,32 @@ +// { dg-do compile } +// Contributed by: <fasbjx at free dot fr> +// PR c++/14389: Disambiguate overloaded member templates which differ only +// in the template argument list. + +namespace N1 { + +struct S { + template< typename B, typename A > void foo(); + template< typename A > void foo(); +}; + +template< typename A > void S::foo() {} +template< typename B, typename A > void S::foo() {} + +template void S::foo<void> (); +template void S::foo<void,void> (); + +} + +namespace N2 { + +struct S { + template< typename _A > void foo(); + template< int _i > void foo(); +}; + +template< typename _A > void S::foo() {} + +template void S::foo< 0 >(); // { dg-error "no definition available|instantiated from here" } + +} diff --git a/gcc/testsuite/gcc.c-torture/execute/divcmp-1.c b/gcc/testsuite/gcc.c-torture/execute/divcmp-1.c new file mode 100644 index 00000000000..0a7f305aa7c --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/divcmp-1.c @@ -0,0 +1,356 @@ +extern void abort(void); + +int test1(int x) +{ + return x/10 == 2; +} + +int test1u(unsigned int x) +{ + return x/10U == 2; +} + +int test2(int x) +{ + return x/10 == 0; +} + +int test2u(unsigned int x) +{ + return x/10U == 0; +} + +int test3(int x) +{ + return x/10 != 2; +} + +int test3u(unsigned int x) +{ + return x/10U != 2; +} + +int test4(int x) +{ + return x/10 != 0; +} + +int test4u(unsigned int x) +{ + return x/10U != 0; +} + +int test5(int x) +{ + return x/10 < 2; +} + +int test5u(unsigned int x) +{ + return x/10U < 2; +} + +int test6(int x) +{ + return x/10 < 0; +} + +int test7(int x) +{ + return x/10 <= 2; +} + +int test7u(unsigned int x) +{ + return x/10U <= 2; +} + +int test8(int x) +{ + return x/10 <= 0; +} + +int test8u(unsigned int x) +{ + return x/10U <= 0; +} + +int test9(int x) +{ + return x/10 > 2; +} + +int test9u(unsigned int x) +{ + return x/10U > 2; +} + +int test10(int x) +{ + return x/10 > 0; +} + +int test10u(unsigned int x) +{ + return x/10U > 0; +} + +int test11(int x) +{ + return x/10 >= 2; +} + +int test11u(unsigned int x) +{ + return x/10U >= 2; +} + +int test12(int x) +{ + return x/10 >= 0; +} + + +int main() +{ + if (test1(19) != 0) + abort (); + if (test1(20) != 1) + abort (); + if (test1(29) != 1) + abort (); + if (test1(30) != 0) + abort (); + + if (test1u(19) != 0) + abort (); + if (test1u(20) != 1) + abort (); + if (test1u(29) != 1) + abort (); + if (test1u(30) != 0) + abort (); + + if (test2(0) != 1) + abort (); + if (test2(9) != 1) + abort (); + if (test2(10) != 0) + abort (); + if (test2(-1) != 1) + abort (); + if (test2(-9) != 1) + abort (); + if (test2(-10) != 0) + abort (); + + if (test2u(0) != 1) + abort (); + if (test2u(9) != 1) + abort (); + if (test2u(10) != 0) + abort (); + if (test2u(-1) != 0) + abort (); + if (test2u(-9) != 0) + abort (); + if (test2u(-10) != 0) + abort (); + + if (test3(19) != 1) + abort (); + if (test3(20) != 0) + abort (); + if (test3(29) != 0) + abort (); + if (test3(30) != 1) + abort (); + + if (test3u(19) != 1) + abort (); + if (test3u(20) != 0) + abort (); + if (test3u(29) != 0) + abort (); + if (test3u(30) != 1) + abort (); + + if (test4(0) != 0) + abort (); + if (test4(9) != 0) + abort (); + if (test4(10) != 1) + abort (); + if (test4(-1) != 0) + abort (); + if (test4(-9) != 0) + abort (); + if (test4(-10) != 1) + abort (); + + if (test4u(0) != 0) + abort (); + if (test4u(9) != 0) + abort (); + if (test4u(10) != 1) + abort (); + if (test4u(-1) != 1) + abort (); + if (test4u(-9) != 1) + abort (); + if (test4u(-10) != 1) + abort (); + + if (test5(19) != 1) + abort (); + if (test5(20) != 0) + abort (); + if (test5(29) != 0) + abort (); + if (test5(30) != 0) + abort (); + + if (test5u(19) != 1) + abort (); + if (test5u(20) != 0) + abort (); + if (test5u(29) != 0) + abort (); + if (test5u(30) != 0) + abort (); + + if (test6(0) != 0) + abort (); + if (test6(9) != 0) + abort (); + if (test6(10) != 0) + abort (); + if (test6(-1) != 0) + abort (); + if (test6(-9) != 0) + abort (); + if (test6(-10) != 1) + abort (); + + if (test7(19) != 1) + abort (); + if (test7(20) != 1) + abort (); + if (test7(29) != 1) + abort (); + if (test7(30) != 0) + abort (); + + if (test7u(19) != 1) + abort (); + if (test7u(20) != 1) + abort (); + if (test7u(29) != 1) + abort (); + if (test7u(30) != 0) + abort (); + + if (test8(0) != 1) + abort (); + if (test8(9) != 1) + abort (); + if (test8(10) != 0) + abort (); + if (test8(-1) != 1) + abort (); + if (test8(-9) != 1) + abort (); + if (test8(-10) != 1) + abort (); + + if (test8u(0) != 1) + abort (); + if (test8u(9) != 1) + abort (); + if (test8u(10) != 0) + abort (); + if (test8u(-1) != 0) + abort (); + if (test8u(-9) != 0) + abort (); + if (test8u(-10) != 0) + abort (); + + if (test9(19) != 0) + abort (); + if (test9(20) != 0) + abort (); + if (test9(29) != 0) + abort (); + if (test9(30) != 1) + abort (); + + if (test9u(19) != 0) + abort (); + if (test9u(20) != 0) + abort (); + if (test9u(29) != 0) + abort (); + if (test9u(30) != 1) + abort (); + + if (test10(0) != 0) + abort (); + if (test10(9) != 0) + abort (); + if (test10(10) != 1) + abort (); + if (test10(-1) != 0) + abort (); + if (test10(-9) != 0) + abort (); + if (test10(-10) != 0) + abort (); + + if (test10u(0) != 0) + abort (); + if (test10u(9) != 0) + abort (); + if (test10u(10) != 1) + abort (); + if (test10u(-1) != 1) + abort (); + if (test10u(-9) != 1) + abort (); + if (test10u(-10) != 1) + abort (); + + if (test11(19) != 0) + abort (); + if (test11(20) != 1) + abort (); + if (test11(29) != 1) + abort (); + if (test11(30) != 1) + abort (); + + if (test11u(19) != 0) + abort (); + if (test11u(20) != 1) + abort (); + if (test11u(29) != 1) + abort (); + if (test11u(30) != 1) + abort (); + + if (test12(0) != 1) + abort (); + if (test12(9) != 1) + abort (); + if (test12(10) != 1) + abort (); + if (test12(-1) != 1) + abort (); + if (test12(-9) != 1) + abort (); + if (test12(-10) != 0) + abort (); + + return 0; +} + diff --git a/gcc/testsuite/gcc.c-torture/execute/divcmp-2.c b/gcc/testsuite/gcc.c-torture/execute/divcmp-2.c new file mode 100644 index 00000000000..b059b8fbaec --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/divcmp-2.c @@ -0,0 +1,92 @@ +extern void abort (void); + +int test1(int x) +{ + return x/10 == 2; +} + +int test2(int x) +{ + return x/10 == 0; +} + +int test3(int x) +{ + return x/10 == -2; +} + +int test4(int x) +{ + return x/-10 == 2; +} + +int test5(int x) +{ + return x/-10 == 0; +} + +int test6(int x) +{ + return x/-10 == -2; +} + + +int main() +{ + if (test1(19) != 0) + abort (); + if (test1(20) != 1) + abort (); + if (test1(29) != 1) + abort (); + if (test1(30) != 0) + abort (); + + if (test2(-10) != 0) + abort (); + if (test2(-9) != 1) + abort (); + if (test2(9) != 1) + abort (); + if (test2(10) != 0) + abort (); + + if (test3(-30) != 0) + abort (); + if (test3(-29) != 1) + abort (); + if (test3(-20) != 1) + abort (); + if (test3(-19) != 0) + abort (); + + if (test4(-30) != 0) + abort (); + if (test4(-29) != 1) + abort (); + if (test4(-20) != 1) + abort (); + if (test4(-19) != 0) + abort (); + + if (test5(-10) != 0) + abort (); + if (test5(-9) != 1) + abort (); + if (test5(9) != 1) + abort (); + if (test5(10) != 0) + abort (); + + if (test6(19) != 0) + abort (); + if (test6(20) != 1) + abort (); + if (test6(29) != 1) + abort (); + if (test6(30) != 0) + abort (); + + return 0; +} + diff --git a/gcc/testsuite/gcc.c-torture/execute/divcmp-3.c b/gcc/testsuite/gcc.c-torture/execute/divcmp-3.c new file mode 100644 index 00000000000..ba52c9e2414 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/divcmp-3.c @@ -0,0 +1,97 @@ +extern void abort(void); + +int test1(char x) +{ + return x/100 == 3; +} + +int test1u(unsigned char x) +{ + return x/100 == 3; +} + +int test2(char x) +{ + return x/100 != 3; +} + +int test2u(unsigned char x) +{ + return x/100 != 3; +} + +int test3(char x) +{ + return x/100 < 3; +} + +int test3u(unsigned char x) +{ + return x/100 < 3; +} + +int test4(char x) +{ + return x/100 <= 3; +} + +int test4u(unsigned char x) +{ + return x/100 <= 3; +} + +int test5(char x) +{ + return x/100 > 3; +} + +int test5u(unsigned char x) +{ + return x/100 > 3; +} + +int test6(char x) +{ + return x/100 >= 3; +} + +int test6u(unsigned char x) +{ + return x/100 >= 3; +} + + +int main() +{ + int c; + + for (c=-128; c<256; c++) + { + if (test1(c) != 0) + abort (); + if (test1u(c) != 0) + abort (); + if (test2(c) != 1) + abort (); + if (test2u(c) != 1) + abort (); + if (test3(c) != 1) + abort (); + if (test3u(c) != 1) + abort (); + if (test4(c) != 1) + abort (); + if (test4u(c) != 1) + abort (); + if (test5(c) != 0) + abort (); + if (test5u(c) != 0) + abort (); + if (test6(c) != 0) + abort (); + if (test6u(c) != 0) + abort (); + } + return 0; +} + diff --git a/gcc/testsuite/gcc.c-torture/execute/pr15296.c b/gcc/testsuite/gcc.c-torture/execute/pr15296.c new file mode 100644 index 00000000000..d2468e425af --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr15296.c @@ -0,0 +1,73 @@ +/* PR optimization/15296. The delayed-branch scheduler caused code that + SEGV:d for CRIS; a register was set to -1 in a delay-slot for the + fall-through code, while that register held a pointer used in code at + the branch target. */ + +typedef int __attribute__ ((mode (__pointer__))) intptr_t; +typedef intptr_t W; +union u0 +{ + union u0 *r; + W i; +}; +struct s1 +{ + union u0 **m0; + union u0 m1[4]; +}; + +void f (void *, struct s1 *, const union u0 *, W, W, W) + __attribute__ ((__noinline__)); +void g (void *, char *) __attribute__ ((__noinline__)); + +void +f (void *a, struct s1 *b, const union u0 *h, W v0, W v1, W v4) +{ + union u0 *e = 0; + union u0 *k = 0; + union u0 **v5 = b->m0; + union u0 *c = b->m1; + union u0 **d = &v5[0]; +l0:; + if (v0 < v1) + goto l0; + if (v0 == 0) + goto l3; + v0 = v4; + if (v0 != 0) + goto l3; + c[0].r = *d; + v1 = -1; + e = c[0].r; + if (e != 0) + g (a, ""); + k = e + 3; + k->i = v1; + goto l4; +l3:; + c[0].i = v0; + e = c[1].r; + if (e != 0) + g (a, ""); + e = c[0].r; + if (e == 0) + g (a, ""); + k = e + 2; + k->r = c[1].r; +l4:; +} + +void g (void *a, char *b) { abort (); } + +int +main () +{ + union u0 uv[] = {{ .i = 111 }, { .i = 222 }, { .i = 333 }, { .i = 444 }}; + struct s1 s = { 0, {{ .i = 555 }, { .i = 0 }, { .i = 999 }, { .i = 777 }}}; + f (0, &s, 0, 20000, 10000, (W) uv); + if (s.m1[0].i != (W) uv || s.m1[1].i != 0 || s.m1[2].i != 999 + || s.m1[3].i != 777 || uv[0].i != 111 || uv[1].i != 222 + || uv[2].i != 0 || uv[3].i != 444) + abort (); + exit (0); +} diff --git a/gcc/testsuite/gcc.dg/altivec-13.c b/gcc/testsuite/gcc.dg/altivec-13.c new file mode 100644 index 00000000000..c377442196b --- /dev/null +++ b/gcc/testsuite/gcc.dg/altivec-13.c @@ -0,0 +1,20 @@ +/* { dg-do compile { target powerpc*-*-* } } */ +/* { dg-options "-maltivec" } */ +/* Author: Ziemowit Laski <zlaski@apple.com> */ + +/* This test case exercises intrinsic/argument combinations that, + while not in the Motorola AltiVec PIM, have nevertheless crept + into the AltiVec vernacular over the years. */ + +#include <altivec.h> + +void foo (void) +{ + vector bool int boolVec1 = (vector bool int) vec_splat_u32(3); + vector bool short boolVec2 = (vector bool short) vec_splat_u16(3); + vector bool char boolVec3 = (vector bool char) vec_splat_u8(3); + + boolVec1 = vec_sld( boolVec1, boolVec1, 4 ); + boolVec2 = vec_sld( boolVec2, boolVec2, 2 ); + boolVec3 = vec_sld( boolVec3, boolVec3, 1 ); +} diff --git a/gcc/testsuite/gcc.dg/builtins-40.c b/gcc/testsuite/gcc.dg/builtins-40.c new file mode 100644 index 00000000000..405c8723309 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtins-40.c @@ -0,0 +1,47 @@ +/* Copyright (C) 2004 Free Software Foundation. + + Check that fmod, fmodf, fmodl, drem, dremf and dreml + built-in functions compile. + + Written by Uros Bizjak, 5th May 2004. */ + +/* { dg-do compile } */ +/* { dg-options "-O2 -ffast-math" } */ + +extern double fmod(double, double); +extern double drem(double, double); +extern float fmodf(float, float); +extern float dremf(float, float); +extern long double fmodl(long double, long double); +extern long double dreml(long double, long double); + + +double test1(double x, double y) +{ + return fmod(x, y); +} + +double test2(double x, double y) +{ + return drem(x, y); +} + +float test1f(float x, float y) +{ + return fmodf(x, y); +} + +float test2f(float x, float y) +{ + return dremf(x, y); +} + +long double test1l(long double x, long double y) +{ + return fmodl(x, y); +} + +long double test2l(long double x, long double y) +{ + return dreml(x, y); +} diff --git a/gcc/testsuite/gcc.dg/rs6000-power2-1.c b/gcc/testsuite/gcc.dg/rs6000-power2-1.c new file mode 100644 index 00000000000..7d344a93a2c --- /dev/null +++ b/gcc/testsuite/gcc.dg/rs6000-power2-1.c @@ -0,0 +1,21 @@ +/* { dg-do compile { target powerpc-*-* rs6000-*-* } } */ +/* { dg-options "-O3 -mcpu=power2 -fno-schedule-insns -w -mhard-float" } */ +/* This used to ICE as the peephole was not checking to see + if the register is a floating point one (I think this cannot + happen in real life except in this example). */ + +register double t1 __asm__("r14"); +register double t2 __asm__("r15"); +register double t3 __asm__("r16"), t4 __asm__("r17"); +void t(double *a, double *b) +{ + t1 = a[-1]; + t2 = a[0]; + t3 = a[1]; + t4 = a[2]; + b[-1] = t1; + b[0] = t2; + b[1] = t3; + b[2] = t4; +} + diff --git a/gcc/testsuite/gcc.dg/rs6000-power2-2.c b/gcc/testsuite/gcc.dg/rs6000-power2-2.c new file mode 100644 index 00000000000..2fefbcbfb81 --- /dev/null +++ b/gcc/testsuite/gcc.dg/rs6000-power2-2.c @@ -0,0 +1,22 @@ +/* { dg-do compile { target powerpc-*-* rs6000-*-* } } */ +/* { dg-options "-O3 -mcpu=power2 -fno-schedule-insns -w -mhard-float" } */ +/* { dg-final { scan-assembler-not "lfd" } } */ +/* { dg-final { scan-assembler-not "sfd" } } */ +/* { dg-final { scan-assembler "lfq" } } */ +/* { dg-final { scan-assembler "sfq" } } */ + +register double t1 __asm__("fr0"); +register double t2 __asm__("fr1"); +register double t3 __asm__("fr2"), t4 __asm__("fr3"); +void t(double *a, double *b) +{ + t1 = a[-1]; + t2 = a[0]; + t3 = a[1]; + t4 = a[2]; + b[-1] = t1; + b[0] = t2; + b[1] = t3; + b[2] = t4; +} + diff --git a/gcc/testsuite/gcc.dg/torture/builtin-convert-3.c b/gcc/testsuite/gcc.dg/torture/builtin-convert-3.c new file mode 100644 index 00000000000..9901ceccf81 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/builtin-convert-3.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2004 Free Software Foundation. + + Verify that builtin math functions (with fixed point return types) + are converted to smaller FP types correctly by the compiler. + + Written by Kaveh Ghazi, 2004-05-01. */ + +/* { dg-do link } */ +/* { dg-options "-ffast-math" } */ + +#include "../builtins-config.h" + +#define PROTOTYPE1_RET(FN, RET) \ + extern RET FN(double); \ + extern RET FN##f(float); \ + extern RET FN##l(long double); + +/* Test converting math builtins to narrower FP types based on if the + argument is a narrower type (perhaps implicitly) cast to a wider + one. */ +#define INNER_CAST1(MATHFN, RET) \ + PROTOTYPE1_RET (MATHFN, RET); \ + extern void link_failure_inner_##MATHFN##l_##MATHFN(void); \ + extern void link_failure_inner_##MATHFN##l_##MATHFN##f(void); \ + extern void link_failure_inner_##MATHFN##_##MATHFN##f(void); \ + if (sizeof (long double) > sizeof (double) \ + && MATHFN##l(d1) != MATHFN(d1)) \ + link_failure_inner_##MATHFN##l_##MATHFN(); \ + if (sizeof (long double) > sizeof (float) \ + && MATHFN##l(f1) != MATHFN##f(f1)) \ + link_failure_inner_##MATHFN##l_##MATHFN##f(); \ + if (sizeof (long double) > sizeof (float) \ + && MATHFN##l((double)f1) != MATHFN##f(f1)) \ + link_failure_inner_##MATHFN##l_##MATHFN##f(); \ + if (sizeof (double) > sizeof (float) \ + && MATHFN(f1) != MATHFN##f(f1)) \ + link_failure_inner_##MATHFN##_##MATHFN##f() + +void __attribute__ ((__noinline__)) test (double d1, float f1) +{ +#ifdef __OPTIMIZE__ +#ifdef HAVE_C99_RUNTIME + /* We're converting to implicitly generated C99 functions. */ + INNER_CAST1 (lround, long); + INNER_CAST1 (llround, long long); + INNER_CAST1 (lrint, long); + INNER_CAST1 (llrint, long long); +#endif /* HAVE_C99_RUNTIME */ +#endif /* __OPTIMIZE__ */ +} + +int main (void) +{ + test (1, 2); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/builtin-rounding-1.c b/gcc/testsuite/gcc.dg/torture/builtin-rounding-1.c new file mode 100644 index 00000000000..4101f911e5a --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/builtin-rounding-1.c @@ -0,0 +1,106 @@ +/* Copyright (C) 2004 Free Software Foundation. + + Check that constant folding of the rounding math functions doesn't + break anything and produces the expected results. + + Written by Kaveh Ghazi, 2004-04-29. */ + +/* { dg-do link } */ + +#define PROTOTYPE(FN) \ + PROTOTYPE_LINK_ERROR(FN) \ + extern double FN (double); \ + extern float FN##f (float); \ + extern long double FN##l (long double); + +#define PROTOTYPE_RET(FN, RET) \ + PROTOTYPE_LINK_ERROR(FN) \ + extern RET FN (double); \ + extern RET FN##f (float); \ + extern RET FN##l (long double); + +#define PROTOTYPE_LINK_ERROR(FN) \ + extern void link_error_##FN(void); \ + extern void link_error_##FN##f(void); \ + extern void link_error_##FN##l(void); + +#define TEST(FN, VALUE, RESULT) \ + if (FN (VALUE) != RESULT) link_error_##FN(); \ + if (FN##f (VALUE) != RESULT) link_error_##FN##f(); \ + if (FN##l (VALUE) != RESULT) link_error_##FN##l(); \ + +PROTOTYPE (trunc); +PROTOTYPE (floor); +PROTOTYPE (ceil); +PROTOTYPE (round); +PROTOTYPE_RET (lround, long); +PROTOTYPE_RET (llround, long long); + +int +main (void) +{ + TEST(trunc, 0, 0); + TEST(floor, 0, 0); + TEST(ceil, 0, 0); + TEST(round, 0, 0); + TEST(lround, 0, 0); + TEST(llround, 0, 0); + + TEST(trunc, 6, 6); + TEST(floor, 6, 6); + TEST(ceil, 6, 6); + TEST(round, 6, 6); + TEST(lround, 6, 6); + TEST(llround, 6, 6); + + TEST(trunc, -8, -8); + TEST(floor, -8, -8); + TEST(ceil, -8, -8); + TEST(round, -8, -8); + TEST(lround, -8, -8); + TEST(llround, -8, -8); + + TEST(trunc, 3.2, 3); + TEST(floor, 3.2, 3); + TEST(ceil, 3.2, 4); + TEST(round, 3.2, 3); + TEST(lround, 3.2, 3); + TEST(llround, 3.2, 3); + + TEST(trunc, -2.8, -2); + TEST(floor, -2.8, -3); + TEST(ceil, -2.8, -2); + TEST(round, -2.8, -3); + TEST(lround, -2.8, -3); + TEST(llround, -2.8, -3); + + TEST(trunc, 0.01, 0); + TEST(floor, 0.01, 0); + TEST(ceil, 0.01, 1); + TEST(round, 0.01, 0); + TEST(lround, 0.01, 0); + TEST(llround, 0.01, 0); + + TEST(trunc, -0.7, 0); + TEST(floor, -0.7, -1); + TEST(ceil, -0.7, 0); + TEST(round, -0.7, -1); + TEST(lround, -0.7, -1); + TEST(llround, -0.7, -1); + + TEST(trunc, 2.5, 2); + TEST(floor, 2.5, 2); + TEST(ceil, 2.5, 3); + TEST(round, 2.5, 3); + TEST(lround, 2.5, 3); + TEST(llround, 2.5, 3); + + TEST(trunc, -1.5, -1); + TEST(floor, -1.5, -2); + TEST(ceil, -1.5, -1); + TEST(round, -1.5, -2); + TEST(lround, -1.5, -2); + TEST(llround, -1.5, -2); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/mips-hilo-2.c b/gcc/testsuite/gcc.dg/torture/mips-hilo-2.c new file mode 100644 index 00000000000..0bdff6cd32c --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/mips-hilo-2.c @@ -0,0 +1,28 @@ +/* Due to a reload inheritance bug, the asm statement in f() would be passed + the low part of u.ll on little-endian 32-bit targets. */ +/* { dg-do run { target mips*-*-* } } */ + +#if !defined(__mips16) +unsigned int g; + +unsigned long long f (unsigned int x) +{ + union { unsigned long long ll; unsigned int parts[2]; } u; + + u.ll = ((unsigned long long) x * x); + asm ("mflo\t%0" : "=r" (g) : "l" (u.parts[1])); + return u.ll; +} + +int main () +{ + union { unsigned long long ll; unsigned int parts[2]; } u; + + u.ll = f (0x12345678); + if (g != u.parts[1]) + abort (); + exit (0); +} +#else +int main () { exit (0); } +#endif diff --git a/libjava/gnu/java/text/AttributedFormatBuffer.java b/libjava/gnu/java/text/AttributedFormatBuffer.java new file mode 100644 index 00000000000..a02f8a1bc97 --- /dev/null +++ b/libjava/gnu/java/text/AttributedFormatBuffer.java @@ -0,0 +1,247 @@ +/* AttributedFormatBuffer.java -- Implements an attributed FormatBuffer. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY 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 +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ +package gnu.java.text; + +import java.text.AttributedCharacterIterator; +import java.util.ArrayList; +import java.util.HashMap; + +/** + * This class is an implementation of a FormatBuffer with attributes. + * + * @author Guilhem Lavaux <guilhem@kaffe.org> + * @date April 10, 2004 + */ +public class AttributedFormatBuffer implements FormatBuffer +{ + private StringBuffer buffer; + private ArrayList ranges; + private ArrayList attributes; + private int[] a_ranges; + private HashMap[] a_attributes; + private int startingRange; + AttributedCharacterIterator.Attribute defaultAttr; + + /** + * This constructor accepts a StringBuffer. If the buffer contains + * already some characters they will not be attributed. + */ + public AttributedFormatBuffer(StringBuffer buffer) + { + this.buffer = buffer; + this.ranges = new ArrayList(); + this.attributes = new ArrayList(); + this.defaultAttr = null; + if (buffer.length() != 0) + { + this.startingRange = buffer.length(); + addAttribute(buffer.length(), null); + } + else + this.startingRange = -1; + } + + public AttributedFormatBuffer(int prebuffer) + { + this(new StringBuffer(prebuffer)); + } + + public AttributedFormatBuffer() + { + this(10); + } + + /** + * This method is a helper function for formatters. Given a set of ranges + * and attributes it adds exactly one attribute for the range of characters + * comprised between the last entry in 'ranges' and the specified new range. + * + * @param new_range A new range to insert in the list. + * @param new_attribute A new attribute to insert in the list. + */ + private final void addAttribute(int new_range, AttributedCharacterIterator.Attribute attr) + { + HashMap map; + + if (attr != null) + { + map = new HashMap(); + map.put(attr, attr); + attributes.add(map); + } + else + attributes.add(null); + + ranges.add(new Integer(new_range)); + } + + public void append(String s) + { + if (startingRange < 0) + startingRange = 0; + buffer.append(s); + } + + public void append(String s, AttributedCharacterIterator.Attribute attr) + { + setDefaultAttribute(attr); + startingRange = buffer.length(); + append(s); + setDefaultAttribute(null); + } + + public void append(String s, int[] ranges, HashMap[] attrs) + { + int curPos = buffer.length(); + + setDefaultAttribute(null); + if (ranges != null) + { + for (int i = 0; i < ranges.length; i++) + { + this.ranges.add(new Integer(ranges[i] + curPos)); + this.attributes.add(attrs[i]); + } + } + startingRange = buffer.length(); + buffer.append(s); + } + + public void append(char c) + { + if (startingRange < 0) + startingRange = buffer.length(); + buffer.append(c); + } + + public void append(char c, AttributedCharacterIterator.Attribute attr) + { + setDefaultAttribute(attr); + buffer.append(c); + setDefaultAttribute(null); + } + + public void setDefaultAttribute(AttributedCharacterIterator.Attribute attr) + { + if (attr == defaultAttr) + return; + + int currentPos = buffer.length(); + + if (startingRange != currentPos && startingRange >= 0) + { + addAttribute(currentPos, defaultAttr); + } + defaultAttr = attr; + startingRange = currentPos; + } + + public AttributedCharacterIterator.Attribute getDefaultAttribute() + { + return defaultAttr; + } + + public void cutTail(int length) + { + buffer.setLength(buffer.length()-length); + } + + public int length() + { + return buffer.length(); + } + + public void clear() + { + buffer.setLength(0); + ranges.clear(); + attributes.clear(); + defaultAttr = null; + startingRange = -1; + } + + /** + * This method synchronizes the state of the attribute array. + * After calling it you may call {@link #getDefaultAttribute()}. + */ + public void sync() + { + if (startingRange < 0 || startingRange == buffer.length()) + return; + + addAttribute(buffer.length(), defaultAttr); + + a_ranges = new int[ranges.size()]; + for (int i = 0; i < a_ranges.length; i++) + a_ranges[i] = ((Integer)(ranges.get (i))).intValue(); + + a_attributes = new HashMap[attributes.size()]; + System.arraycopy(attributes.toArray(), 0, a_attributes, 0, a_attributes.length); + } + + /** + * This method returns the internal StringBuffer describing + * the attributed string. + * + * @return An instance of StringBuffer which contains the string. + */ + public StringBuffer getBuffer() + { + return buffer; + } + + /** + * This method returns the ranges for the attributes. + * + * @return An array of int describing the ranges. + */ + public int[] getRanges() + { + return a_ranges; + } + + /** + * This method returns the array containing the map on the + * attributes. + * + * @return An array of {@link java.util.Map} containing the attributes. + */ + public HashMap[] getAttributes() + { + return a_attributes; + } +} diff --git a/libjava/gnu/java/text/FormatBuffer.java b/libjava/gnu/java/text/FormatBuffer.java new file mode 100644 index 00000000000..addfcbe5c1c --- /dev/null +++ b/libjava/gnu/java/text/FormatBuffer.java @@ -0,0 +1,136 @@ +/* FormatBuffer.java -- General interface to build attributed strings. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY 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 +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ +package gnu.java.text; + +import java.text.AttributedCharacterIterator; +import java.util.HashMap; + +/** + * This interface describes a modifiable buffer which contains attributed + * characters. The implementation may or may not implements attributes. It + * aims to greatly simplify and clarify the implementation of java.text + * formatters. The buffer may be appended or have its tail cut. It may also + * be completely cleant up. + * + * @author Guilhem Lavaux <guilhem@kaffe.org> + * @date April 10, 2004 + */ +public interface FormatBuffer +{ + /** + * This method appends a simple string to the buffer. This part of + * the buffer will be attributed using the default attribute. + * + * @param s The string to append to the buffer. + */ + public void append(String s); + + /** + * This method appends a simple string to the buffer. This part of + * the buffer will have the specified attribute (and only this one). + * The default attribute may be changed after calling this method. + * + * @param s The string to append to the buffer. + * @param attr Attribute to use for the string in the buffer. + */ + public void append(String s, AttributedCharacterIterator.Attribute attr); + + /** + * This method appends a simple string to the buffer. This part of + * the buffer will be attributed using the specified ranges and attributes. + * To have an example on how to specify ranges see {@link gnu.java.text.FormatCharacterIterator}. + * + * @param s The string to append to the buffer. + * @param ranges The ranges describing how the attributes should be applied + * to the string. + * @param attrs The attributes of the string in the buffer. + */ + public void append(String s, int[] ranges, HashMap[] attrs); + + /** + * This method appends a simple char to the buffer. This part of + * the buffer will be attributed using the default attribute. + * + * @param c The character to append to the buffer. + */ + public void append(char c); + + /** + * This method appends a simple character to the buffer. This part of + * the buffer will have the specified attribute (and only this one). + * The default attribute may be changed after calling this method. + * + * @param c The character to append to the buffer. + * @param attr Attribute to use for the character in the buffer. + */ + public void append(char c, AttributedCharacterIterator.Attribute attr); + + /** + * This method changes the current default attribute for the next string + * or character which will be appended to the buffer. + * + * @param attr The attribute which will be used by default. + */ + public void setDefaultAttribute(AttributedCharacterIterator.Attribute attr); + + /** + * This method returns the current default attribute for the buffer. + * + * @return The default attribute for the buffer. + */ + public AttributedCharacterIterator.Attribute getDefaultAttribute(); + + /** + * This method cuts the last characters of the buffer. The number of + * characters to cut is given by "length". + * + * @param length Number of characters to cut at the end of the buffer. + */ + public void cutTail(int length); + + /** + * This method resets completely the buffer. + */ + public void clear(); + + /** + * This method returns the number of character in the buffer. + * + * @return The number of character in the buffer. + */ + public int length(); +} diff --git a/libjava/gnu/java/text/FormatCharacterIterator.java b/libjava/gnu/java/text/FormatCharacterIterator.java new file mode 100644 index 00000000000..116198bdc13 --- /dev/null +++ b/libjava/gnu/java/text/FormatCharacterIterator.java @@ -0,0 +1,534 @@ +/* FormatCharacter.java -- Implementation of AttributedCharacterIterator for + formatters. + Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY 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 +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ +package gnu.java.text; + +import gnu.classpath.Configuration; + +import java.text.AttributedCharacterIterator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.Vector; + +/** + * This class should not be put public and it is only intended to the + * classes of the java.text package. Its aim is to build a segmented + * character iterator by appending strings and adding attributes to + * portions of strings. The code intends to do some optimization + * concerning memory consumption and attribute access but at the + * end it is only an AttributedCharacterIterator. + * + * @author Guilhem Lavaux <guilhem@kaffe.org> + * @date November 22, 2003 + */ +public class FormatCharacterIterator implements AttributedCharacterIterator +{ + private String formattedString; + private int charIndex; + private int attributeIndex; + private int[] ranges; + private HashMap[] attributes; + + /** + * This constructor builds an empty iterated strings. The attributes + * are empty and so is the string. However you may append strings + * and attributes to this iterator. + */ + public FormatCharacterIterator() + { + formattedString = ""; + ranges = new int[0]; + attributes = new HashMap[0]; + } + + /** + * This constructor take a string <code>s</code>, a set of ranges + * and the corresponding attributes. This is used to build an iterator. + * The array <code>ranges</code> should be formatted as follow: + * each element of <code>ranges</code> specifies the index in the string + * until which the corresponding map of attributes at the same position + * is applied. For example, if you have: + * <pre> + * s = "hello"; + * ranges = new int[] { 2, 6 }; + * attributes = new HashMap[2]; + * </pre> + * <code>"he"</code> will have the attributes <code>attributes[0]</code>, + * <code>"llo"</code> the <code>attributes[1]</code>. + */ + public FormatCharacterIterator (String s, int[] ranges, HashMap[] attributes) + { + formattedString = s; + this.ranges = ranges; + this.attributes = attributes; + } + + /* + * The following methods are inherited from AttributedCharacterIterator, + * and thus are already documented. + */ + + public Set getAllAttributeKeys() + { + if (attributes != null && attributes[attributeIndex] != null) + return attributes[attributeIndex].keySet(); + else + return new HashSet(); + } + + public Map getAttributes() + { + if (attributes != null && attributes[attributeIndex] != null) + return attributes[attributeIndex]; + else + return new HashMap(); + } + + public Object getAttribute (AttributedCharacterIterator.Attribute attrib) + { + if (attributes != null && attributes[attributeIndex] != null) + return attributes[attributeIndex].get (attrib); + else + return null; + } + + public int getRunLimit(Set reqAttrs) + { + if (attributes == null) + return formattedString.length(); + + int currentAttrIndex = attributeIndex; + Set newKeys; + + do + { + currentAttrIndex++; + if (currentAttrIndex == attributes.length) + return formattedString.length(); + if (attributes[currentAttrIndex] == null) + break; + newKeys = attributes[currentAttrIndex].keySet(); + } + while (newKeys.containsAll (reqAttrs)); + + return ranges[currentAttrIndex-1]; + } + + public int getRunLimit (AttributedCharacterIterator.Attribute attribute) + { + Set s = new HashSet(); + + s.add (attribute); + return getRunLimit (s); + } + + public int getRunLimit() + { + if (attributes == null) + return formattedString.length(); + if (attributes[attributeIndex] == null) + { + for (int i=attributeIndex+1;i<attributes.length;i++) + if (attributes[i] != null) + return ranges[i-1]; + return formattedString.length(); + } + + return getRunLimit (attributes[attributeIndex].keySet()); + } + + public int getRunStart (Set reqAttrs) + { + if (attributes == null) + return formattedString.length(); + + int currentAttrIndex = attributeIndex; + Set newKeys = null; + + do + { + if (currentAttrIndex == 0) + return 0; + + currentAttrIndex--; + if (attributes[currentAttrIndex] == null) + break; + newKeys = attributes[currentAttrIndex].keySet(); + } + while (newKeys.containsAll (reqAttrs)); + + return (currentAttrIndex > 0) ? ranges[currentAttrIndex-1] : 0; + } + + public int getRunStart() + { + if (attributes == null) + return 0; + + if (attributes[attributeIndex] == null) + { + for (int i=attributeIndex;i>0;i--) + if (attributes[i] != null) + return ranges[attributeIndex-1]; + return 0; + } + + return getRunStart (attributes[attributeIndex].keySet()); + } + + public int getRunStart (AttributedCharacterIterator.Attribute attribute) + { + Set s = new HashSet(); + + s.add (attribute); + return getRunStart (s); + } + + public Object clone() + { + return new FormatCharacterIterator (formattedString, ranges, attributes); + } + + /* + * The following methods are inherited from CharacterIterator and thus + * are already documented. + */ + + public char current() + { + return formattedString.charAt (charIndex); + } + + public char first() + { + charIndex = 0; + attributeIndex = 0; + return formattedString.charAt (0); + } + + public int getBeginIndex() + { + return 0; + } + + public int getEndIndex() + { + return formattedString.length(); + } + + public int getIndex() + { + return charIndex; + } + + public char last() + { + charIndex = formattedString.length()-1; + if (attributes != null) + attributeIndex = attributes.length-1; + return formattedString.charAt (charIndex); + } + + public char next() + { + charIndex++; + if (charIndex >= formattedString.length()) + { + charIndex = getEndIndex(); + return DONE; + } + if (attributes != null) + { + if (charIndex >= ranges[attributeIndex]) + attributeIndex++; + } + return formattedString.charAt (charIndex); + } + + public char previous() + { + charIndex--; + if (charIndex < 0) + { + charIndex = 0; + return DONE; + } + + if (attributes != null) + { + if (charIndex < ranges[attributeIndex]) + attributeIndex--; + } + return formattedString.charAt (charIndex); + } + + public char setIndex (int position) + { + if (position < 0 || position > formattedString.length()) + throw new IllegalArgumentException ("position is out of range"); + + charIndex = position; + if (attributes != null) + { + for (attributeIndex=0;attributeIndex<attributes.length; + attributeIndex++) + if (ranges[attributeIndex] > charIndex) + break; + attributeIndex--; + } + if (charIndex == formattedString.length()) + return DONE; + else + return formattedString.charAt (charIndex); + } + + /** + * This method merge the specified attributes and ranges with the + * internal tables. This method is in charge of the optimization + * of tables. Two following sets of attributes are never the same. + * + * @see #FormatCharacterIterator() + * + * @param attributes the new array attributes to apply to the string. + */ + public void mergeAttributes (HashMap[] attributes, int[] ranges) + { + Vector new_ranges = new Vector(); + Vector new_attributes = new Vector(); + int i = 0, j = 0; + + debug("merging " + attributes.length + " attrs"); + + while (i < this.ranges.length && j < ranges.length) + { + if (this.attributes[i] != null) + { + new_attributes.add (this.attributes[i]); + if (attributes[j] != null) + this.attributes[i].putAll (attributes[j]); + } + else + { + new_attributes.add (attributes[j]); + } + if (this.ranges[i] == ranges[j]) + { + new_ranges.add (new Integer (ranges[j])); + i++; + j++; + } + else if (this.ranges[i] < ranges[j]) + { + new_ranges.add (new Integer (this.ranges[i])); + i++; + } + else + { + new_ranges.add (new Integer (ranges[j])); + j++; + } + } + + if (i != this.ranges.length) + { + for (;i<this.ranges.length;i++) + { + new_attributes.add (this.attributes[i]); + new_ranges.add (new Integer (this.ranges[i])); + } + } + if (j != ranges.length) + { + for (;j<ranges.length;j++) + { + new_attributes.add (attributes[j]); + new_ranges.add (new Integer (ranges[j])); + } + } + + this.attributes = new HashMap[new_attributes.size()]; + this.ranges = new int[new_ranges.size()]; + System.arraycopy (new_attributes.toArray(), 0, this.attributes, + 0, this.attributes.length); + + for (i=0;i<new_ranges.size();i++) + { + this.ranges[i] = ((Integer)new_ranges.elementAt (i)).intValue(); + } + + dumpTable(); + } + + /** + * This method appends to the internal attributed string the attributed + * string contained in the specified iterator. + * + * @param iterator the iterator which contains the attributed string to + * append to this iterator. + */ + public void append (AttributedCharacterIterator iterator) + { + char c = iterator.first(); + Vector more_ranges = new Vector(); + Vector more_attributes = new Vector(); + + do + { + formattedString = formattedString + String.valueOf (c); + // TODO: Reduce the size of the output array. + more_attributes.add (iterator.getAttributes()); + more_ranges.add (new Integer (formattedString.length())); + // END TOOD + c = iterator.next(); + } + while (c != DONE); + + HashMap[] new_attributes = new HashMap[attributes.length + + more_attributes.size()]; + int[] new_ranges = new int[ranges.length + more_ranges.size()]; + + System.arraycopy (attributes, 0, new_attributes, 0, attributes.length); + System.arraycopy (more_attributes.toArray(), 0, new_attributes, + attributes.length, more_attributes.size()); + + System.arraycopy (ranges, 0, new_ranges, 0, ranges.length); + Object[] new_ranges_array = more_ranges.toArray(); + for (int i = 0; i < more_ranges.size();i++) + new_ranges[i+ranges.length] = ((Integer) new_ranges_array[i]).intValue(); + + attributes = new_attributes; + ranges = new_ranges; + } + + /** + * This method appends an attributed string which attributes are specified + * directly in the calling parameters. + * + * @param text The string to append. + * @param local_attributes The attributes to put on this string in the + * iterator. If it is <code>null</code> the string will simply have no + * attributes. + */ + public void append (String text, HashMap local_attributes) + { + int[] new_ranges = new int[ranges.length+1]; + HashMap[] new_attributes = new HashMap[attributes.length+1]; + + formattedString += text; + System.arraycopy (attributes, 0, new_attributes, 0, attributes.length); + System.arraycopy (ranges, 0, new_ranges, 0, ranges.length); + new_ranges[ranges.length] = formattedString.length(); + new_attributes[attributes.length] = local_attributes; + + ranges = new_ranges; + attributes = new_attributes; + } + + /** + * This method appends a string without attributes. It is completely + * equivalent to call {@link #append(String,HashMap)} with local_attributes + * equal to <code>null</code>. + * + * @param text The string to append to the iterator. + */ + public void append (String text) + { + append (text, null); + } + + /** + * This method adds a set of attributes to a range of character. The + * bounds are always inclusive. In the case many attributes have to + * be added it is advised to directly use {@link #mergeAttributes([Ljava.util.HashMap;[I} + * + * @param attributes Attributes to merge into the iterator. + * @param range_start Lower bound of the range of characters which will receive the + * attribute. + * @param range_end Upper bound of the range of characters which will receive the + * attribute. + * + * @throws IllegalArgumentException if ranges are out of bounds. + */ + public void addAttributes(HashMap attributes, int range_start, int range_end) + { + if (range_start == 0) + mergeAttributes(new HashMap[] { attributes }, new int[] { range_end }); + else + mergeAttributes(new HashMap[] { null, attributes }, new int[] { range_start, range_end }); + } + + final private void debug(String s) + { + if (Configuration.DEBUG) + System.out.println(s); + } + + final private void dumpTable() + { + int start_range = 0; + + if (!Configuration.DEBUG) + return; + + System.out.println("Dumping internal table:"); + for (int i = 0; i < ranges.length; i++) + { + System.out.print("\t" + start_range + " => " + ranges[i] + ":"); + if (attributes[i] == null) + System.out.println("null"); + else + { + Set keyset = attributes[i].keySet(); + if (keyset != null) + { + Iterator keys = keyset.iterator(); + + while (keys.hasNext()) + System.out.print(" " + keys.next()); + } + else + System.out.println("keySet null"); + System.out.println(); + } + } + System.out.println(); + System.out.flush(); + } +} diff --git a/libjava/gnu/java/text/StringFormatBuffer.java b/libjava/gnu/java/text/StringFormatBuffer.java new file mode 100644 index 00000000000..ec0ed86417e --- /dev/null +++ b/libjava/gnu/java/text/StringFormatBuffer.java @@ -0,0 +1,121 @@ +/* StringFormatBuffer.java -- Implements FormatBuffer using StringBuffer. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY 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 +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ +package gnu.java.text; + +import java.text.AttributedCharacterIterator; +import java.util.HashMap; + +/** + * This class is an implementation of a FormatBuffer without attributes. + * + * @author Guilhem Lavaux <guilhem@kaffe.org> + * @date April 10, 2004 + */ +public class StringFormatBuffer implements FormatBuffer +{ + private StringBuffer buffer; + private AttributedCharacterIterator.Attribute defaultAttr; + + public StringFormatBuffer(int prebuffer) + { + buffer = new StringBuffer(prebuffer); + } + + public StringFormatBuffer(StringBuffer buffer) + { + this.buffer = buffer; + } + + public void append(String s) + { + buffer.append(s); + } + + public void append(String s, AttributedCharacterIterator.Attribute attr) + { + buffer.append(s); + } + + public void append(String s, int[] ranges, HashMap[] attrs) + { + buffer.append(s); + } + + public void append(char c) + { + buffer.append(c); + } + + public void append(char c, AttributedCharacterIterator.Attribute attr) + { + buffer.append(c); + } + + public void setDefaultAttribute(AttributedCharacterIterator.Attribute attr) + { + defaultAttr = attr; + } + + public AttributedCharacterIterator.Attribute getDefaultAttribute() + { + return defaultAttr; + } + + public void cutTail(int length) + { + buffer.setLength(buffer.length()-length); + } + + public int length() + { + return buffer.length(); + } + + public void clear() + { + buffer.setLength(0); + } + + /** + * This method returns the internal {@link java.lang.StringBuffer} which + * contains the string of character. + */ + public StringBuffer getBuffer() + { + return buffer; + } +} diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxGroupPeer.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxGroupPeer.c new file mode 100644 index 00000000000..f88e2e8bcc3 --- /dev/null +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxGroupPeer.c @@ -0,0 +1,75 @@ +/* gtkcheckboxgrouppeer.c -- Native implementation of GtkCheckboxGroupPeer + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY 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 +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +#include "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkCheckboxGroupPeer.h" + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkCheckboxGroupPeer_dispose + (JNIEnv *env, jobject obj) +{ + /* The actual underlying widget is owned by a different class. So + we just clean up the hash table here. */ + NSA_DEL_PTR (env, obj); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkCheckboxGroupPeer_remove + (JNIEnv *env, jobject obj, jobject checkbox) +{ + GtkRadioButton *button; + void *ptr; + GSList *list; + + ptr = NSA_GET_PTR (env, checkbox); + gdk_threads_enter (); + button = GTK_RADIO_BUTTON (ptr); + + /* Update the group to point to some other widget in the group. We + have to do this because Gtk doesn't have a separate object to + represent a radio button's group. */ + for (list = gtk_radio_button_group (button); list != NULL; + list = list->next) + { + if (list->data != button) + break; + } + + gdk_threads_leave (); + + NSA_SET_PTR (env, obj, list ? list->data : NULL); +} + diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkGenericPeer.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkGenericPeer.c new file mode 100644 index 00000000000..7b8babeb839 --- /dev/null +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkGenericPeer.c @@ -0,0 +1,59 @@ +/* gtkgenericpeer.c -- Native implementation of GtkGenericPeer + Copyright (C) 1998, 1999, 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY 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 +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +#include "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkGenericPeer.h" + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkGenericPeer_dispose + (JNIEnv *env, jobject obj) +{ + void *ptr; + + /* Remove entries from state tables */ + NSA_DEL_GLOBAL_REF (env, obj); + ptr = NSA_DEL_PTR (env, obj); + + gdk_threads_enter (); + + /* For now the native state for any object must be a widget. + However, a subclass could override dispose() if required. */ + gtk_widget_destroy (GTK_WIDGET (ptr)); + + gdk_threads_leave (); +} + diff --git a/libjava/testsuite/libjava.jni/PR15133.c b/libjava/testsuite/libjava.jni/PR15133.c new file mode 100644 index 00000000000..be5a48efa3b --- /dev/null +++ b/libjava/testsuite/libjava.jni/PR15133.c @@ -0,0 +1,9 @@ +#include <stdio.h> +#include <jni.h> +#include "PR15133.h" + +JNIEXPORT void JNICALL +Java_PR15133_printIt (JNIEnv *env, jobject x, jint y) +{ + printf ("%d\n", y); +} diff --git a/libjava/testsuite/libjava.jni/PR15133.java b/libjava/testsuite/libjava.jni/PR15133.java new file mode 100644 index 00000000000..90435765b3d --- /dev/null +++ b/libjava/testsuite/libjava.jni/PR15133.java @@ -0,0 +1,14 @@ +/* Test case for PR java/15133 */ +public class PR15133 +{ + public void printIt (String dummy) { } + + public native void printIt (int num); + + public static void main (String[] args) + { + System.loadLibrary ("PR15133"); + + new PR15133( ).printIt( 1729); + } +} diff --git a/libjava/testsuite/libjava.jni/PR15133.out b/libjava/testsuite/libjava.jni/PR15133.out new file mode 100644 index 00000000000..32bb421c624 --- /dev/null +++ b/libjava/testsuite/libjava.jni/PR15133.out @@ -0,0 +1 @@ +1729 |