diff options
Diffstat (limited to 'gcc/ada/bindgen.adb')
-rw-r--r-- | gcc/ada/bindgen.adb | 2903 |
1 files changed, 2903 insertions, 0 deletions
diff --git a/gcc/ada/bindgen.adb b/gcc/ada/bindgen.adb new file mode 100644 index 0000000..677e495 --- /dev/null +++ b/gcc/ada/bindgen.adb @@ -0,0 +1,2903 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- B I N D G E N -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.201 $ +-- -- +-- Copyright (C) 1992-2001 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. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with ALI; use ALI; +with Binde; use Binde; +with Butil; use Butil; +with Casing; use Casing; +with Fname; use Fname; +with GNAT.OS_Lib; use GNAT.OS_Lib; +with Gnatvsn; use Gnatvsn; +with Hostparm; +with Namet; use Namet; +with Opt; use Opt; +with Osint; use Osint; +with Output; use Output; +with Types; use Types; +with Sdefault; use Sdefault; +with System; use System; + +with GNAT.Heap_Sort_A; use GNAT.Heap_Sort_A; + +package body Bindgen is + + Statement_Buffer : String (1 .. 1000); + -- Buffer used for constructing output statements + + Last : Natural := 0; + -- Last location in Statement_Buffer currently set + + With_DECGNAT : Boolean := False; + -- Flag which indicates whether the program uses the DECGNAT library + -- (presence of the unit System.Aux_DEC.DECLIB) + + With_GNARL : Boolean := False; + -- Flag which indicates whether the program uses the GNARL library + -- (presence of the unit System.OS_Interface) + + Num_Elab_Calls : Nat := 0; + -- Number of generated calls to elaboration routines + + subtype chars_ptr is Address; + + ----------------------- + -- Local Subprograms -- + ----------------------- + + procedure WBI (Info : String) renames Osint.Write_Binder_Info; + -- Convenient shorthand used throughout + + function ABE_Boolean_Required (U : Unit_Id) return Boolean; + -- Given a unit id value U, determines if the corresponding unit requires + -- an access-before-elaboration check variable, i.e. it is a non-predefined + -- body for which no pragma Elaborate, Elaborate_All or Elaborate_Body is + -- present, and thus could require ABE checks. + + procedure Resolve_Binder_Options; + -- Set the value of With_GNARL and With_DECGNAT. The latter only on VMS + -- since it tests for a package named "dec" which might cause a conflict + -- on non-VMS systems. + + procedure Gen_Adainit_Ada; + -- Generates the Adainit procedure (Ada code case) + + procedure Gen_Adainit_C; + -- Generates the Adainit procedure (C code case) + + procedure Gen_Adafinal_Ada; + -- Generate the Adafinal procedure (Ada code case) + + procedure Gen_Adafinal_C; + -- Generate the Adafinal procedure (C code case) + + procedure Gen_Elab_Calls_Ada; + -- Generate sequence of elaboration calls (Ada code case) + + procedure Gen_Elab_Calls_C; + -- Generate sequence of elaboration calls (C code case) + + procedure Gen_Elab_Order_Ada; + -- Generate comments showing elaboration order chosen (Ada case) + + procedure Gen_Elab_Order_C; + -- Generate comments showing elaboration order chosen (C case) + + procedure Gen_Elab_Defs_C; + -- Generate sequence of definitions for elaboration routines (C code case) + + procedure Gen_Exception_Table_Ada; + -- Generate binder exception table (Ada code case). This consists of + -- declarations followed by a begin followed by a call. If zero cost + -- exceptions are not active, then only the begin is generated. + + procedure Gen_Exception_Table_C; + -- Generate binder exception table (C code case). This has no effect + -- if zero cost exceptions are not active, otherwise it generates a + -- set of declarations followed by a call. + + procedure Gen_Main_Ada; + -- Generate procedure main (Ada code case) + + procedure Gen_Main_C; + -- Generate main() procedure (C code case) + + procedure Gen_Object_Files_Options; + -- Output comments containing a list of the full names of the object + -- files to be linked and the list of linker options supplied by + -- Linker_Options pragmas in the source. (C and Ada code case) + + procedure Gen_Output_File_Ada (Filename : String); + -- Generate output file (Ada code case) + + procedure Gen_Output_File_C (Filename : String); + -- Generate output file (C code case) + + procedure Gen_Scalar_Values; + -- Generates scalar initialization values for -Snn. A single procedure + -- handles both the Ada and C cases, since there is much common code. + + procedure Gen_Versions_Ada; + -- Output series of definitions for unit versions (Ada code case) + + procedure Gen_Versions_C; + -- Output series of definitions for unit versions (C code case) + + function Get_Ada_Main_Name return String; + -- This function is used in the Ada main output case to compute a usable + -- name for the generated main program. The normal main program name is + -- Ada_Main, but this won't work if the user has a unit with this name. + -- This function tries Ada_Main first, and if there is such a clash, then + -- it tries Ada_Name_01, Ada_Name_02 ... Ada_Name_99 in sequence. + + function Get_Main_Name return String; + -- This function is used in the Ada main output case to compute the + -- correct external main program. It is "main" by default, except on + -- VxWorks where it is the name of the Ada main name without the "_ada". + -- the -Mname binder option overrides the default with name. + + function Lt_Linker_Option (Op1, Op2 : Natural) return Boolean; + -- Compare linker options, when sorting, first according to + -- Is_Internal_File (internal files come later) and then by elaboration + -- order position (latest to earliest) except its not possible to + -- distinguish between a linker option in the spec and one in the body. + + procedure Move_Linker_Option (From : Natural; To : Natural); + -- Move routine for sorting linker options + + procedure Public_Version_Warning; + -- Emit a warning concerning the use of the Public version under + -- certain circumstances. See details in body. + + procedure Set_Char (C : Character); + -- Set given character in Statement_Buffer at the Last + 1 position + -- and increment Last by one to reflect the stored character. + + procedure Set_Int (N : Int); + -- Set given value in decimal in Statement_Buffer with no spaces + -- starting at the Last + 1 position, and updating Last past the value. + -- A minus sign is output for a negative value. + + procedure Set_Main_Program_Name; + -- Given the main program name in Name_Buffer (length in Name_Len) + -- generate the name of the routine to be used in the call. The name + -- is generated starting at Last + 1, and Last is updated past it. + + procedure Set_Name_Buffer; + -- Set the value stored in positions 1 .. Name_Len of the Name_Buffer. + + procedure Set_String (S : String); + -- Sets characters of given string in Statement_Buffer, starting at the + -- Last + 1 position, and updating last past the string value. + + procedure Set_Unit_Name; + -- Given a unit name in the Name_Buffer, copies it to Statement_Buffer, + -- starting at the Last + 1 position, and updating last past the value. + -- changing periods to double underscores, and updating Last appropriately. + + procedure Set_Unit_Number (U : Unit_Id); + -- Sets unit number (first unit is 1, leading zeroes output to line + -- up all output unit numbers nicely as required by the value, and + -- by the total number of units. + + procedure Tab_To (N : Natural); + -- If Last is greater than or equal to N, no effect, otherwise store + -- blanks in Statement_Buffer bumping Last, until Last = N. + + function Value (chars : chars_ptr) return String; + -- Return C NUL-terminated string at chars as an Ada string + + procedure Write_Info_Ada_C (Ada : String; C : String; Common : String); + -- For C code case, write C & Common, for Ada case write Ada & Common + -- to current binder output file using Write_Binder_Info. + + procedure Write_Statement_Buffer; + -- Write out contents of statement buffer up to Last, and reset Last to 0 + + procedure Write_Statement_Buffer (S : String); + -- First writes its argument (using Set_String (S)), then writes out the + -- contents of statement buffer up to Last, and reset Last to 0 + + -------------------------- + -- ABE_Boolean_Required -- + -------------------------- + + function ABE_Boolean_Required (U : Unit_Id) return Boolean is + Typ : constant Unit_Type := Units.Table (U).Utype; + Unit : Unit_Id; + + begin + if Typ /= Is_Body then + return False; + + else + Unit := U + 1; + + return (not Units.Table (Unit).Pure) + and then + (not Units.Table (Unit).Preelab) + and then + (not Units.Table (Unit).Elaborate_Body) + and then + (not Units.Table (Unit).Predefined); + end if; + end ABE_Boolean_Required; + + ---------------------- + -- Gen_Adafinal_Ada -- + ---------------------- + + procedure Gen_Adafinal_Ada is + begin + WBI (""); + WBI (" procedure " & Ada_Final_Name.all & " is"); + WBI (" begin"); + + -- If compiling for the JVM, we directly call Adafinal because + -- we don't import it via Do_Finalize (see Gen_Output_File_Ada). + + if Hostparm.Java_VM then + WBI (" System.Standard_Library.Adafinal;"); + else + WBI (" Do_Finalize;"); + end if; + + WBI (" end " & Ada_Final_Name.all & ";"); + end Gen_Adafinal_Ada; + + -------------------- + -- Gen_Adafinal_C -- + -------------------- + + procedure Gen_Adafinal_C is + begin + WBI ("void " & Ada_Final_Name.all & " () {"); + WBI (" system__standard_library__adafinal ();"); + WBI ("}"); + WBI (""); + end Gen_Adafinal_C; + + --------------------- + -- Gen_Adainit_Ada -- + --------------------- + + procedure Gen_Adainit_Ada is + begin + WBI (" procedure " & Ada_Init_Name.all & " is"); + + -- Generate externals for elaboration entities + + for E in Elab_Order.First .. Elab_Order.Last loop + declare + Unum : constant Unit_Id := Elab_Order.Table (E); + U : Unit_Record renames Units.Table (Unum); + + begin + if U.Set_Elab_Entity then + Set_String (" "); + Set_String ("E"); + Set_Unit_Number (Unum); + Set_String (" : Boolean; pragma Import (Ada, "); + Set_String ("E"); + Set_Unit_Number (Unum); + Set_String (", """); + Get_Name_String (U.Uname); + + -- In the case of JGNAT we need to emit an Import name + -- that includes the class name (using '$' separators + -- in the case of a child unit name). + + if Hostparm.Java_VM then + for J in 1 .. Name_Len - 2 loop + if Name_Buffer (J) /= '.' then + Set_Char (Name_Buffer (J)); + else + Set_String ("$"); + end if; + end loop; + + Set_String ("."); + + -- If the unit name is very long, then split the + -- Import link name across lines using "&" (occurs + -- in some C2 tests). + + if 2 * Name_Len + 60 > Hostparm.Max_Line_Length then + Set_String (""" &"); + Write_Statement_Buffer; + Set_String (" """); + end if; + end if; + + Set_Unit_Name; + Set_String ("_E"");"); + Write_Statement_Buffer; + end if; + end; + end loop; + + Write_Statement_Buffer; + + -- Normal case (no pragma No_Run_Time). The global values are + -- assigned using the runtime routine Set_Globals (we have to use + -- the routine call, rather than define the globals in the binder + -- file to deal with cross-library calls in some systems. + + if not No_Run_Time_Specified then + WBI (""); + WBI (" procedure Set_Globals"); + WBI (" (Main_Priority : Integer;"); + WBI (" Time_Slice_Value : Integer;"); + WBI (" WC_Encoding : Character;"); + WBI (" Locking_Policy : Character;"); + WBI (" Queuing_Policy : Character;"); + WBI (" Task_Dispatching_Policy : Character;"); + WBI (" Adafinal : System.Address;"); + WBI (" Unreserve_All_Interrupts : Integer;"); + WBI (" Exception_Tracebacks : Integer);"); + WBI (" pragma Import (C, Set_Globals, ""__gnat_set_globals"");"); + WBI (""); + + -- Import entry point for elaboration time signal handler + -- installation, and indication of whether it's been called + -- previously + WBI (""); + WBI (" procedure Install_Handler;"); + WBI (" pragma Import (C, Install_Handler, " & + """__gnat_install_handler"");"); + WBI (""); + WBI (" Handler_Installed : Integer;"); + WBI (" pragma Import (C, Handler_Installed, " & + """__gnat_handler_installed"");"); + + -- Generate exception table + + Gen_Exception_Table_Ada; + + -- Generate the call to Set_Globals + + WBI (" Set_Globals"); + + Set_String (" (Main_Priority => "); + Set_Int (ALIs.Table (ALIs.First).Main_Priority); + Set_Char (','); + Write_Statement_Buffer; + + Set_String (" Time_Slice_Value => "); + + if Task_Dispatching_Policy_Specified = 'F' + and then ALIs.Table (ALIs.First).Time_Slice_Value = -1 + then + Set_Int (0); + else + Set_Int (ALIs.Table (ALIs.First).Time_Slice_Value); + end if; + + Set_Char (','); + Write_Statement_Buffer; + + Set_String (" WC_Encoding => '"); + Set_Char (ALIs.Table (ALIs.First).WC_Encoding); + Set_String ("',"); + Write_Statement_Buffer; + + Set_String (" Locking_Policy => '"); + Set_Char (Locking_Policy_Specified); + Set_String ("',"); + Write_Statement_Buffer; + + Set_String (" Queuing_Policy => '"); + Set_Char (Queuing_Policy_Specified); + Set_String ("',"); + Write_Statement_Buffer; + + Set_String (" Task_Dispatching_Policy => '"); + Set_Char (Task_Dispatching_Policy_Specified); + Set_String ("',"); + Write_Statement_Buffer; + + WBI (" Adafinal => System.Null_Address,"); + + Set_String (" Unreserve_All_Interrupts => "); + + if Unreserve_All_Interrupts_Specified then + Set_String ("1"); + else + Set_String ("0"); + end if; + + Set_String (","); + Write_Statement_Buffer; + + Set_String (" Exception_Tracebacks => "); + + if Exception_Tracebacks then + Set_String ("1"); + else + Set_String ("0"); + end if; + + Set_String (");"); + Write_Statement_Buffer; + + -- Generate call to Install_Handler + WBI (""); + WBI (" if Handler_Installed = 0 then"); + WBI (" Install_Handler;"); + WBI (" end if;"); + + -- Case of pragma No_Run_Time present. Globals are not needed since + -- there are no runtime routines to make use of them, and no routine + -- to store them in any case! Also no exception tables are needed. + + else + WBI (" begin"); + WBI (" null;"); + end if; + + Gen_Elab_Calls_Ada; + + WBI (" end " & Ada_Init_Name.all & ";"); + end Gen_Adainit_Ada; + + ------------------- + -- Gen_Adainit_C -- + -------------------- + + procedure Gen_Adainit_C is + begin + WBI ("void " & Ada_Init_Name.all & " ()"); + WBI ("{"); + + -- Generate externals for elaboration entities + + for E in Elab_Order.First .. Elab_Order.Last loop + declare + Unum : constant Unit_Id := Elab_Order.Table (E); + U : Unit_Record renames Units.Table (Unum); + + begin + if U.Set_Elab_Entity then + Set_String (" extern char "); + Get_Name_String (U.Uname); + Set_Unit_Name; + Set_String ("_E;"); + Write_Statement_Buffer; + end if; + end; + end loop; + + Write_Statement_Buffer; + + -- Code for normal case (no pragma No_Run_Time in use) + + if not No_Run_Time_Specified then + + Gen_Exception_Table_C; + + -- Generate call to set the runtime global variables defined in + -- a-init.c. We define the varables in a-init.c, rather than in + -- the binder generated file itself to avoid undefined externals + -- when the runtime is linked as a shareable image library. + + -- We call the routine from inside adainit() because this works for + -- both programs with and without binder generated "main" functions. + + WBI (" __gnat_set_globals ("); + + Set_String (" "); + Set_Int (ALIs.Table (ALIs.First).Main_Priority); + Set_Char (','); + Tab_To (15); + Set_String ("/* Main_Priority */"); + Write_Statement_Buffer; + + Set_String (" "); + + if Task_Dispatching_Policy = 'F' + and then ALIs.Table (ALIs.First).Time_Slice_Value = -1 + then + Set_Int (0); + else + Set_Int (ALIs.Table (ALIs.First).Time_Slice_Value); + end if; + + Set_Char (','); + Tab_To (15); + Set_String ("/* Time_Slice_Value */"); + Write_Statement_Buffer; + + Set_String (" '"); + Set_Char (ALIs.Table (ALIs.First).WC_Encoding); + Set_String ("',"); + Tab_To (15); + Set_String ("/* WC_Encoding */"); + Write_Statement_Buffer; + + Set_String (" '"); + Set_Char (Locking_Policy_Specified); + Set_String ("',"); + Tab_To (15); + Set_String ("/* Locking_Policy */"); + Write_Statement_Buffer; + + Set_String (" '"); + Set_Char (Queuing_Policy_Specified); + Set_String ("',"); + Tab_To (15); + Set_String ("/* Queuing_Policy */"); + Write_Statement_Buffer; + + Set_String (" '"); + Set_Char (Task_Dispatching_Policy_Specified); + Set_String ("',"); + Tab_To (15); + Set_String ("/* Tasking_Dispatching_Policy */"); + Write_Statement_Buffer; + + Set_String (" "); + Set_String ("0,"); + Tab_To (15); + Set_String ("/* Finalization routine address, not used anymore */"); + Write_Statement_Buffer; + + Set_String (" "); + Set_Int (Boolean'Pos (Unreserve_All_Interrupts_Specified)); + Set_String (","); + Tab_To (15); + Set_String ("/* Unreserve_All_Interrupts */"); + Write_Statement_Buffer; + + Set_String (" "); + Set_Int (Boolean'Pos (Exception_Tracebacks)); + Set_String (");"); + Tab_To (15); + Set_String ("/* Exception_Tracebacks */"); + Write_Statement_Buffer; + + -- Install elaboration time signal handler + WBI (" if (__gnat_handler_installed == 0)"); + WBI (" {"); + WBI (" __gnat_install_handler ();"); + WBI (" }"); + + -- Case where No_Run_Time pragma is present (no globals required) + -- Nothing more needs to be done in this case. + + else + null; + end if; + + WBI (""); + Gen_Elab_Calls_C; + WBI ("}"); + end Gen_Adainit_C; + + ------------------------ + -- Gen_Elab_Calls_Ada -- + ------------------------ + + procedure Gen_Elab_Calls_Ada is + begin + + for E in Elab_Order.First .. Elab_Order.Last loop + declare + Unum : constant Unit_Id := Elab_Order.Table (E); + U : Unit_Record renames Units.Table (Unum); + + Unum_Spec : Unit_Id; + -- This is the unit number of the spec that corresponds to + -- this entry. It is the same as Unum except when the body + -- and spec are different and we are currently processing + -- the body, in which case it is the spec (Unum + 1). + + procedure Set_Elab_Entity; + -- Set name of elaboration entity flag + + procedure Set_Elab_Entity is + begin + Get_Decoded_Name_String_With_Brackets (U.Uname); + Name_Len := Name_Len - 2; + Set_Casing (U.Icasing); + Set_Name_Buffer; + end Set_Elab_Entity; + + begin + if U.Utype = Is_Body then + Unum_Spec := Unum + 1; + else + Unum_Spec := Unum; + end if; + + -- Case of no elaboration code + + if U.No_Elab then + + -- The only case in which we have to do something is if + -- this is a body, with a separate spec, where the separate + -- spec has an elaboration entity defined. + + -- In that case, this is where we set the elaboration entity + -- to True, we do not need to test if this has already been + -- done, since it is quicker to set the flag than to test it. + + if U.Utype = Is_Body + and then Units.Table (Unum_Spec).Set_Elab_Entity + then + Set_String (" E"); + Set_Unit_Number (Unum_Spec); + Set_String (" := True;"); + Write_Statement_Buffer; + end if; + + -- Here if elaboration code is present. We generate: + + -- if not uname_E then + -- uname'elab_[spec|body]; + -- uname_E := True; + -- end if; + + -- The uname_E assignment is skipped if this is a separate spec, + -- since the assignment will be done when we process the body. + + else + Set_String (" if not E"); + Set_Unit_Number (Unum_Spec); + Set_String (" then"); + Write_Statement_Buffer; + + Set_String (" "); + Get_Decoded_Name_String_With_Brackets (U.Uname); + + if Name_Buffer (Name_Len) = 's' then + Name_Buffer (Name_Len - 1 .. Name_Len + 8) := "'elab_spec"; + else + Name_Buffer (Name_Len - 1 .. Name_Len + 8) := "'elab_body"; + end if; + + Name_Len := Name_Len + 8; + Set_Casing (U.Icasing); + Set_Name_Buffer; + Set_Char (';'); + Write_Statement_Buffer; + + if U.Utype /= Is_Spec then + Set_String (" E"); + Set_Unit_Number (Unum_Spec); + Set_String (" := True;"); + Write_Statement_Buffer; + end if; + + WBI (" end if;"); + end if; + end; + end loop; + + end Gen_Elab_Calls_Ada; + + ---------------------- + -- Gen_Elab_Calls_C -- + ---------------------- + + procedure Gen_Elab_Calls_C is + begin + + for E in Elab_Order.First .. Elab_Order.Last loop + declare + Unum : constant Unit_Id := Elab_Order.Table (E); + U : Unit_Record renames Units.Table (Unum); + + Unum_Spec : Unit_Id; + -- This is the unit number of the spec that corresponds to + -- this entry. It is the same as Unum except when the body + -- and spec are different and we are currently processing + -- the body, in which case it is the spec (Unum + 1). + + begin + if U.Utype = Is_Body then + Unum_Spec := Unum + 1; + else + Unum_Spec := Unum; + end if; + + -- Case of no elaboration code + + if U.No_Elab then + + -- The only case in which we have to do something is if + -- this is a body, with a separate spec, where the separate + -- spec has an elaboration entity defined. + + -- In that case, this is where we set the elaboration entity + -- to True, we do not need to test if this has already been + -- done, since it is quicker to set the flag than to test it. + + if U.Utype = Is_Body + and then Units.Table (Unum_Spec).Set_Elab_Entity + then + Set_String (" "); + Get_Name_String (U.Uname); + Set_Unit_Name; + Set_String ("_E = 1;"); + Write_Statement_Buffer; + end if; + + -- Here if elaboration code is present. We generate: + + -- if (uname_E == 0) { + -- uname__elab[s|b] (); + -- uname_E++; + -- } + + -- The uname_E assignment is skipped if this is a separate spec, + -- since the assignment will be done when we process the body. + + else + Set_String (" if ("); + Get_Name_String (U.Uname); + Set_Unit_Name; + Set_String ("_E == 0) {"); + Write_Statement_Buffer; + + Set_String (" "); + Set_Unit_Name; + Set_String ("___elab"); + Set_Char (Name_Buffer (Name_Len)); -- 's' or 'b' for spec/body + Set_String (" ();"); + Write_Statement_Buffer; + + if U.Utype /= Is_Spec then + Set_String (" "); + Set_Unit_Name; + Set_String ("_E++;"); + Write_Statement_Buffer; + end if; + + WBI (" }"); + end if; + end; + end loop; + + end Gen_Elab_Calls_C; + + ---------------------- + -- Gen_Elab_Defs_C -- + ---------------------- + + procedure Gen_Elab_Defs_C is + begin + for E in Elab_Order.First .. Elab_Order.Last loop + + -- Generate declaration of elaboration procedure if elaboration + -- needed. Note that passive units are always excluded. + + if not Units.Table (Elab_Order.Table (E)).No_Elab then + Get_Name_String (Units.Table (Elab_Order.Table (E)).Uname); + Set_String ("extern void "); + Set_Unit_Name; + Set_String ("___elab"); + Set_Char (Name_Buffer (Name_Len)); -- 's' or 'b' for spec/body + Set_String (" PARAMS ((void));"); + Write_Statement_Buffer; + end if; + + end loop; + + WBI (""); + end Gen_Elab_Defs_C; + + ------------------------ + -- Gen_Elab_Order_Ada -- + ------------------------ + + procedure Gen_Elab_Order_Ada is + begin + WBI (""); + WBI (" -- BEGIN ELABORATION ORDER"); + + for J in Elab_Order.First .. Elab_Order.Last loop + Set_String (" -- "); + Get_Unit_Name_String (Units.Table (Elab_Order.Table (J)).Uname); + Set_Name_Buffer; + Write_Statement_Buffer; + end loop; + + WBI (" -- END ELABORATION ORDER"); + end Gen_Elab_Order_Ada; + + ---------------------- + -- Gen_Elab_Order_C -- + ---------------------- + + procedure Gen_Elab_Order_C is + begin + WBI (""); + WBI ("/* BEGIN ELABORATION ORDER"); + + for J in Elab_Order.First .. Elab_Order.Last loop + Get_Unit_Name_String (Units.Table (Elab_Order.Table (J)).Uname); + Set_Name_Buffer; + Write_Statement_Buffer; + end loop; + + WBI (" END ELABORATION ORDER */"); + end Gen_Elab_Order_C; + + ----------------------------- + -- Gen_Exception_Table_Ada -- + ----------------------------- + + procedure Gen_Exception_Table_Ada is + Num : Nat; + Last : ALI_Id := No_ALI_Id; + + begin + if not Zero_Cost_Exceptions_Specified then + WBI (" begin"); + return; + end if; + + -- The code we generate looks like + + -- procedure SDP_Table_Build + -- (SDP_Addresses : System.Address; + -- SDP_Count : Natural; + -- Elab_Addresses : System.Address; + -- Elab_Addr_Count : Natural); + -- pragma Import (C, SDP_Table_Build, "__gnat_SDP_Table_Build"); + -- + -- ST : aliased constant array (1 .. nnn) of System.Address := ( + -- unit_name_1'UET_Address, + -- unit_name_2'UET_Address, + -- ... + -- unit_name_3'UET_Address, + -- + -- EA : aliased constant array (1 .. eee) of System.Address := ( + -- adainit'Code_Address, + -- adafinal'Code_Address, + -- unit_name'elab[spec|body]'Code_Address, + -- unit_name'elab[spec|body]'Code_Address, + -- unit_name'elab[spec|body]'Code_Address, + -- unit_name'elab[spec|body]'Code_Address); + -- + -- begin + -- SDP_Table_Build (ST'Address, nnn, EA'Address, eee); + + Num := 0; + for A in ALIs.First .. ALIs.Last loop + if ALIs.Table (A).Unit_Exception_Table then + Num := Num + 1; + Last := A; + end if; + end loop; + + WBI (" procedure SDP_Table_Build"); + WBI (" (SDP_Addresses : System.Address;"); + WBI (" SDP_Count : Natural;"); + WBI (" Elab_Addresses : System.Address;"); + WBI (" Elab_Addr_Count : Natural);"); + WBI (" " & + "pragma Import (C, SDP_Table_Build, ""__gnat_SDP_Table_Build"");"); + + WBI (" "); + Set_String (" ST : aliased constant array (1 .. "); + Set_Int (Num); + Set_String (") of System.Address := ("); + + if Num = 1 then + Set_String ("1 => A1);"); + Write_Statement_Buffer; + + else + Write_Statement_Buffer; + + for A in ALIs.First .. ALIs.Last loop + if ALIs.Table (A).Unit_Exception_Table then + Get_Decoded_Name_String_With_Brackets + (Units.Table (ALIs.Table (A).First_Unit).Uname); + Set_Casing (Mixed_Case); + Set_String (" "); + Set_String (Name_Buffer (1 .. Name_Len - 2)); + Set_String ("'UET_Address"); + + if A = Last then + Set_String (");"); + else + Set_Char (','); + end if; + + Write_Statement_Buffer; + end if; + end loop; + end if; + + WBI (" "); + Set_String (" EA : aliased constant array (1 .. "); + Set_Int (Num_Elab_Calls + 2); + Set_String (") of System.Address := ("); + Write_Statement_Buffer; + WBI (" " & Ada_Init_Name.all & "'Code_Address,"); + + -- If compiling for the JVM, we directly reference Adafinal because + -- we don't import it via Do_Finalize (see Gen_Output_File_Ada). + + if Hostparm.Java_VM then + Set_String (" System.Standard_Library.Adafinal'Code_Address"); + else + Set_String (" Do_Finalize'Code_Address"); + end if; + + for E in Elab_Order.First .. Elab_Order.Last loop + Get_Decoded_Name_String_With_Brackets + (Units.Table (Elab_Order.Table (E)).Uname); + + if Units.Table (Elab_Order.Table (E)).No_Elab then + null; + + else + Set_Char (','); + Write_Statement_Buffer; + Set_String (" "); + + if Name_Buffer (Name_Len) = 's' then + Name_Buffer (Name_Len - 1 .. Name_Len + 21) := + "'elab_spec'code_address"; + else + Name_Buffer (Name_Len - 1 .. Name_Len + 21) := + "'elab_body'code_address"; + end if; + + Name_Len := Name_Len + 21; + Set_Casing (Units.Table (Elab_Order.Table (E)).Icasing); + Set_Name_Buffer; + end if; + end loop; + + Set_String (");"); + Write_Statement_Buffer; + + WBI (" "); + WBI (" begin"); + + Set_String (" SDP_Table_Build (ST'Address, "); + Set_Int (Num); + Set_String (", EA'Address, "); + Set_Int (Num_Elab_Calls + 2); + Set_String (");"); + Write_Statement_Buffer; + end Gen_Exception_Table_Ada; + + --------------------------- + -- Gen_Exception_Table_C -- + --------------------------- + + procedure Gen_Exception_Table_C is + Num : Nat; + Num2 : Nat; + + begin + if not Zero_Cost_Exceptions_Specified then + return; + end if; + + -- The code we generate looks like + + -- extern void *__gnat_unitname1__SDP; + -- extern void *__gnat_unitname2__SDP; + -- ... + -- + -- void **st[nnn] = { + -- &__gnat_unitname1__SDP, + -- &__gnat_unitname2__SDP, + -- ... + -- &__gnat_unitnamen__SDP}; + -- + -- extern void unitname1__elabb (); + -- extern void unitname2__elabb (); + -- ... + -- + -- void (*ea[eee]) () = { + -- adainit, + -- adafinal, + -- unitname1___elab[b,s], + -- unitname2___elab[b,s], + -- ... + -- unitnamen___elab[b,s]}; + -- + -- __gnat_SDP_Table_Build (&st, nnn, &ea, eee); + + Num := 0; + for A in ALIs.First .. ALIs.Last loop + if ALIs.Table (A).Unit_Exception_Table then + Num := Num + 1; + + Set_String (" extern void *__gnat_"); + Get_Name_String (Units.Table (ALIs.Table (A).First_Unit).Uname); + Set_Unit_Name; + Set_String ("__SDP"); + Set_Char (';'); + Write_Statement_Buffer; + end if; + end loop; + + WBI (" "); + + Set_String (" void **st["); + Set_Int (Num); + Set_String ("] = {"); + Write_Statement_Buffer; + + Num2 := 0; + for A in ALIs.First .. ALIs.Last loop + if ALIs.Table (A).Unit_Exception_Table then + Num2 := Num2 + 1; + + Set_String (" &__gnat_"); + Get_Name_String (Units.Table (ALIs.Table (A).First_Unit).Uname); + Set_Unit_Name; + Set_String ("__SDP"); + + if Num = Num2 then + Set_String ("};"); + else + Set_Char (','); + end if; + + Write_Statement_Buffer; + end if; + end loop; + + WBI (""); + for E in Elab_Order.First .. Elab_Order.Last loop + Get_Name_String (Units.Table (Elab_Order.Table (E)).Uname); + + if Units.Table (Elab_Order.Table (E)).No_Elab then + null; + + else + Set_String (" extern void "); + Set_Unit_Name; + Set_String ("___elab"); + Set_Char (Name_Buffer (Name_Len)); -- 's' or 'b' for spec/body + Set_String (" ();"); + Write_Statement_Buffer; + end if; + end loop; + + WBI (""); + Set_String (" void (*ea["); + Set_Int (Num_Elab_Calls + 2); + Set_String ("]) () = {"); + Write_Statement_Buffer; + + WBI (" " & Ada_Init_Name.all & ","); + Set_String (" system__standard_library__adafinal"); + + for E in Elab_Order.First .. Elab_Order.Last loop + Get_Name_String (Units.Table (Elab_Order.Table (E)).Uname); + + if Units.Table (Elab_Order.Table (E)).No_Elab then + null; + + else + Set_Char (','); + Write_Statement_Buffer; + Set_String (" "); + Set_Unit_Name; + Set_String ("___elab"); + Set_Char (Name_Buffer (Name_Len)); -- 's' or 'b' for spec/body + end if; + end loop; + + Set_String ("};"); + Write_Statement_Buffer; + + WBI (" "); + + Set_String (" __gnat_SDP_Table_Build (&st, "); + Set_Int (Num); + Set_String (", ea, "); + Set_Int (Num_Elab_Calls + 2); + Set_String (");"); + Write_Statement_Buffer; + end Gen_Exception_Table_C; + + ------------------ + -- Gen_Main_Ada -- + ------------------ + + procedure Gen_Main_Ada is + Target : constant String_Ptr := Target_Name; + VxWorks_Target : constant Boolean := + Target (Target'Last - 7 .. Target'Last) = "vxworks/"; + + begin + WBI (""); + Set_String (" function "); + Set_String (Get_Main_Name); + + if VxWorks_Target then + Set_String (" return Integer is"); + Write_Statement_Buffer; + + else + Write_Statement_Buffer; + WBI (" (argc : Integer;"); + WBI (" argv : System.Address;"); + WBI (" envp : System.Address)"); + WBI (" return Integer"); + WBI (" is"); + end if; + + -- Initialize and Finalize are not used in No_Run_Time mode + + if not No_Run_Time_Specified then + WBI (" procedure initialize;"); + WBI (" pragma Import (C, initialize, ""__gnat_initialize"");"); + WBI (""); + WBI (" procedure finalize;"); + WBI (" pragma Import (C, finalize, ""__gnat_finalize"");"); + WBI (""); + end if; + + -- Deal with declarations for main program case + + if not No_Main_Subprogram then + + -- To call the main program, we declare it using a pragma Import + -- Ada with the right link name. + + -- It might seem more obvious to "with" the main program, and call + -- it in the normal Ada manner. We do not do this for three reasons: + + -- 1. It is more efficient not to recompile the main program + -- 2. We are not entitled to assume the source is accessible + -- 3. We don't know what options to use to compile it + + -- It is really reason 3 that is most critical (indeed we used + -- to generate the "with", but several regression tests failed). + + WBI (""); + + if ALIs.Table (ALIs.First).Main_Program = Func then + WBI (" Result : Integer;"); + WBI (""); + WBI (" function Ada_Main_Program return Integer;"); + + else + WBI (" procedure Ada_Main_Program;"); + end if; + + Set_String (" pragma Import (Ada, Ada_Main_Program, """); + Get_Name_String (Units.Table (First_Unit_Entry).Uname); + Set_Main_Program_Name; + Set_String (""");"); + + Write_Statement_Buffer; + WBI (""); + end if; + + WBI (" begin"); + + -- On VxWorks, there are no command line arguments + + if VxWorks_Target then + WBI (" gnat_argc := 0;"); + WBI (" gnat_argv := System.Null_Address;"); + WBI (" gnat_envp := System.Null_Address;"); + + -- Normal case of command line arguments present + + else + WBI (" gnat_argc := argc;"); + WBI (" gnat_argv := argv;"); + WBI (" gnat_envp := envp;"); + WBI (""); + end if; + + if not No_Run_Time_Specified then + WBI (" Initialize;"); + end if; + + WBI (" " & Ada_Init_Name.all & ";"); + + if not No_Main_Subprogram then + WBI (" Break_Start;"); + + if ALIs.Table (ALIs.First).Main_Program = Proc then + WBI (" Ada_Main_Program;"); + else + WBI (" Result := Ada_Main_Program;"); + end if; + end if; + + -- Adafinal is only called if we have a run time + + if not No_Run_Time_Specified then + + -- If compiling for the JVM, we directly call Adafinal because + -- we don't import it via Do_Finalize (see Gen_Output_File_Ada). + + if Hostparm.Java_VM then + WBI (" System.Standard_Library.Adafinal;"); + else + WBI (" Do_Finalize;"); + end if; + end if; + + -- Finalize is only called if we have a run time + + if not No_Run_Time_Specified then + WBI (" Finalize;"); + end if; + + -- Return result + + if No_Main_Subprogram + or else ALIs.Table (ALIs.First).Main_Program = Proc + then + WBI (" return (gnat_exit_status);"); + else + WBI (" return (Result);"); + end if; + + WBI (" end;"); + end Gen_Main_Ada; + + ---------------- + -- Gen_Main_C -- + ---------------- + + procedure Gen_Main_C is + Target : constant String_Ptr := Target_Name; + VxWorks_Target : constant Boolean := + Target (Target'Last - 7 .. Target'Last) = "vxworks/"; + + begin + Set_String ("int "); + Set_String (Get_Main_Name); + + -- On VxWorks, there are no command line arguments + + if VxWorks_Target then + Set_String (" ()"); + + -- Normal case with command line arguments present + + else + Set_String (" (argc, argv, envp)"); + end if; + + Write_Statement_Buffer; + + -- VxWorks doesn't have the notion of argc/argv + + if VxWorks_Target then + WBI ("{"); + WBI (" int result;"); + WBI (" gnat_argc = 0;"); + WBI (" gnat_argv = 0;"); + WBI (" gnat_envp = 0;"); + + -- Normal case of arguments present + + else + WBI (" int argc;"); + WBI (" char **argv;"); + WBI (" char **envp;"); + WBI ("{"); + + if ALIs.Table (ALIs.First).Main_Program = Func then + WBI (" int result;"); + end if; + + WBI (" gnat_argc = argc;"); + WBI (" gnat_argv = argv;"); + WBI (" gnat_envp = envp;"); + WBI (" "); + end if; + + -- The __gnat_initialize routine is used only if we have a run-time + + if not No_Run_Time_Specified then + WBI + (" __gnat_initialize ();"); + end if; + + WBI (" " & Ada_Init_Name.all & " ();"); + + if not No_Main_Subprogram then + + WBI (" __gnat_break_start ();"); + WBI (" "); + + -- Output main program name + + Get_Name_String (Units.Table (First_Unit_Entry).Uname); + + -- Main program is procedure case + + if ALIs.Table (ALIs.First).Main_Program = Proc then + Set_String (" "); + Set_Main_Program_Name; + Set_String (" ();"); + Write_Statement_Buffer; + + -- Main program is function case + + else -- ALIs.Table (ALIs_First).Main_Program = Func + Set_String (" result = "); + Set_Main_Program_Name; + Set_String (" ();"); + Write_Statement_Buffer; + end if; + + end if; + + -- Adafinal is called only when we have a run-time + + if not No_Run_Time_Specified then + WBI (" "); + WBI (" system__standard_library__adafinal ();"); + end if; + + -- The finalize routine is used only if we have a run-time + + if not No_Run_Time_Specified then + WBI (" __gnat_finalize ();"); + end if; + + if ALIs.Table (ALIs.First).Main_Program = Func then + + if Hostparm.OpenVMS then + + -- VMS must use the Posix exit routine in order to get an + -- Unix compatible exit status. + + WBI (" __posix_exit (result);"); + + else + WBI (" exit (result);"); + end if; + + else + + if Hostparm.OpenVMS then + -- VMS must use the Posix exit routine in order to get an + -- Unix compatible exit status. + WBI (" __posix_exit (gnat_exit_status);"); + else + WBI (" exit (gnat_exit_status);"); + end if; + end if; + + WBI ("}"); + end Gen_Main_C; + + ------------------------------ + -- Gen_Object_Files_Options -- + ------------------------------ + + procedure Gen_Object_Files_Options is + Lgnat : Integer; + + procedure Write_Linker_Option; + -- Write binder info linker option. + + ------------------------- + -- Write_Linker_Option -- + ------------------------- + + procedure Write_Linker_Option is + Start : Natural; + Stop : Natural; + + begin + -- Loop through string, breaking at null's + + Start := 1; + while Start < Name_Len loop + + -- Find null ending this section + + Stop := Start + 1; + while Name_Buffer (Stop) /= ASCII.NUL + and then Stop <= Name_Len loop + Stop := Stop + 1; + end loop; + + -- Process section if non-null + + if Stop > Start then + if Output_Linker_Option_List then + Write_Str (Name_Buffer (Start .. Stop - 1)); + Write_Eol; + end if; + Write_Info_Ada_C + (" -- ", "", Name_Buffer (Start .. Stop - 1)); + end if; + + Start := Stop + 1; + end loop; + end Write_Linker_Option; + + -- Start of processing for Gen_Object_Files_Options + + begin + WBI (""); + Write_Info_Ada_C ("--", "/*", " BEGIN Object file/option list"); + + for E in Elab_Order.First .. Elab_Order.Last loop + + -- If not spec that has an associated body, then generate a + -- comment giving the name of the corresponding object file. + + if Units.Table (Elab_Order.Table (E)).Utype /= Is_Spec then + Get_Name_String + (ALIs.Table + (Units.Table (Elab_Order.Table (E)).My_ALI).Ofile_Full_Name); + + -- If the presence of an object file is necessary or if it + -- exists, then use it. + + if not Hostparm.Exclude_Missing_Objects + or else + GNAT.OS_Lib.Is_Regular_File (Name_Buffer (1 .. Name_Len)) + then + Write_Info_Ada_C (" -- ", "", Name_Buffer (1 .. Name_Len)); + if Output_Object_List then + Write_Str (Name_Buffer (1 .. Name_Len)); + Write_Eol; + end if; + + -- Don't link with the shared library on VMS if an internal + -- filename object is seen. Multiply defined symbols will + -- result. + + if Hostparm.OpenVMS + and then Is_Internal_File_Name + (ALIs.Table + (Units.Table (Elab_Order.Table (E)).My_ALI).Sfile) + then + Opt.Shared_Libgnat := False; + end if; + + end if; + end if; + end loop; + + -- Add a "-Ldir" for each directory in the object path. We skip this + -- in No_Run_Time mode, where we want more precise control of exactly + -- what goes into the resulting object file + + if not No_Run_Time_Specified then + for J in 1 .. Nb_Dir_In_Obj_Search_Path loop + declare + Dir : String_Ptr := Dir_In_Obj_Search_Path (J); + + begin + Name_Len := 0; + Add_Str_To_Name_Buffer ("-L"); + Add_Str_To_Name_Buffer (Dir.all); + Write_Linker_Option; + end; + end loop; + end if; + + -- Sort linker options + + Sort (Linker_Options.Last, Move_Linker_Option'Access, + Lt_Linker_Option'Access); + + -- Write user linker options + + Lgnat := Linker_Options.Last + 1; + + for J in 1 .. Linker_Options.Last loop + if not Linker_Options.Table (J).Internal_File then + Get_Name_String (Linker_Options.Table (J).Name); + Write_Linker_Option; + else + Lgnat := J; + exit; + end if; + end loop; + + if not (No_Run_Time_Specified or else Opt.No_Stdlib) then + + Name_Len := 0; + + if Opt.Shared_Libgnat then + Add_Str_To_Name_Buffer ("-shared"); + else + Add_Str_To_Name_Buffer ("-static"); + end if; + + -- Write directly to avoid -K output. + + Write_Info_Ada_C (" -- ", "", Name_Buffer (1 .. Name_Len)); + + if With_DECGNAT then + Name_Len := 0; + Add_Str_To_Name_Buffer ("-ldecgnat"); + Write_Linker_Option; + end if; + + if With_GNARL then + Name_Len := 0; + Add_Str_To_Name_Buffer ("-lgnarl"); + Write_Linker_Option; + end if; + + Name_Len := 0; + Add_Str_To_Name_Buffer ("-lgnat"); + Write_Linker_Option; + + end if; + + -- Write internal linker options + + for J in Lgnat .. Linker_Options.Last loop + Get_Name_String (Linker_Options.Table (J).Name); + Write_Linker_Option; + end loop; + + if Ada_Bind_File then + WBI ("-- END Object file/option list "); + else + WBI (" END Object file/option list */"); + end if; + + end Gen_Object_Files_Options; + + --------------------- + -- Gen_Output_File -- + --------------------- + + procedure Gen_Output_File (Filename : String) is + + function Public_Version return Boolean; + -- Return true if the version number contains a 'p' + + function Public_Version return Boolean is + begin + for J in Gnat_Version_String'Range loop + if Gnat_Version_String (J) = 'p' then + return True; + end if; + end loop; + + return False; + end Public_Version; + + -- Start of processing for Gen_Output_File + + begin + -- Override Ada_Bind_File and Bind_Main_Program for Java since + -- JGNAT only supports Ada code, and the main program is already + -- generated by the compiler. + + if Hostparm.Java_VM then + Ada_Bind_File := True; + Bind_Main_Program := False; + end if; + + -- Override time slice value if -T switch is set + + if Time_Slice_Set then + ALIs.Table (ALIs.First).Time_Slice_Value := Opt.Time_Slice_Value; + end if; + + -- Count number of elaboration calls + + for E in Elab_Order.First .. Elab_Order.Last loop + if Units.Table (Elab_Order.Table (E)).No_Elab then + null; + else + Num_Elab_Calls := Num_Elab_Calls + 1; + end if; + end loop; + + -- Get the time stamp of the former bind for public version warning + + if Public_Version then + Record_Time_From_Last_Bind; + end if; + + -- Generate output file in appropriate language + + if Ada_Bind_File then + Gen_Output_File_Ada (Filename); + else + Gen_Output_File_C (Filename); + end if; + + -- Periodically issue a warning when the public version is used on + -- big projects + + if Public_Version then + Public_Version_Warning; + end if; + end Gen_Output_File; + + ------------------------- + -- Gen_Output_File_Ada -- + ------------------------- + + procedure Gen_Output_File_Ada (Filename : String) is + + Bfiles : Name_Id; + -- Name of generated bind file (spec) + + Bfileb : Name_Id; + -- Name of generated bind file (body) + + Ada_Main : constant String := Get_Ada_Main_Name; + -- Name to be used for generated Ada main program. See the body of + -- function Get_Ada_Main_Name for details on the form of the name. + + Target : constant String_Ptr := Target_Name; + VxWorks_Target : constant Boolean := + Target (Target'Last - 7 .. Target'Last) = "vxworks/"; + + begin + -- Create spec first + + Create_Binder_Output (Filename, 's', Bfiles); + + if No_Run_Time_Specified then + WBI ("pragma No_Run_Time;"); + end if; + + -- Generate with of System so we can reference System.Address, note + -- that such a reference is safe even in No_Run_Time mode, since we + -- do not need any run-time code for such a reference, and we output + -- a pragma No_Run_Time for this compilation above. + + WBI ("with System;"); + + -- Generate with of System.Initialize_Scalars if active + + if Initialize_Scalars_Used then + WBI ("with System.Scalar_Values;"); + end if; + + Resolve_Binder_Options; + + if not No_Run_Time_Specified then + + -- Usually, adafinal is called using a pragma Import C. Since + -- Import C doesn't have the same semantics for JGNAT, we use + -- standard Ada. + + if Hostparm.Java_VM then + WBI ("with System.Standard_Library;"); + end if; + end if; + + WBI ("package " & Ada_Main & " is"); + + -- Main program case + + if Bind_Main_Program then + + -- Generate argc/argv stuff + + WBI (""); + WBI (" gnat_argc : Integer;"); + WBI (" gnat_argv : System.Address;"); + WBI (" gnat_envp : System.Address;"); + + -- If we have a run time present, these variables are in the + -- runtime data area for easy access from the runtime + + if not No_Run_Time_Specified then + WBI (""); + WBI (" pragma Import (C, gnat_argc);"); + WBI (" pragma Import (C, gnat_argv);"); + WBI (" pragma Import (C, gnat_envp);"); + end if; + + -- Define exit status. Again in normal mode, this is in the + -- run-time library, and is initialized there, but in the no + -- run time case, the variable is here and initialized here. + + WBI (""); + + if No_Run_Time_Specified then + WBI (" gnat_exit_status : Integer := 0;"); + else + WBI (" gnat_exit_status : Integer;"); + WBI (" pragma Import (C, gnat_exit_status);"); + end if; + end if; + + -- Generate the GNAT_Version info only for the main program. Otherwise, + -- it can lead under some circumstances to a symbol duplication during + -- the link (for instance when a C program uses 2 Ada libraries) + + if Bind_Main_Program then + WBI (""); + WBI (" GNAT_Version : constant String :="); + WBI (" ""GNAT Version: " & + Gnat_Version_String & """;"); + WBI (" pragma Export (C, GNAT_Version, ""__gnat_version"");"); + end if; + + -- No need to generate a finalization routine if there is no + -- runtime, since there is nothing to do in this case. + + if not No_Run_Time_Specified then + WBI (""); + WBI (" procedure " & Ada_Final_Name.all & ";"); + WBI (" pragma Export (C, " & Ada_Final_Name.all & ", """ & + Ada_Final_Name.all & """);"); + end if; + + WBI (""); + WBI (" procedure " & Ada_Init_Name.all & ";"); + WBI (" pragma Export (C, " & Ada_Init_Name.all & ", """ & + Ada_Init_Name.all & """);"); + + if Bind_Main_Program then + + -- If we have a run time, then Break_Start is defined there, but + -- if there is no run-time, Break_Start is defined in this file. + + WBI (""); + WBI (" procedure Break_Start;"); + + if No_Run_Time_Specified then + WBI (" pragma Export (C, Break_Start, ""__gnat_break_start"");"); + else + WBI (" pragma Import (C, Break_Start, ""__gnat_break_start"");"); + end if; + + WBI (""); + WBI (" function " & Get_Main_Name); + + -- Generate argument list (except on VxWorks, where none is present) + + if not VxWorks_Target then + WBI (" (argc : Integer;"); + WBI (" argv : System.Address;"); + WBI (" envp : System.Address)"); + end if; + + WBI (" return Integer;"); + WBI (" pragma Export (C, " & Get_Main_Name & ", """ & + Get_Main_Name & """);"); + end if; + + if Initialize_Scalars_Used then + Gen_Scalar_Values; + end if; + + Gen_Versions_Ada; + Gen_Elab_Order_Ada; + + -- Spec is complete + + WBI (""); + WBI ("end " & Ada_Main & ";"); + Close_Binder_Output; + + -- Prepare to write body + + Create_Binder_Output (Filename, 'b', Bfileb); + + -- Output Source_File_Name pragmas which look like + + -- pragma Source_File_Name (Ada_Main, Spec_File_Name => "sss"); + -- pragma Source_File_Name (Ada_Main, Body_File_Name => "bbb"); + + -- where sss/bbb are the spec/body file names respectively + + Get_Name_String (Bfiles); + Name_Buffer (Name_Len + 1 .. Name_Len + 3) := """);"; + + WBI ("pragma Source_File_Name (" & + Ada_Main & + ", Spec_File_Name => """ & + Name_Buffer (1 .. Name_Len + 3)); + + Get_Name_String (Bfileb); + Name_Buffer (Name_Len + 1 .. Name_Len + 3) := """);"; + + WBI ("pragma Source_File_Name (" & + Ada_Main & + ", Body_File_Name => """ & + Name_Buffer (1 .. Name_Len + 3)); + + WBI (""); + WBI ("package body " & Ada_Main & " is"); + + -- Import the finalization procedure only if there is a runtime. + + if not No_Run_Time_Specified then + + -- In the Java case, pragma Import C cannot be used, so the + -- standard Ada constructs will be used instead. + + if not Hostparm.Java_VM then + WBI (""); + WBI (" procedure Do_Finalize;"); + WBI + (" pragma Import (C, Do_Finalize, " & + """system__standard_library__adafinal"");"); + WBI (""); + end if; + end if; + + Gen_Adainit_Ada; + + -- No need to generate a finalization routine if there is no + -- runtime, since there is nothing to do in this case. + + if not No_Run_Time_Specified then + Gen_Adafinal_Ada; + end if; + + if Bind_Main_Program then + + -- In No_Run_Time mode, generate dummy body for Break_Start + + if No_Run_Time_Specified then + WBI (""); + WBI (" procedure Break_Start is"); + WBI (" begin"); + WBI (" null;"); + WBI (" end;"); + end if; + + Gen_Main_Ada; + end if; + + -- Output object file list and the Ada body is complete + + Gen_Object_Files_Options; + + WBI (""); + WBI ("end " & Ada_Main & ";"); + + Close_Binder_Output; + end Gen_Output_File_Ada; + + ----------------------- + -- Gen_Output_File_C -- + ----------------------- + + procedure Gen_Output_File_C (Filename : String) is + + Bfile : Name_Id; + -- Name of generated bind file + + begin + Create_Binder_Output (Filename, 'c', Bfile); + + Resolve_Binder_Options; + + WBI ("#ifdef __STDC__"); + WBI ("#define PARAMS(paramlist) paramlist"); + WBI ("#else"); + WBI ("#define PARAMS(paramlist) ()"); + WBI ("#endif"); + WBI (""); + + WBI ("extern void __gnat_set_globals "); + WBI (" PARAMS ((int, int, int, int, int, int, "); + WBI (" void (*) PARAMS ((void)), int, int));"); + WBI ("extern void " & Ada_Final_Name.all & " PARAMS ((void));"); + WBI ("extern void " & Ada_Init_Name.all & " PARAMS ((void));"); + + WBI ("extern void system__standard_library__adafinal PARAMS ((void));"); + + if not No_Main_Subprogram then + WBI ("extern int main PARAMS ((int, char **, char **));"); + if Hostparm.OpenVMS then + WBI ("extern void __posix_exit PARAMS ((int));"); + else + WBI ("extern void exit PARAMS ((int));"); + end if; + + WBI ("extern void __gnat_break_start PARAMS ((void));"); + Set_String ("extern "); + + if ALIs.Table (ALIs.First).Main_Program = Proc then + Set_String ("void "); + else + Set_String ("int "); + end if; + + Get_Name_String (Units.Table (First_Unit_Entry).Uname); + Set_Main_Program_Name; + Set_String (" PARAMS ((void));"); + Write_Statement_Buffer; + end if; + + if not No_Run_Time_Specified then + WBI ("extern void __gnat_initialize PARAMS ((void));"); + WBI ("extern void __gnat_finalize PARAMS ((void));"); + WBI ("extern void __gnat_install_handler PARAMS ((void));"); + end if; + + WBI (""); + + Gen_Elab_Defs_C; + + -- Imported variable used to track elaboration/finalization phase. + -- Used only when we have a runtime. + + if not No_Run_Time_Specified then + WBI ("extern int __gnat_handler_installed;"); + WBI (""); + end if; + + -- Write argv/argc stuff if main program case + + if Bind_Main_Program then + + -- In the normal case, these are in the runtime library + + if not No_Run_Time_Specified then + WBI ("extern int gnat_argc;"); + WBI ("extern char **gnat_argv;"); + WBI ("extern char **gnat_envp;"); + WBI ("extern int gnat_exit_status;"); + + -- In the No_Run_Time case, they are right in the binder file + -- and we initialize gnat_exit_status in the declaration. + + else + WBI ("int gnat_argc;"); + WBI ("char **gnat_argv;"); + WBI ("char **gnat_envp;"); + WBI ("int gnat_exit_status = 0;"); + end if; + + WBI (""); + end if; + + -- In no run-time mode, the __gnat_break_start routine (for the + -- debugger to get initial control) is defined in this file. + + if No_Run_Time_Specified then + WBI (""); + WBI ("void __gnat_break_start () {}"); + end if; + + -- Generate the __gnat_version info only for the main program. + -- Otherwise, it can lead under some circumstances to a symbol + -- duplication during the link (for instance when a C program + -- uses 2 Ada libraries) + + if Bind_Main_Program then + WBI (""); + WBI ("char __gnat_version[] = ""GNAT Version: " & + Gnat_Version_String & """;"); + end if; + + -- Generate the adafinal routine. In no runtime mode, this is + -- not needed, since there is no finalization to do. + + if not No_Run_Time_Specified then + Gen_Adafinal_C; + end if; + + Gen_Adainit_C; + + -- Main is only present for Ada main case + + if Bind_Main_Program then + Gen_Main_C; + end if; + + -- Scalar values, versions and object files needed in both cases + + if Initialize_Scalars_Used then + Gen_Scalar_Values; + end if; + + Gen_Versions_C; + Gen_Elab_Order_C; + Gen_Object_Files_Options; + + -- C binder output is complete + + Close_Binder_Output; + end Gen_Output_File_C; + + ----------------------- + -- Gen_Scalar_Values -- + ----------------------- + + procedure Gen_Scalar_Values is + + -- Strings to hold hex values of initialization constants. Note that + -- we store these strings in big endian order, but they are actually + -- used to initialize integer values, so the actual generated data + -- will automaticaly have the right endianess. + + IS_Is1 : String (1 .. 2); + IS_Is2 : String (1 .. 4); + IS_Is4 : String (1 .. 8); + IS_Is8 : String (1 .. 16); + IS_Iu1 : String (1 .. 2); + IS_Iu2 : String (1 .. 4); + IS_Iu4 : String (1 .. 8); + IS_Iu8 : String (1 .. 16); + IS_Isf : String (1 .. 8); + IS_Ifl : String (1 .. 8); + IS_Ilf : String (1 .. 16); + + -- The string for Long_Long_Float is special. This is used only on the + -- ia32 with 80-bit extended float (stored in 96 bits by gcc). The + -- value here is represented little-endian, since that's the only way + -- it is ever generated (this is not used on big-endian machines. + + IS_Ill : String (1 .. 24); + + begin + -- -Sin (invalid values) + + if Opt.Initialize_Scalars_Mode = 'I' then + IS_Is1 := "80"; + IS_Is2 := "8000"; + IS_Is4 := "80000000"; + IS_Is8 := "8000000000000000"; + IS_Iu1 := "FF"; + IS_Iu2 := "FFFF"; + IS_Iu4 := "FFFFFFFF"; + IS_Iu8 := "FFFFFFFFFFFFFFFF"; + IS_Isf := IS_Iu4; + IS_Ifl := IS_Iu4; + IS_Ilf := IS_Iu8; + IS_Ill := "00000000000000C0FFFF0000"; + + -- -Slo (low values) + + elsif Opt.Initialize_Scalars_Mode = 'L' then + IS_Is1 := "80"; + IS_Is2 := "8000"; + IS_Is4 := "80000000"; + IS_Is8 := "8000000000000000"; + IS_Iu1 := "00"; + IS_Iu2 := "0000"; + IS_Iu4 := "00000000"; + IS_Iu8 := "0000000000000000"; + IS_Isf := "FF800000"; + IS_Ifl := IS_Isf; + IS_Ilf := "FFF0000000000000"; + IS_Ill := "0000000000000080FFFF0000"; + + -- -Shi (high values) + + elsif Opt.Initialize_Scalars_Mode = 'H' then + IS_Is1 := "7F"; + IS_Is2 := "7FFF"; + IS_Is4 := "7FFFFFFF"; + IS_Is8 := "7FFFFFFFFFFFFFFF"; + IS_Iu1 := "FF"; + IS_Iu2 := "FFFF"; + IS_Iu4 := "FFFFFFFF"; + IS_Iu8 := "FFFFFFFFFFFFFFFF"; + IS_Isf := "7F800000"; + IS_Ifl := IS_Isf; + IS_Ilf := "7FF0000000000000"; + IS_Ill := "0000000000000080FF7F0000"; + + -- -Shh (hex byte) + + else pragma Assert (Opt.Initialize_Scalars_Mode = 'X'); + IS_Is1 (1 .. 2) := Opt.Initialize_Scalars_Val; + IS_Is2 (1 .. 2) := Opt.Initialize_Scalars_Val; + IS_Is2 (3 .. 4) := Opt.Initialize_Scalars_Val; + + for J in 1 .. 4 loop + IS_Is4 (2 * J - 1 .. 2 * J) := Opt.Initialize_Scalars_Val; + end loop; + + for J in 1 .. 8 loop + IS_Is8 (2 * J - 1 .. 2 * J) := Opt.Initialize_Scalars_Val; + end loop; + + IS_Iu1 := IS_Is1; + IS_Iu2 := IS_Is2; + IS_Iu4 := IS_Is4; + IS_Iu8 := IS_Is8; + + IS_Isf := IS_Is4; + IS_Ifl := IS_Is4; + IS_Ilf := IS_Is8; + + for J in 1 .. 12 loop + IS_Ill (2 * J - 1 .. 2 * J) := Opt.Initialize_Scalars_Val; + end loop; + end if; + + -- Generate output, Ada case + + if Ada_Bind_File then + WBI (""); + + Set_String (" IS_Is1 : constant System.Scalar_Values.Byte1 := 16#"); + Set_String (IS_Is1); + Write_Statement_Buffer ("#;"); + + Set_String (" IS_Is2 : constant System.Scalar_Values.Byte2 := 16#"); + Set_String (IS_Is2); + Write_Statement_Buffer ("#;"); + + Set_String (" IS_Is4 : constant System.Scalar_Values.Byte4 := 16#"); + Set_String (IS_Is4); + Write_Statement_Buffer ("#;"); + + Set_String (" IS_Is8 : constant System.Scalar_Values.Byte8 := 16#"); + Set_String (IS_Is8); + Write_Statement_Buffer ("#;"); + + Set_String (" IS_Iu1 : constant System.Scalar_Values.Byte1 := 16#"); + Set_String (IS_Iu1); + Write_Statement_Buffer ("#;"); + + Set_String (" IS_Iu2 : constant System.Scalar_Values.Byte2 := 16#"); + Set_String (IS_Iu2); + Write_Statement_Buffer ("#;"); + + Set_String (" IS_Iu4 : constant System.Scalar_Values.Byte4 := 16#"); + Set_String (IS_Iu4); + Write_Statement_Buffer ("#;"); + + Set_String (" IS_Iu8 : constant System.Scalar_Values.Byte8 := 16#"); + Set_String (IS_Iu8); + Write_Statement_Buffer ("#;"); + + Set_String (" IS_Isf : constant System.Scalar_Values.Byte4 := 16#"); + Set_String (IS_Isf); + Write_Statement_Buffer ("#;"); + + Set_String (" IS_Ifl : constant System.Scalar_Values.Byte4 := 16#"); + Set_String (IS_Ifl); + Write_Statement_Buffer ("#;"); + + Set_String (" IS_Ilf : constant System.Scalar_Values.Byte8 := 16#"); + Set_String (IS_Ilf); + Write_Statement_Buffer ("#;"); + + -- Special case of Long_Long_Float. This is a 10-byte value used + -- only on the x86. We could omit it for other architectures, but + -- we don't easily have that kind of target specialization in the + -- binder, and it's only 10 bytes, and only if -Sxx is used. Note + -- that for architectures where Long_Long_Float is the same as + -- Long_Float, the expander uses the Long_Float constant for the + -- initializations of Long_Long_Float values. + + WBI (" IS_Ill : constant array (1 .. 12) of"); + WBI (" System.Scalar_Values.Byte1 := ("); + Set_String (" "); + + for J in 1 .. 6 loop + Set_String (" 16#"); + Set_Char (IS_Ill (2 * J - 1)); + Set_Char (IS_Ill (2 * J)); + Set_String ("#,"); + end loop; + + Write_Statement_Buffer; + Set_String (" "); + + for J in 7 .. 12 loop + Set_String (" 16#"); + Set_Char (IS_Ill (2 * J - 1)); + Set_Char (IS_Ill (2 * J)); + + if J = 12 then + Set_String ("#);"); + else + Set_String ("#,"); + end if; + end loop; + + Write_Statement_Buffer; + + -- Output export statements to export to System.Scalar_Values + + WBI (""); + + WBI (" pragma Export (Ada, IS_Is1, ""__gnat_Is1"");"); + WBI (" pragma Export (Ada, IS_Is2, ""__gnat_Is2"");"); + WBI (" pragma Export (Ada, IS_Is4, ""__gnat_Is4"");"); + WBI (" pragma Export (Ada, IS_Is8, ""__gnat_Is8"");"); + WBI (" pragma Export (Ada, IS_Iu1, ""__gnat_Iu1"");"); + WBI (" pragma Export (Ada, IS_Iu2, ""__gnat_Iu2"");"); + WBI (" pragma Export (Ada, IS_Iu4, ""__gnat_Iu4"");"); + WBI (" pragma Export (Ada, IS_Iu8, ""__gnat_Iu8"");"); + WBI (" pragma Export (Ada, IS_Isf, ""__gnat_Isf"");"); + WBI (" pragma Export (Ada, IS_Ifl, ""__gnat_Ifl"");"); + WBI (" pragma Export (Ada, IS_Ilf, ""__gnat_Ilf"");"); + WBI (" pragma Export (Ada, IS_Ill, ""__gnat_Ill"");"); + + -- Generate output C case + + else + -- The lines we generate in this case are of the form + -- typ __gnat_I?? = 0x??; + -- where typ is appropriate to the length + + WBI (""); + + Set_String ("unsigned char __gnat_Is1 = 0x"); + Set_String (IS_Is1); + Write_Statement_Buffer (";"); + + Set_String ("unsigned short __gnat_Is2 = 0x"); + Set_String (IS_Is2); + Write_Statement_Buffer (";"); + + Set_String ("unsigned __gnat_Is4 = 0x"); + Set_String (IS_Is4); + Write_Statement_Buffer (";"); + + Set_String ("long long unsigned __gnat_Is8 = 0x"); + Set_String (IS_Is8); + Write_Statement_Buffer ("LL;"); + + Set_String ("unsigned char __gnat_Iu1 = 0x"); + Set_String (IS_Is1); + Write_Statement_Buffer (";"); + + Set_String ("unsigned short __gnat_Iu2 = 0x"); + Set_String (IS_Is2); + Write_Statement_Buffer (";"); + + Set_String ("unsigned __gnat_Iu4 = 0x"); + Set_String (IS_Is4); + Write_Statement_Buffer (";"); + + Set_String ("long long unsigned __gnat_Iu8 = 0x"); + Set_String (IS_Is8); + Write_Statement_Buffer ("LL;"); + + Set_String ("unsigned __gnat_Isf = 0x"); + Set_String (IS_Isf); + Write_Statement_Buffer (";"); + + Set_String ("unsigned __gnat_Ifl = 0x"); + Set_String (IS_Ifl); + Write_Statement_Buffer (";"); + + Set_String ("long long unsigned __gnat_Ilf = 0x"); + Set_String (IS_Ilf); + Write_Statement_Buffer ("LL;"); + + -- For Long_Long_Float, we generate + -- char __gnat_Ill[12] = {0x??, 0x??, 0x??, 0x??, 0x??, 0x??, + -- 0x??, 0x??, 0x??, 0x??, 0x??, 0x??); + + Set_String ("unsigned char __gnat_Ill[12] = {"); + + for J in 1 .. 6 loop + Set_String ("0x"); + Set_Char (IS_Ill (2 * J - 1)); + Set_Char (IS_Ill (2 * J)); + Set_String (", "); + end loop; + + Write_Statement_Buffer; + Set_String (" "); + + for J in 7 .. 12 loop + Set_String ("0x"); + Set_Char (IS_Ill (2 * J - 1)); + Set_Char (IS_Ill (2 * J)); + + if J = 12 then + Set_String ("};"); + else + Set_String (", "); + end if; + end loop; + + Write_Statement_Buffer; + end if; + end Gen_Scalar_Values; + + ---------------------- + -- Gen_Versions_Ada -- + ---------------------- + + -- This routine generates two sets of lines. The first set has the form: + + -- unnnnn : constant Integer := 16#hhhhhhhh#; + + -- The second set has the form + + -- pragma Export (C, unnnnn, unam); + + -- for each unit, where unam is the unit name suffixed by either B or + -- S for body or spec, with dots replaced by double underscores, and + -- hhhhhhhh is the version number, and nnnnn is a 5-digits serial number. + + procedure Gen_Versions_Ada is + Ubuf : String (1 .. 6) := "u00000"; + + procedure Increment_Ubuf; + -- Little procedure to increment the serial number + + procedure Increment_Ubuf is + begin + for J in reverse Ubuf'Range loop + Ubuf (J) := Character'Succ (Ubuf (J)); + exit when Ubuf (J) <= '9'; + Ubuf (J) := '0'; + end loop; + end Increment_Ubuf; + + -- Start of processing for Gen_Versions_Ada + + begin + if Bind_For_Library then + + -- When building libraries, the version number of each unit can + -- not be computed, since the binder does not know the full list + -- of units. Therefore, the 'Version and 'Body_Version + -- attributes can not supported in this case. + + return; + end if; + + WBI (""); + + WBI (" type Version_32 is mod 2 ** 32;"); + for U in Units.First .. Units.Last loop + Increment_Ubuf; + WBI (" " & Ubuf & " : constant Version_32 := 16#" & + Units.Table (U).Version & "#;"); + end loop; + + WBI (""); + Ubuf := "u00000"; + + for U in Units.First .. Units.Last loop + Increment_Ubuf; + Set_String (" pragma Export (C, "); + Set_String (Ubuf); + Set_String (", """); + + Get_Name_String (Units.Table (U).Uname); + + for K in 1 .. Name_Len loop + if Name_Buffer (K) = '.' then + Set_Char ('_'); + Set_Char ('_'); + + elsif Name_Buffer (K) = '%' then + exit; + + else + Set_Char (Name_Buffer (K)); + end if; + end loop; + + if Name_Buffer (Name_Len) = 's' then + Set_Char ('S'); + else + Set_Char ('B'); + end if; + + Set_String (""");"); + Write_Statement_Buffer; + end loop; + + end Gen_Versions_Ada; + + -------------------- + -- Gen_Versions_C -- + -------------------- + + -- This routine generates a line of the form: + + -- unsigned unam = 0xhhhhhhhh; + + -- for each unit, where unam is the unit name suffixed by either B or + -- S for body or spec, with dots replaced by double underscores. + + procedure Gen_Versions_C is + begin + if Bind_For_Library then + + -- When building libraries, the version number of each unit can + -- not be computed, since the binder does not know the full list + -- of units. Therefore, the 'Version and 'Body_Version + -- attributes can not supported. + + return; + end if; + + for U in Units.First .. Units.Last loop + Set_String ("unsigned "); + + Get_Name_String (Units.Table (U).Uname); + + for K in 1 .. Name_Len loop + if Name_Buffer (K) = '.' then + Set_String ("__"); + + elsif Name_Buffer (K) = '%' then + exit; + + else + Set_Char (Name_Buffer (K)); + end if; + end loop; + + if Name_Buffer (Name_Len) = 's' then + Set_Char ('S'); + else + Set_Char ('B'); + end if; + + Set_String (" = 0x"); + Set_String (Units.Table (U).Version); + Set_Char (';'); + Write_Statement_Buffer; + end loop; + + end Gen_Versions_C; + + ----------------------- + -- Get_Ada_Main_Name -- + ----------------------- + + function Get_Ada_Main_Name return String is + Suffix : constant String := "_00"; + Name : String (1 .. Opt.Ada_Main_Name.all'Length + Suffix'Length) := + Opt.Ada_Main_Name.all & Suffix; + Nlen : Natural; + + begin + -- The main program generated by JGNAT expects a package called + -- ada_<main procedure>. + + if Hostparm.Java_VM then + -- Get main program name + + Get_Name_String (Units.Table (First_Unit_Entry).Uname); + + -- Remove the %b + + return "ada_" & Name_Buffer (1 .. Name_Len - 2); + end if; + + -- This loop tries the following possibilities in order + -- <Ada_Main> + -- <Ada_Main>_01 + -- <Ada_Main>_02 + -- .. + -- <Ada_Main>_99 + -- where <Ada_Main> is equal to Opt.Ada_Main_Name. By default, + -- it is set to 'ada_main'. + + for J in 0 .. 99 loop + if J = 0 then + Nlen := Name'Length - Suffix'Length; + else + Nlen := Name'Length; + Name (Name'Last) := Character'Val (J mod 10 + Character'Pos ('0')); + Name (Name'Last - 1) := + Character'Val (J / 10 + Character'Pos ('0')); + end if; + + for K in ALIs.First .. ALIs.Last loop + for L in ALIs.Table (K).First_Unit .. ALIs.Table (K).Last_Unit loop + + -- Get unit name, removing %b or %e at end + + Get_Name_String (Units.Table (L).Uname); + Name_Len := Name_Len - 2; + + if Name_Buffer (1 .. Name_Len) = Name (1 .. Nlen) then + goto Continue; + end if; + end loop; + end loop; + + return Name (1 .. Nlen); + + <<Continue>> + null; + end loop; + + -- If we fall through, just use a peculiar unlikely name + + return ("Qwertyuiop"); + end Get_Ada_Main_Name; + + ------------------- + -- Get_Main_Name -- + ------------------- + + function Get_Main_Name return String is + Target : constant String_Ptr := Target_Name; + VxWorks_Target : constant Boolean := + Target (Target'Last - 7 .. Target'Last) = "vxworks/"; + + begin + -- Explicit name given with -M switch + + if Bind_Alternate_Main_Name then + return Alternate_Main_Name.all; + + -- Case of main program name to be used directly + + elsif VxWorks_Target then + + -- Get main program name + + Get_Name_String (Units.Table (First_Unit_Entry).Uname); + + -- If this is a child name, return only the name of the child, + -- since we can't have dots in a nested program name. Note that + -- we do not include the %b at the end of the unit name. + + for J in reverse 1 .. Name_Len - 3 loop + if J = 1 or else Name_Buffer (J - 1) = '.' then + return Name_Buffer (J .. Name_Len - 2); + end if; + end loop; + + raise Program_Error; -- impossible exit + + -- Case where "main" is to be used as default + + else + return "main"; + end if; + end Get_Main_Name; + + ---------------------- + -- Lt_Linker_Option -- + ---------------------- + + function Lt_Linker_Option (Op1, Op2 : Natural) return Boolean is + begin + if Linker_Options.Table (Op1).Internal_File + /= + Linker_Options.Table (Op2).Internal_File + then + return Linker_Options.Table (Op1).Internal_File + < + Linker_Options.Table (Op2).Internal_File; + else + if Units.Table (Linker_Options.Table (Op1).Unit).Elab_Position + /= + Units.Table (Linker_Options.Table (Op2).Unit).Elab_Position + then + return Units.Table (Linker_Options.Table (Op1).Unit).Elab_Position + > + Units.Table (Linker_Options.Table (Op2).Unit).Elab_Position; + + else + return Linker_Options.Table (Op1).Original_Pos + < + Linker_Options.Table (Op2).Original_Pos; + end if; + end if; + end Lt_Linker_Option; + + ------------------------ + -- Move_Linker_Option -- + ------------------------ + + procedure Move_Linker_Option (From : Natural; To : Natural) is + begin + Linker_Options.Table (To) := Linker_Options.Table (From); + end Move_Linker_Option; + + ---------------------------- + -- Public_Version_Warning -- + ---------------------------- + + procedure Public_Version_Warning is + + Time : Int := Time_From_Last_Bind; + + -- Constants to help defining periods + + Hour : constant := 60; + Day : constant := 24 * Hour; + + Never : constant := Integer'Last; + -- Special value indicating no warnings should be given + + -- Constants defining when the warning is issued. Programs with more + -- than Large Units will issue a warning every Period_Large amount of + -- time. Smaller programs will generate a warning every Period_Small + -- amount of time. + + Large : constant := 20; + -- Threshold for considering a program small or large + + Period_Large : constant := Day; + -- Periodic warning time for large programs + + Period_Small : constant := Never; + -- Periodic warning time for small programs + + Nb_Unit : Int; + + begin + -- Compute the number of units that are not GNAT internal files + + Nb_Unit := 0; + for A in ALIs.First .. ALIs.Last loop + if not Is_Internal_File_Name (ALIs.Table (A).Sfile) then + Nb_Unit := Nb_Unit + 1; + end if; + end loop; + + -- Do not emit the message if the last message was emitted in the + -- specified period taking into account the number of units. + + if Nb_Unit < Large and then Time <= Period_Small then + return; + + elsif Time <= Period_Large then + return; + end if; + + Write_Eol; + Write_Str ("IMPORTANT NOTICE:"); + Write_Eol; + Write_Str (" This version of GNAT is unsupported" + & " and comes with absolutely no warranty."); + Write_Eol; + Write_Str (" If you intend to evaluate or use GNAT for building " + & "commercial applications,"); + Write_Eol; + Write_Str (" please consult http://www.gnat.com/ for information"); + Write_Eol; + Write_Str (" on the GNAT Professional product line."); + Write_Eol; + Write_Eol; + end Public_Version_Warning; + + ---------------------------- + -- Resolve_Binder_Options -- + ---------------------------- + + procedure Resolve_Binder_Options is + begin + for E in Elab_Order.First .. Elab_Order.Last loop + Get_Name_String (Units.Table (Elab_Order.Table (E)).Uname); + + -- The procedure of looking for specific packages and setting + -- flags is very wrong, but there isn't a good alternative at + -- this time. + + if Name_Buffer (1 .. 19) = "system.os_interface" then + With_GNARL := True; + end if; + + if Hostparm.OpenVMS and then Name_Buffer (1 .. 3) = "dec" then + With_DECGNAT := True; + end if; + end loop; + end Resolve_Binder_Options; + + -------------- + -- Set_Char -- + -------------- + + procedure Set_Char (C : Character) is + begin + Last := Last + 1; + Statement_Buffer (Last) := C; + end Set_Char; + + ------------- + -- Set_Int -- + ------------- + + procedure Set_Int (N : Int) is + begin + if N < 0 then + Set_String ("-"); + Set_Int (-N); + + else + if N > 9 then + Set_Int (N / 10); + end if; + + Last := Last + 1; + Statement_Buffer (Last) := + Character'Val (N mod 10 + Character'Pos ('0')); + end if; + end Set_Int; + + --------------------------- + -- Set_Main_Program_Name -- + --------------------------- + + procedure Set_Main_Program_Name is + begin + -- Note that name has %b on the end which we ignore + + -- First we output the initial _ada_ since we know that the main + -- program is a library level subprogram. + + Set_String ("_ada_"); + + -- Copy name, changing dots to double underscores + + for J in 1 .. Name_Len - 2 loop + if Name_Buffer (J) = '.' then + Set_String ("__"); + else + Set_Char (Name_Buffer (J)); + end if; + end loop; + end Set_Main_Program_Name; + + --------------------- + -- Set_Name_Buffer -- + --------------------- + + procedure Set_Name_Buffer is + begin + for J in 1 .. Name_Len loop + Set_Char (Name_Buffer (J)); + end loop; + end Set_Name_Buffer; + + ---------------- + -- Set_String -- + ---------------- + + procedure Set_String (S : String) is + begin + Statement_Buffer (Last + 1 .. Last + S'Length) := S; + Last := Last + S'Length; + end Set_String; + + ------------------- + -- Set_Unit_Name -- + ------------------- + + procedure Set_Unit_Name is + begin + for J in 1 .. Name_Len - 2 loop + if Name_Buffer (J) /= '.' then + Set_Char (Name_Buffer (J)); + else + Set_String ("__"); + end if; + end loop; + end Set_Unit_Name; + + --------------------- + -- Set_Unit_Number -- + --------------------- + + procedure Set_Unit_Number (U : Unit_Id) is + Num_Units : constant Nat := Nat (Units.Table'Last) - Nat (Unit_Id'First); + Unum : constant Nat := Nat (U) - Nat (Unit_Id'First); + + begin + if Num_Units >= 10 and then Unum < 10 then + Set_Char ('0'); + end if; + + if Num_Units >= 100 and then Unum < 100 then + Set_Char ('0'); + end if; + + Set_Int (Unum); + end Set_Unit_Number; + + ------------ + -- Tab_To -- + ------------ + + procedure Tab_To (N : Natural) is + begin + while Last < N loop + Set_Char (' '); + end loop; + end Tab_To; + + ----------- + -- Value -- + ----------- + + function Value (chars : chars_ptr) return String is + function Strlen (chars : chars_ptr) return Natural; + pragma Import (C, Strlen); + + begin + if chars = Null_Address then + return ""; + + else + declare + subtype Result_Type is String (1 .. Strlen (chars)); + + Result : Result_Type; + for Result'Address use chars; + + begin + return Result; + end; + end if; + end Value; + + ---------------------- + -- Write_Info_Ada_C -- + ---------------------- + + procedure Write_Info_Ada_C (Ada : String; C : String; Common : String) is + begin + if Ada_Bind_File then + declare + S : String (1 .. Ada'Length + Common'Length); + + begin + S (1 .. Ada'Length) := Ada; + S (Ada'Length + 1 .. S'Length) := Common; + WBI (S); + end; + + else + declare + S : String (1 .. C'Length + Common'Length); + + begin + S (1 .. C'Length) := C; + S (C'Length + 1 .. S'Length) := Common; + WBI (S); + end; + end if; + end Write_Info_Ada_C; + + ---------------------------- + -- Write_Statement_Buffer -- + ---------------------------- + + procedure Write_Statement_Buffer is + begin + WBI (Statement_Buffer (1 .. Last)); + Last := 0; + end Write_Statement_Buffer; + + procedure Write_Statement_Buffer (S : String) is + begin + Set_String (S); + Write_Statement_Buffer; + end Write_Statement_Buffer; + +end Bindgen; |