OSDN Git Service

2007-04-20 Vincent Celier <celier@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / gnatdll.adb
index ac70e70..ada455e 100644 (file)
@@ -2,13 +2,11 @@
 --                                                                          --
 --                         GNAT COMPILER COMPONENTS                         --
 --                                                                          --
---                               G N A T D L L                              --
+--                              G N A T D L L                               --
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---                            $Revision$
---                                                                          --
---          Copyright (C) 1997-2001, Free Software Foundation, Inc.         --
+--          Copyright (C) 1997-2006, 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- --
 -- 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.                                                      --
+-- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
+-- Boston, MA 02110-1301, 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). --
+-- Extensive contributions were provided by Ada Core Technologies Inc.      --
 --                                                                          --
 ------------------------------------------------------------------------------
 
---  GNATDLL is a Windows specific tool to build DLL.
---  Both relocatable and non-relocatable DLL are supported
+--  GNATDLL is a Windows specific tool for building a DLL.
+--  Both relocatable and non-relocatable DLL's are supported
 
-with Ada.Text_IO;
-with Ada.Strings.Unbounded;
-with Ada.Exceptions;
-with Ada.Command_Line;
-with GNAT.OS_Lib;
-with GNAT.Command_Line;
+with Ada.Text_IO;           use Ada.Text_IO;
+with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
+with Ada.Exceptions;        use Ada.Exceptions;
+with Ada.Command_Line;      use Ada.Command_Line;
+with GNAT.OS_Lib;           use GNAT.OS_Lib;
+with GNAT.Command_Line;     use GNAT.Command_Line;
 with Gnatvsn;
 
-with MDLL.Files;
-with MDLL.Tools;
+with MDLL.Fil;              use MDLL.Fil;
+with MDLL.Utl;              use MDLL.Utl;
 
 procedure Gnatdll is
 
-   use GNAT;
-   use Ada;
-   use MDLL;
-   use Ada.Strings.Unbounded;
-
-   use type OS_Lib.Argument_List;
+   use type GNAT.OS_Lib.Argument_List;
 
    procedure Syntax;
-   --  print out usage.
+   --  Print out usage
 
    procedure Check (Filename : String);
-   --  check that filename exist.
+   --  Check that the file whose name is Filename exists
 
    procedure Parse_Command_Line;
-   --  parse the command line arguments of gnatdll.
+   --  Parse the command line arguments passed to gnatdll
 
    procedure Check_Context;
-   --  check the context before runing any commands to build the library.
+   --  Check the context before runing any commands to build the library
+
+   Syntax_Error : exception;
+   --  Raised when a syntax error is detected, in this case a usage info will
+   --  be displayed.
 
-   Syntax_Error  : exception;
    Context_Error : exception;
+   --  Raised when some files (specifed on the command line) are missing to
+   --  build the DLL.
 
-   Help          : Boolean := False;
+   Help : Boolean := False;
+   --  Help will be set to True the usage information is to be displayed
 
    Version : constant String := Gnatvsn.Gnat_Version_String;
-
-   --  default address for non relocatable DLL (Win32)
+   --  Why should it be necessary to make a copy of this
 
    Default_DLL_Address : constant String := "0x11000000";
+   --  Default address for non relocatable DLL (Win32)
+
+   Lib_Filename : Unbounded_String := Null_Unbounded_String;
+   --  The DLL filename that will be created (.dll)
 
-   Lib_Filename        : Unbounded_String := Null_Unbounded_String;
-   Def_Filename        : Unbounded_String := Null_Unbounded_String;
-   List_Filename       : Unbounded_String := Null_Unbounded_String;
-   DLL_Address         : Unbounded_String :=
-     To_Unbounded_String (Default_DLL_Address);
+   Def_Filename : Unbounded_String := Null_Unbounded_String;
+   --  The definition filename (.def)
 
-   --  list of objects to put inside the library
+   List_Filename : Unbounded_String := Null_Unbounded_String;
+   --  The name of the file containing the objects file to put into the DLL
 
-   Objects_Files : Argument_List_Access := Null_Argument_List_Access;
+   DLL_Address : Unbounded_String := To_Unbounded_String (Default_DLL_Address);
+   --  The DLL's base address
 
-   --  for each Ada files specified we keep record of the corresponding
-   --  Ali. This list of ali is used to build the binder program.
+   Gen_Map_File : Boolean := False;
+   --  Set to True if a map file is to be generated
 
-   Ali_Files     : Argument_List_Access := Null_Argument_List_Access;
+   Objects_Files : Argument_List_Access := MDLL.Null_Argument_List_Access;
+   --  List of objects to put inside the library
 
-   --  a list of options set in the command line.
+   Ali_Files : Argument_List_Access := MDLL.Null_Argument_List_Access;
+   --  For each Ada file specified, we keep arecord of the corresponding
+   --  ALI file. This list of SLI files is used to build the binder program.
 
-   Options       : Argument_List_Access := Null_Argument_List_Access;
+   Options : Argument_List_Access := MDLL.Null_Argument_List_Access;
+   --  A list of options set in the command line
 
-   --  gnat linker and binder args options
+   Largs_Options : Argument_List_Access := MDLL.Null_Argument_List_Access;
+   Bargs_Options : Argument_List_Access := MDLL.Null_Argument_List_Access;
+   --  GNAT linker and binder args options
 
-   Largs_Options : Argument_List_Access := Null_Argument_List_Access;
-   Bargs_Options : Argument_List_Access := Null_Argument_List_Access;
+   type Build_Mode_State is (Import_Lib, Dynamic_Lib, Dynamic_Lib_Only, Nil);
+   --  Import_Lib means only the .a file will be created, Dynamic_Lib means
+   --  that both the DLL and the import library will be created.
+   --  Dynamic_Lib_Only means that only the DLL will be created (no import
+   --  library).
 
-   type Build_Mode_State is (Import_Lib, Dynamic_Lib, Nil);
+   Build_Mode : Build_Mode_State := Nil;
+   --  Will be set when parsing the command line
 
-   Build_Mode             : Build_Mode_State := Nil;
    Must_Build_Relocatable : Boolean := True;
-   Build_Import           : Boolean := True;
+   --  True means build a relocatable DLL, will be set to False if a
+   --  non-relocatable DLL must be built.
 
    ------------
    -- Syntax --
    ------------
 
    procedure Syntax is
-      use Text_IO;
-
-      procedure P (Str : in String) renames Text_IO.Put_Line;
-
+      procedure P (Str : String) renames Put_Line;
    begin
       P ("Usage : gnatdll [options] [list-of-files]");
       New_Line;
@@ -129,9 +137,12 @@ procedure Gnatdll is
       P ("   -e file       Definition file containing exports");
       P ("   -d file       Put objects in the relocatable dynamic "
          & "library <file>");
+      P ("   -b addr       Set base address for the relocatable DLL");
+      P ("                 default address is " & Default_DLL_Address);
       P ("   -a[addr]      Build non-relocatable DLL at address <addr>");
       P ("                 if <addr> is not specified use "
          & Default_DLL_Address);
+      P ("   -m            Generate map file");
       P ("   -n            No-import - do not create the import library");
       P ("   -bargs opts   opts are passed to the binder");
       P ("   -largs opts   opts are passed to the linker");
@@ -141,11 +152,11 @@ procedure Gnatdll is
    -- Check --
    -----------
 
-   procedure Check (Filename : in String) is
+   procedure Check (Filename : String) is
    begin
-      if not OS_Lib.Is_Regular_File (Filename) then
-         Exceptions.Raise_Exception (Context_Error'Identity,
-                                     "Error: " & Filename & " not found.");
+      if not Is_Regular_File (Filename) then
+         Raise_Exception
+           (Context_Error'Identity, "Error: " & Filename & " not found.");
       end if;
    end Check;
 
@@ -155,80 +166,70 @@ procedure Gnatdll is
 
    procedure Parse_Command_Line is
 
-      use GNAT.Command_Line;
-
-      procedure Add_File (Filename : in String);
-      --  add one file to the list of file to handle
+      procedure Add_File (Filename : String);
+      --  Add one file to the list of file to handle
 
-      procedure Add_Files_From_List (List_Filename : in String);
-      --  add the files listed in List_Filename (one by line) to the list
+      procedure Add_Files_From_List (List_Filename : String);
+      --  Add the files listed in List_Filename (one by line) to the list
       --  of file to handle
 
-      procedure Ali_To_Object_List;
-      --  for each ali file in Afiles set put a corresponding object file in
-      --  Ofiles set.
-
-      --  these are arbitrary limits, a better way will be to use linked list.
-
       Max_Files   : constant := 5_000;
       Max_Options : constant :=   100;
+      --  These are arbitrary limits, a better way will be to use linked list.
+      --  No, a better choice would be to use tables ???
+      --  Limits on what???
 
-      --  objects files to put in the library
-
-      Ofiles : OS_Lib.Argument_List (1 .. Max_Files);
+      Ofiles : Argument_List (1 .. Max_Files);
       O      : Positive := Ofiles'First;
+      --  List of object files to put in the library. O is the next entry
+      --  to be used.
 
-      --  ali files.
-
-      Afiles : OS_Lib.Argument_List (1 .. Max_Files);
+      Afiles : Argument_List (1 .. Max_Files);
       A      : Positive := Afiles'First;
+      --  List of ALI files. A is the next entry to be used
 
-      --  gcc options.
-
-      Gopts  : OS_Lib.Argument_List (1 .. Max_Options);
+      Gopts  : Argument_List (1 .. Max_Options);
       G      : Positive := Gopts'First;
+      --  List of gcc options. G is the next entry to be used
 
-      --  largs options
-
-      Lopts  : OS_Lib.Argument_List (1 .. Max_Options);
+      Lopts  : Argument_List (1 .. Max_Options);
       L      : Positive := Lopts'First;
+      --  A list of -largs options (L is next entry to be used)
 
-      --  bargs options
-
-      Bopts  : OS_Lib.Argument_List (1 .. Max_Options);
+      Bopts  : Argument_List (1 .. Max_Options);
       B      : Positive := Bopts'First;
+      --  A list of -bargs options (B is next entry to be used)
+
+      Build_Import : Boolean := True;
+      --  Set to Fals if option -n if specified (no-import)
 
       --------------
       -- Add_File --
       --------------
 
-      procedure Add_File (Filename : in String) is
+      procedure Add_File (Filename : String) is
       begin
-         --  others files are to be put inside the dynamic library
-
-         if Files.Is_Ali (Filename) then
-
+         if Is_Ali (Filename) then
             Check (Filename);
 
-            --  record it to generate the binder program when
+            --  Record it to generate the binder program when
             --  building dynamic library
 
             Afiles (A) := new String'(Filename);
             A := A + 1;
 
-         elsif Files.Is_Obj (Filename) then
-
+         elsif Is_Obj (Filename) then
             Check (Filename);
 
-            --  just record this object file
+            --  Just record this object file
 
             Ofiles (O) := new String'(Filename);
             O := O + 1;
 
          else
-            --  unknown file type
+            --  Unknown file type
 
-            Exceptions.Raise_Exception
+            Raise_Exception
               (Syntax_Error'Identity,
                "don't know what to do with " & Filename & " !");
          end if;
@@ -238,41 +239,37 @@ procedure Gnatdll is
       -- Add_Files_From_List --
       -------------------------
 
-      procedure Add_Files_From_List (List_Filename : in String) is
-         File   : Text_IO.File_Type;
+      procedure Add_Files_From_List (List_Filename : String) is
+         File   : File_Type;
          Buffer : String (1 .. 500);
          Last   : Natural;
+
       begin
-         Text_IO.Open (File, Text_IO.In_File, List_Filename);
+         Open (File, In_File, List_Filename);
 
-         while not Text_IO.End_Of_File (File) loop
-            Text_IO.Get_Line (File, Buffer, Last);
+         while not End_Of_File (File) loop
+            Get_Line (File, Buffer, Last);
             Add_File (Buffer (1 .. Last));
          end loop;
 
-         Text_IO.Close (File);
+         Close (File);
+
+      exception
+         when Name_Error =>
+            Raise_Exception
+              (Syntax_Error'Identity,
+               "list-of-files file " & List_Filename & " not found.");
       end Add_Files_From_List;
 
-      ------------------------
-      -- Ali_To_Object_List --
-      ------------------------
-
-      procedure Ali_To_Object_List is
-      begin
-         for K in 1 .. A - 1 loop
-            Ofiles (O) := new String'(Files.Ext_To (Afiles (K).all, "o"));
-            O := O + 1;
-         end loop;
-      end Ali_To_Object_List;
+   --  Start of processing for Parse_Command_Line
 
    begin
-
       Initialize_Option_Scan ('-', False, "bargs largs");
 
       --  scan gnatdll switches
 
       loop
-         case Getopt ("g h v q k a? d: e: l: n I:") is
+         case Getopt ("g h v q k a? b: d: e: l: n m I:") is
 
             when ASCII.Nul =>
                exit;
@@ -285,21 +282,23 @@ procedure Gnatdll is
                G := G + 1;
 
             when 'v' =>
-               --  verbose mode on.
+
+               --  Turn verbose mode on
 
                MDLL.Verbose := True;
                if MDLL.Quiet then
-                  Exceptions.Raise_Exception
+                  Raise_Exception
                     (Syntax_Error'Identity,
                      "impossible to use -q and -v together.");
                end if;
 
             when 'q' =>
-               --  quiet mode on.
+
+               --  Turn quiet mode on
 
                MDLL.Quiet := True;
                if MDLL.Verbose then
-                  Exceptions.Raise_Exception
+                  Raise_Exception
                     (Syntax_Error'Identity,
                      "impossible to use -v and -q together.");
                end if;
@@ -312,7 +311,7 @@ procedure Gnatdll is
 
                if Parameter = "" then
 
-                  --  default address for a relocatable dynamic library.
+                  --  Default address for a relocatable dynamic library.
                   --  address for a non relocatable dynamic library.
 
                   DLL_Address := To_Unbounded_String (Default_DLL_Address);
@@ -323,23 +322,33 @@ procedure Gnatdll is
 
                Must_Build_Relocatable := False;
 
+            when 'b' =>
+
+               DLL_Address := To_Unbounded_String (Parameter);
+
+               Must_Build_Relocatable := True;
+
             when 'e' =>
 
                Def_Filename := To_Unbounded_String (Parameter);
 
             when 'd' =>
 
-               --  build a non relocatable DLL.
+               --  Build a non relocatable DLL
 
                Lib_Filename := To_Unbounded_String (Parameter);
 
                if Def_Filename = Null_Unbounded_String then
                   Def_Filename := To_Unbounded_String
-                    (Files.Ext_To (Parameter, "def"));
+                    (Ext_To (Parameter, "def"));
                end if;
 
                Build_Mode := Dynamic_Lib;
 
+            when 'm' =>
+
+               Gen_Map_File := True;
+
             when 'n' =>
 
                Build_Import := False;
@@ -353,12 +362,10 @@ procedure Gnatdll is
 
             when others =>
                raise Invalid_Switch;
-
          end case;
-
       end loop;
 
-      --  get parameters
+      --  Get parameters
 
       loop
          declare
@@ -369,24 +376,22 @@ procedure Gnatdll is
          end;
       end loop;
 
-      --  get largs parameters
+      --  Get largs parameters
 
       Goto_Section ("largs");
 
       loop
          case Getopt ("*") is
-
             when ASCII.Nul =>
                exit;
 
             when others =>
                Lopts (L) := new String'(Full_Switch);
                L := L + 1;
-
          end case;
       end loop;
 
-      --  get bargs parameters
+      --  Get bargs parameters
 
       Goto_Section ("bargs");
 
@@ -403,22 +408,31 @@ procedure Gnatdll is
          end case;
       end loop;
 
-      --  if list filename has been specified parse it
+      --  if list filename has been specified, parse it
 
       if List_Filename /= Null_Unbounded_String then
          Add_Files_From_List (To_String (List_Filename));
       end if;
 
-      --  check if the set of parameters are compatible.
+      --  Check if the set of parameters are compatible
+
+      if Build_Mode = Nil and then not Help and then not MDLL.Verbose then
+         Raise_Exception (Syntax_Error'Identity, "nothing to do.");
+      end if;
 
-      if Build_Mode = Nil and then not Help and then not Verbose then
-         Exceptions.Raise_Exception
+      --  -n option but no file specified
+
+      if not Build_Import
+        and then A = Afiles'First
+        and then O = Ofiles'First
+      then
+         Raise_Exception
            (Syntax_Error'Identity,
-            "nothing to do.");
+            "-n specified but there are no objects to build the library.");
       end if;
 
-      --  check if we want to build an import library (option -e and no file
-      --  specified)
+      --  Check if we want to build an import library (option -e and
+      --  no file specified)
 
       if Build_Mode = Dynamic_Lib
         and then A = Afiles'First
@@ -427,38 +441,50 @@ procedure Gnatdll is
          Build_Mode := Import_Lib;
       end if;
 
+      --  If map file is to be generated, add linker option here
+
+      if Gen_Map_File and then Build_Mode = Import_Lib then
+         Raise_Exception
+           (Syntax_Error'Identity,
+            "Can't generate a map file for an import library.");
+      end if;
+
+      --  Check if only a dynamic library must be built
+
+      if Build_Mode = Dynamic_Lib and then not Build_Import then
+         Build_Mode := Dynamic_Lib_Only;
+      end if;
+
       if O /= Ofiles'First then
-         Objects_Files := new OS_Lib.Argument_List'(Ofiles (1 .. O - 1));
+         Objects_Files := new Argument_List'(Ofiles (1 .. O - 1));
       end if;
 
       if A /= Afiles'First then
-         Ali_Files     := new OS_Lib.Argument_List'(Afiles (1 .. A - 1));
+         Ali_Files     := new Argument_List'(Afiles (1 .. A - 1));
       end if;
 
       if G /= Gopts'First then
-         Options       := new OS_Lib.Argument_List'(Gopts (1 .. G - 1));
+         Options       := new Argument_List'(Gopts (1 .. G - 1));
       end if;
 
       if L /= Lopts'First then
-         Largs_Options := new OS_Lib.Argument_List'(Lopts (1 .. L - 1));
+         Largs_Options := new Argument_List'(Lopts (1 .. L - 1));
       end if;
 
       if B /= Bopts'First then
-         Bargs_Options := new OS_Lib.Argument_List'(Bopts (1 .. B - 1));
+         Bargs_Options := new Argument_List'(Bopts (1 .. B - 1));
       end if;
 
    exception
-
       when Invalid_Switch    =>
-         Exceptions.Raise_Exception
+         Raise_Exception
            (Syntax_Error'Identity,
             Message => "Invalid Switch " & Full_Switch);
 
       when Invalid_Parameter =>
-         Exceptions.Raise_Exception
+         Raise_Exception
            (Syntax_Error'Identity,
             Message => "No parameter for " & Full_Switch);
-
    end Parse_Command_Line;
 
    -------------------
@@ -467,19 +493,19 @@ procedure Gnatdll is
 
    procedure Check_Context is
    begin
-
       Check (To_String (Def_Filename));
 
-      --  check that each object file specified exist
-      --  raises Context_Error if it does not.
+      --  Check that each object file specified exists and raise exception
+      --  Context_Error if it does not.
 
       for F in Objects_Files'Range loop
          Check (Objects_Files (F).all);
       end loop;
    end Check_Context;
 
-begin
+--  Start of processing for Gnatdll
 
+begin
    if Ada.Command_Line.Argument_Count = 0 then
       Help := True;
    else
@@ -487,12 +513,12 @@ begin
    end if;
 
    if MDLL.Verbose or else Help then
-      Text_IO.New_Line;
-      Text_IO.Put_Line ("GNATDLL " & Version & " - Dynamic Libraries Builder");
-      Text_IO.New_Line;
+      New_Line;
+      Put_Line ("GNATDLL " & Version & " - Dynamic Libraries Builder");
+      New_Line;
    end if;
 
-   MDLL.Tools.Locate;
+   MDLL.Utl.Locate;
 
    if Help
      or else (MDLL.Verbose and then Ada.Command_Line.Argument_Count = 1)
@@ -502,7 +528,6 @@ begin
       Check_Context;
 
       case Build_Mode is
-
          when Import_Lib =>
             MDLL.Build_Import_Library
               (To_String (Lib_Filename),
@@ -518,32 +543,43 @@ begin
                To_String (Lib_Filename),
                To_String (Def_Filename),
                To_String (DLL_Address),
-               Build_Import,
-               Must_Build_Relocatable);
+               Build_Import => True,
+               Relocatable  => Must_Build_Relocatable,
+               Map_File     => Gen_Map_File);
+
+         when Dynamic_Lib_Only =>
+            MDLL.Build_Dynamic_Library
+              (Objects_Files.all,
+               Ali_Files.all,
+               Options.all,
+               Bargs_Options.all,
+               Largs_Options.all,
+               To_String (Lib_Filename),
+               To_String (Def_Filename),
+               To_String (DLL_Address),
+               Build_Import => False,
+               Relocatable  => Must_Build_Relocatable,
+               Map_File     => Gen_Map_File);
 
          when Nil =>
             null;
-
       end case;
-
    end if;
 
-   Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Success);
+   Set_Exit_Status (Success);
 
 exception
-
    when SE : Syntax_Error =>
-      Text_IO.Put_Line ("Syntax error : " & Exceptions.Exception_Message (SE));
-      Text_IO.New_Line;
+      Put_Line ("Syntax error : " & Exception_Message (SE));
+      New_Line;
       Syntax;
-      Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
+      Set_Exit_Status (Failure);
 
-   when E : Tools_Error | Context_Error =>
-      Text_IO.Put_Line (Exceptions.Exception_Message (E));
-      Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
+   when E : MDLL.Tools_Error | Context_Error =>
+      Put_Line (Exception_Message (E));
+      Set_Exit_Status (Failure);
 
    when others =>
-      Text_IO.Put_Line ("gnatdll: INTERNAL ERROR. Please report");
-      Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
-
+      Put_Line ("gnatdll: INTERNAL ERROR. Please report");
+      Set_Exit_Status (Failure);
 end Gnatdll;