1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
11 -- Copyright (C) 1997-2001, Free Software Foundation, Inc. --
13 -- GNAT is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 2, or (at your option) any later ver- --
16 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
19 -- for more details. You should have received a copy of the GNU General --
20 -- Public License distributed with GNAT; see file COPYING. If not, write --
21 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
22 -- MA 02111-1307, USA. --
24 -- GNAT was originally developed by the GNAT team at New York University. --
25 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
27 ------------------------------------------------------------------------------
29 -- GNATDLL is a Windows specific tool for building a DLL.
30 -- Both relocatable and non-relocatable DLL's are supported
33 with Ada
.Strings
.Unbounded
;
35 with Ada
.Command_Line
;
37 with GNAT
.Command_Line
;
48 use Ada
.Strings
.Unbounded
;
50 use type OS_Lib
.Argument_List
;
55 procedure Check
(Filename
: String);
56 -- Check that the file whose name is Filename exists
58 procedure Parse_Command_Line
;
59 -- Parse the command line arguments passed to gnatdll
61 procedure Check_Context
;
62 -- Check the context before runing any commands to build the library
64 Syntax_Error
: exception;
65 Context_Error
: exception;
66 -- What are these for ???
68 Help
: Boolean := False;
69 -- What is this for ???
71 Version
: constant String := Gnatvsn
.Gnat_Version_String
;
72 -- Why should it be necessary to make a copy of this
74 Default_DLL_Address
: constant String := "0x11000000";
75 -- Default address for non relocatable DLL (Win32)
77 Lib_Filename
: Unbounded_String
:= Null_Unbounded_String
;
78 Def_Filename
: Unbounded_String
:= Null_Unbounded_String
;
79 List_Filename
: Unbounded_String
:= Null_Unbounded_String
;
80 DLL_Address
: Unbounded_String
:=
81 To_Unbounded_String
(Default_DLL_Address
);
82 -- What are the above ???
84 Objects_Files
: Argument_List_Access
:= Null_Argument_List_Access
;
85 -- List of objects to put inside the library
87 Ali_Files
: Argument_List_Access
:= Null_Argument_List_Access
;
88 -- For each Ada file specified, we keep arecord of the corresponding
89 -- ALI file. This list of SLI files is used to build the binder program.
91 Options
: Argument_List_Access
:= Null_Argument_List_Access
;
92 -- A list of options set in the command line.
94 Largs_Options
: Argument_List_Access
:= Null_Argument_List_Access
;
95 Bargs_Options
: Argument_List_Access
:= Null_Argument_List_Access
;
96 -- GNAT linker and binder args options
98 type Build_Mode_State
is (Import_Lib
, Dynamic_Lib
, Nil
);
99 -- Comments needed ???
101 Build_Mode
: Build_Mode_State
:= Nil
;
102 Must_Build_Relocatable
: Boolean := True;
103 Build_Import
: Boolean := True;
113 procedure P
(Str
: in String) renames Text_IO
.Put_Line
;
116 P
("Usage : gnatdll [options] [list-of-files]");
118 P
("[list-of-files] a list of Ada libraries (.ali) and/or " &
119 "foreign object files");
121 P
("[options] can be");
122 P
(" -h Help - display this message");
125 P
(" -k Remove @nn suffix from exported names");
126 P
(" -g Generate debugging information");
127 P
(" -Idir Specify source and object files search path");
128 P
(" -l file File contains a list-of-files to be added to "
130 P
(" -e file Definition file containing exports");
131 P
(" -d file Put objects in the relocatable dynamic "
133 P
(" -a[addr] Build non-relocatable DLL at address <addr>");
134 P
(" if <addr> is not specified use "
135 & Default_DLL_Address
);
136 P
(" -n No-import - do not create the import library");
137 P
(" -bargs opts opts are passed to the binder");
138 P
(" -largs opts opts are passed to the linker");
145 procedure Check
(Filename
: in String) is
147 if not OS_Lib
.Is_Regular_File
(Filename
) then
148 Exceptions
.Raise_Exception
(Context_Error
'Identity,
149 "Error: " & Filename
& " not found.");
153 ------------------------
154 -- Parse_Command_Line --
155 ------------------------
157 procedure Parse_Command_Line
is
159 use GNAT
.Command_Line
;
161 procedure Add_File
(Filename
: in String);
162 -- add one file to the list of file to handle
164 procedure Add_Files_From_List
(List_Filename
: in String);
165 -- add the files listed in List_Filename (one by line) to the list
168 procedure Ali_To_Object_List
;
169 -- for each ali file in Afiles set put a corresponding object file in
172 Max_Files
: constant := 5_000
;
173 Max_Options
: constant := 100;
174 -- These are arbitrary limits, a better way will be to use linked list.
175 -- No, a better choice would be to use tables ???
178 Ofiles
: OS_Lib
.Argument_List
(1 .. Max_Files
);
179 O
: Positive := Ofiles
'First;
180 -- List of object files to put in the library. O is the next entry
183 Afiles
: OS_Lib
.Argument_List
(1 .. Max_Files
);
184 A
: Positive := Afiles
'First;
185 -- List of ALI files. A is the next entry to be used.
187 Gopts
: OS_Lib
.Argument_List
(1 .. Max_Options
);
188 G
: Positive := Gopts
'First;
189 -- List of gcc options. G is the next entry to be used.
191 Lopts
: OS_Lib
.Argument_List
(1 .. Max_Options
);
192 L
: Positive := Lopts
'First;
193 -- A list of -largs options (L is next entry to be used)
195 Bopts
: OS_Lib
.Argument_List
(1 .. Max_Options
);
196 B
: Positive := Bopts
'First;
197 -- A list of -bargs options (B is next entry to be used)
203 procedure Add_File
(Filename
: in String) is
205 -- others files are to be put inside the dynamic library
206 -- ??? this makes no sense, should it be "Other files ..."
208 if Files
.Is_Ali
(Filename
) then
212 -- Record it to generate the binder program when
213 -- building dynamic library
215 Afiles
(A
) := new String'(Filename);
218 elsif Files.Is_Obj (Filename) then
222 -- Just record this object file
224 Ofiles (O) := new String'(Filename
);
230 Exceptions
.Raise_Exception
231 (Syntax_Error
'Identity,
232 "don't know what to do with " & Filename
& " !");
236 -------------------------
237 -- Add_Files_From_List --
238 -------------------------
240 procedure Add_Files_From_List
(List_Filename
: in String) is
241 File
: Text_IO
.File_Type
;
242 Buffer
: String (1 .. 500);
246 Text_IO
.Open
(File
, Text_IO
.In_File
, List_Filename
);
248 while not Text_IO
.End_Of_File
(File
) loop
249 Text_IO
.Get_Line
(File
, Buffer
, Last
);
250 Add_File
(Buffer
(1 .. Last
));
253 Text_IO
.Close
(File
);
254 end Add_Files_From_List
;
256 ------------------------
257 -- Ali_To_Object_List --
258 ------------------------
260 procedure Ali_To_Object_List
is
262 for K
in 1 .. A
- 1 loop
263 Ofiles
(O
) := new String'(Files.Ext_To (Afiles (K).all, "o"));
266 end Ali_To_Object_List;
268 -- Start of processing for Parse_Command_Line
271 Initialize_Option_Scan ('-', False, "bargs largs");
273 -- scan gnatdll switches
276 case Getopt ("g h v q k a? d: e: l: n I:") is
285 Gopts (G) := new String'("-g");
290 -- Turn verbose mode on
292 MDLL
.Verbose
:= True;
294 Exceptions
.Raise_Exception
295 (Syntax_Error
'Identity,
296 "impossible to use -q and -v together.");
301 -- Turn quiet mode on
305 Exceptions
.Raise_Exception
306 (Syntax_Error
'Identity,
307 "impossible to use -v and -q together.");
312 MDLL
.Kill_Suffix
:= True;
316 if Parameter
= "" then
318 -- Default address for a relocatable dynamic library.
319 -- address for a non relocatable dynamic library.
321 DLL_Address
:= To_Unbounded_String
(Default_DLL_Address
);
324 DLL_Address
:= To_Unbounded_String
(Parameter
);
327 Must_Build_Relocatable
:= False;
331 Def_Filename
:= To_Unbounded_String
(Parameter
);
335 -- Build a non relocatable DLL
337 Lib_Filename
:= To_Unbounded_String
(Parameter
);
339 if Def_Filename
= Null_Unbounded_String
then
340 Def_Filename
:= To_Unbounded_String
341 (Files
.Ext_To
(Parameter
, "def"));
344 Build_Mode
:= Dynamic_Lib
;
348 Build_Import
:= False;
351 List_Filename
:= To_Unbounded_String
(Parameter
);
354 Gopts
(G
) := new String'("-I" & Parameter);
358 raise Invalid_Switch;
367 File : constant String := Get_Argument (Do_Expansion => True);
369 exit when File'Length = 0;
374 -- Get largs parameters
376 Goto_Section ("largs");
385 Lopts (L) := new String'(Full_Switch
);
391 -- Get bargs parameters
393 Goto_Section
("bargs");
402 Bopts
(B
) := new String'(Full_Switch);
408 -- if list filename has been specified, parse it
410 if List_Filename /= Null_Unbounded_String then
411 Add_Files_From_List (To_String (List_Filename));
414 -- Check if the set of parameters are compatible.
416 if Build_Mode = Nil and then not Help and then not Verbose then
417 Exceptions.Raise_Exception
418 (Syntax_Error'Identity,
422 -- Check if we want to build an import library (option -e and
423 -- no file specified)
425 if Build_Mode = Dynamic_Lib
426 and then A = Afiles'First
427 and then O = Ofiles'First
429 Build_Mode := Import_Lib;
432 if O /= Ofiles'First then
433 Objects_Files := new OS_Lib.Argument_List'(Ofiles
(1 .. O
- 1));
436 if A
/= Afiles
'First then
437 Ali_Files
:= new OS_Lib
.Argument_List
'(Afiles (1 .. A - 1));
440 if G /= Gopts'First then
441 Options := new OS_Lib.Argument_List'(Gopts
(1 .. G
- 1));
444 if L
/= Lopts
'First then
445 Largs_Options
:= new OS_Lib
.Argument_List
'(Lopts (1 .. L - 1));
448 if B /= Bopts'First then
449 Bargs_Options := new OS_Lib.Argument_List'(Bopts
(1 .. B
- 1));
454 when Invalid_Switch
=>
455 Exceptions
.Raise_Exception
456 (Syntax_Error
'Identity,
457 Message
=> "Invalid Switch " & Full_Switch
);
459 when Invalid_Parameter
=>
460 Exceptions
.Raise_Exception
461 (Syntax_Error
'Identity,
462 Message
=> "No parameter for " & Full_Switch
);
464 end Parse_Command_Line
;
470 procedure Check_Context
is
473 Check
(To_String
(Def_Filename
));
475 -- Check that each object file specified exists and raise exception
476 -- Context_Error if it does not.
478 for F
in Objects_Files
'Range loop
479 Check
(Objects_Files
(F
).all);
483 -- Start of processing for Gnatdll
486 if Ada
.Command_Line
.Argument_Count
= 0 then
492 if MDLL
.Verbose
or else Help
then
494 Text_IO
.Put_Line
("GNATDLL " & Version
& " - Dynamic Libraries Builder");
501 or else (MDLL
.Verbose
and then Ada
.Command_Line
.Argument_Count
= 1)
510 MDLL
.Build_Import_Library
511 (To_String
(Lib_Filename
),
512 To_String
(Def_Filename
));
515 MDLL
.Build_Dynamic_Library
521 To_String
(Lib_Filename
),
522 To_String
(Def_Filename
),
523 To_String
(DLL_Address
),
525 Must_Build_Relocatable
);
534 Ada
.Command_Line
.Set_Exit_Status
(Ada
.Command_Line
.Success
);
538 when SE
: Syntax_Error
=>
539 Text_IO
.Put_Line
("Syntax error : " & Exceptions
.Exception_Message
(SE
));
542 Ada
.Command_Line
.Set_Exit_Status
(Ada
.Command_Line
.Failure
);
544 when E
: Tools_Error | Context_Error
=>
545 Text_IO
.Put_Line
(Exceptions
.Exception_Message
(E
));
546 Ada
.Command_Line
.Set_Exit_Status
(Ada
.Command_Line
.Failure
);
549 Text_IO
.Put_Line
("gnatdll: INTERNAL ERROR. Please report");
550 Ada
.Command_Line
.Set_Exit_Status
(Ada
.Command_Line
.Failure
);