FSF GCC merge 02/23/03
[official-gcc.git] / gcc / ada / gnatdll.adb
blob5dc81541e636818137a26c8e96cea7b0556c7f0b
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT COMPILER COMPONENTS --
4 -- --
5 -- G N A T D L L --
6 -- --
7 -- B o d y --
8 -- --
9 -- --
10 -- Copyright (C) 1997-2002, Free Software Foundation, Inc. --
11 -- --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
21 -- MA 02111-1307, USA. --
22 -- --
23 -- GNAT was originally developed by the GNAT team at New York University. --
24 -- Extensive contributions were provided by Ada Core Technologies Inc. --
25 -- --
26 ------------------------------------------------------------------------------
28 -- GNATDLL is a Windows specific tool for building a DLL.
29 -- Both relocatable and non-relocatable DLL's are supported
31 with Ada.Text_IO;
32 with Ada.Strings.Unbounded;
33 with Ada.Exceptions;
34 with Ada.Command_Line;
35 with GNAT.OS_Lib;
36 with GNAT.Command_Line;
37 with Gnatvsn;
39 with MDLL.Fil;
40 with MDLL.Utl;
42 procedure Gnatdll is
44 use GNAT;
45 use Ada;
46 use MDLL;
47 use Ada.Strings.Unbounded;
49 use type OS_Lib.Argument_List;
51 procedure Syntax;
52 -- Print out usage
54 procedure Check (Filename : String);
55 -- Check that the file whose name is Filename exists
57 procedure Parse_Command_Line;
58 -- Parse the command line arguments passed to gnatdll
60 procedure Check_Context;
61 -- Check the context before runing any commands to build the library
63 Syntax_Error : exception;
64 -- Raised when a syntax error is detected, in this case a usage info will
65 -- be displayed.
67 Context_Error : exception;
68 -- Raised when some files (specifed on the command line) are missing to
69 -- build the DLL.
71 Help : Boolean := False;
72 -- Help will be set to True the usage information is to be displayed.
74 Version : constant String := Gnatvsn.Gnat_Version_String;
75 -- Why should it be necessary to make a copy of this
77 Default_DLL_Address : constant String := "0x11000000";
78 -- Default address for non relocatable DLL (Win32)
80 Lib_Filename : Unbounded_String := Null_Unbounded_String;
81 -- The DLL filename that will be created (.dll)
83 Def_Filename : Unbounded_String := Null_Unbounded_String;
84 -- The definition filename (.def)
86 List_Filename : Unbounded_String := Null_Unbounded_String;
87 -- The name of the file containing the objects file to put into the DLL
89 DLL_Address : Unbounded_String :=
90 To_Unbounded_String (Default_DLL_Address);
91 -- The DLL's base address
93 Objects_Files : Argument_List_Access := Null_Argument_List_Access;
94 -- List of objects to put inside the library
96 Ali_Files : Argument_List_Access := Null_Argument_List_Access;
97 -- For each Ada file specified, we keep arecord of the corresponding
98 -- ALI file. This list of SLI files is used to build the binder program.
100 Options : Argument_List_Access := Null_Argument_List_Access;
101 -- A list of options set in the command line.
103 Largs_Options : Argument_List_Access := Null_Argument_List_Access;
104 Bargs_Options : Argument_List_Access := Null_Argument_List_Access;
105 -- GNAT linker and binder args options
107 type Build_Mode_State is (Import_Lib, Dynamic_Lib, Dynamic_Lib_Only, Nil);
108 -- Import_Lib means only the .a file will be created, Dynamic_Lib means
109 -- that both the DLL and the import library will be created.
110 -- Dynamic_Lib_Only means that only the DLL will be created (no import
111 -- library).
113 Build_Mode : Build_Mode_State := Nil;
114 -- Will be set when parsing the command line.
116 Must_Build_Relocatable : Boolean := True;
117 -- True means build a relocatable DLL, will be set to False if a
118 -- non-relocatable DLL must be built.
120 ------------
121 -- Syntax --
122 ------------
124 procedure Syntax is
125 use Text_IO;
127 procedure P (Str : in String) renames Text_IO.Put_Line;
129 begin
130 P ("Usage : gnatdll [options] [list-of-files]");
131 New_Line;
132 P ("[list-of-files] a list of Ada libraries (.ali) and/or " &
133 "foreign object files");
134 New_Line;
135 P ("[options] can be");
136 P (" -h Help - display this message");
137 P (" -v Verbose");
138 P (" -q Quiet");
139 P (" -k Remove @nn suffix from exported names");
140 P (" -g Generate debugging information");
141 P (" -Idir Specify source and object files search path");
142 P (" -l file File contains a list-of-files to be added to "
143 & "the library");
144 P (" -e file Definition file containing exports");
145 P (" -d file Put objects in the relocatable dynamic "
146 & "library <file>");
147 P (" -b addr Set base address for the relocatable DLL");
148 P (" default address is " & Default_DLL_Address);
149 P (" -a[addr] Build non-relocatable DLL at address <addr>");
150 P (" if <addr> is not specified use "
151 & Default_DLL_Address);
152 P (" -n No-import - do not create the import library");
153 P (" -bargs opts opts are passed to the binder");
154 P (" -largs opts opts are passed to the linker");
155 end Syntax;
157 -----------
158 -- Check --
159 -----------
161 procedure Check (Filename : in String) is
162 begin
163 if not OS_Lib.Is_Regular_File (Filename) then
164 Exceptions.Raise_Exception (Context_Error'Identity,
165 "Error: " & Filename & " not found.");
166 end if;
167 end Check;
169 ------------------------
170 -- Parse_Command_Line --
171 ------------------------
173 procedure Parse_Command_Line is
175 use GNAT.Command_Line;
177 procedure Add_File (Filename : in String);
178 -- Add one file to the list of file to handle
180 procedure Add_Files_From_List (List_Filename : in String);
181 -- Add the files listed in List_Filename (one by line) to the list
182 -- of file to handle
184 Max_Files : constant := 5_000;
185 Max_Options : constant := 100;
186 -- These are arbitrary limits, a better way will be to use linked list.
187 -- No, a better choice would be to use tables ???
188 -- Limits on what???
190 Ofiles : OS_Lib.Argument_List (1 .. Max_Files);
191 O : Positive := Ofiles'First;
192 -- List of object files to put in the library. O is the next entry
193 -- to be used.
195 Afiles : OS_Lib.Argument_List (1 .. Max_Files);
196 A : Positive := Afiles'First;
197 -- List of ALI files. A is the next entry to be used.
199 Gopts : OS_Lib.Argument_List (1 .. Max_Options);
200 G : Positive := Gopts'First;
201 -- List of gcc options. G is the next entry to be used.
203 Lopts : OS_Lib.Argument_List (1 .. Max_Options);
204 L : Positive := Lopts'First;
205 -- A list of -largs options (L is next entry to be used)
207 Bopts : OS_Lib.Argument_List (1 .. Max_Options);
208 B : Positive := Bopts'First;
209 -- A list of -bargs options (B is next entry to be used)
211 Build_Import : Boolean := True;
212 -- Set to Fals if option -n if specified (no-import).
214 --------------
215 -- Add_File --
216 --------------
218 procedure Add_File (Filename : in String) is
219 begin
220 if Fil.Is_Ali (Filename) then
222 Check (Filename);
224 -- Record it to generate the binder program when
225 -- building dynamic library
227 Afiles (A) := new String'(Filename);
228 A := A + 1;
230 elsif Fil.Is_Obj (Filename) then
232 Check (Filename);
234 -- Just record this object file
236 Ofiles (O) := new String'(Filename);
237 O := O + 1;
239 else
240 -- Unknown file type
242 Exceptions.Raise_Exception
243 (Syntax_Error'Identity,
244 "don't know what to do with " & Filename & " !");
245 end if;
246 end Add_File;
248 -------------------------
249 -- Add_Files_From_List --
250 -------------------------
252 procedure Add_Files_From_List (List_Filename : in String) is
253 File : Text_IO.File_Type;
254 Buffer : String (1 .. 500);
255 Last : Natural;
257 begin
258 Text_IO.Open (File, Text_IO.In_File, List_Filename);
260 while not Text_IO.End_Of_File (File) loop
261 Text_IO.Get_Line (File, Buffer, Last);
262 Add_File (Buffer (1 .. Last));
263 end loop;
265 Text_IO.Close (File);
266 end Add_Files_From_List;
268 -- Start of processing for Parse_Command_Line
270 begin
271 Initialize_Option_Scan ('-', False, "bargs largs");
273 -- scan gnatdll switches
275 loop
276 case Getopt ("g h v q k a? b: d: e: l: n I:") is
278 when ASCII.Nul =>
279 exit;
281 when 'h' =>
282 Help := True;
284 when 'g' =>
285 Gopts (G) := new String'("-g");
286 G := G + 1;
288 when 'v' =>
290 -- Turn verbose mode on
292 MDLL.Verbose := True;
293 if MDLL.Quiet then
294 Exceptions.Raise_Exception
295 (Syntax_Error'Identity,
296 "impossible to use -q and -v together.");
297 end if;
299 when 'q' =>
301 -- Turn quiet mode on
303 MDLL.Quiet := True;
304 if MDLL.Verbose then
305 Exceptions.Raise_Exception
306 (Syntax_Error'Identity,
307 "impossible to use -v and -q together.");
308 end if;
310 when 'k' =>
312 MDLL.Kill_Suffix := True;
314 when 'a' =>
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);
323 else
324 DLL_Address := To_Unbounded_String (Parameter);
325 end if;
327 Must_Build_Relocatable := False;
329 when 'b' =>
331 DLL_Address := To_Unbounded_String (Parameter);
333 Must_Build_Relocatable := True;
335 when 'e' =>
337 Def_Filename := To_Unbounded_String (Parameter);
339 when 'd' =>
341 -- Build a non relocatable DLL
343 Lib_Filename := To_Unbounded_String (Parameter);
345 if Def_Filename = Null_Unbounded_String then
346 Def_Filename := To_Unbounded_String
347 (Fil.Ext_To (Parameter, "def"));
348 end if;
350 Build_Mode := Dynamic_Lib;
352 when 'n' =>
354 Build_Import := False;
356 when 'l' =>
357 List_Filename := To_Unbounded_String (Parameter);
359 when 'I' =>
360 Gopts (G) := new String'("-I" & Parameter);
361 G := G + 1;
363 when others =>
364 raise Invalid_Switch;
366 end case;
367 end loop;
369 -- Get parameters
371 loop
372 declare
373 File : constant String := Get_Argument (Do_Expansion => True);
374 begin
375 exit when File'Length = 0;
376 Add_File (File);
377 end;
378 end loop;
380 -- Get largs parameters
382 Goto_Section ("largs");
384 loop
385 case Getopt ("*") is
387 when ASCII.Nul =>
388 exit;
390 when others =>
391 Lopts (L) := new String'(Full_Switch);
392 L := L + 1;
394 end case;
395 end loop;
397 -- Get bargs parameters
399 Goto_Section ("bargs");
401 loop
402 case Getopt ("*") is
404 when ASCII.Nul =>
405 exit;
407 when others =>
408 Bopts (B) := new String'(Full_Switch);
409 B := B + 1;
411 end case;
412 end loop;
414 -- if list filename has been specified, parse it
416 if List_Filename /= Null_Unbounded_String then
417 Add_Files_From_List (To_String (List_Filename));
418 end if;
420 -- Check if the set of parameters are compatible.
422 if Build_Mode = Nil and then not Help and then not Verbose then
423 Exceptions.Raise_Exception
424 (Syntax_Error'Identity,
425 "nothing to do.");
426 end if;
428 -- -n option but no file specified
430 if not Build_Import
431 and then A = Afiles'First
432 and then O = Ofiles'First
433 then
434 Exceptions.Raise_Exception
435 (Syntax_Error'Identity,
436 "-n specified but there are no objects to build the library.");
437 end if;
439 -- Check if we want to build an import library (option -e and
440 -- no file specified)
442 if Build_Mode = Dynamic_Lib
443 and then A = Afiles'First
444 and then O = Ofiles'First
445 then
446 Build_Mode := Import_Lib;
447 end if;
449 -- Check if only a dynamic library must be built.
451 if Build_Mode = Dynamic_Lib and then not Build_Import then
452 Build_Mode := Dynamic_Lib_Only;
453 end if;
455 if O /= Ofiles'First then
456 Objects_Files := new OS_Lib.Argument_List'(Ofiles (1 .. O - 1));
457 end if;
459 if A /= Afiles'First then
460 Ali_Files := new OS_Lib.Argument_List'(Afiles (1 .. A - 1));
461 end if;
463 if G /= Gopts'First then
464 Options := new OS_Lib.Argument_List'(Gopts (1 .. G - 1));
465 end if;
467 if L /= Lopts'First then
468 Largs_Options := new OS_Lib.Argument_List'(Lopts (1 .. L - 1));
469 end if;
471 if B /= Bopts'First then
472 Bargs_Options := new OS_Lib.Argument_List'(Bopts (1 .. B - 1));
473 end if;
475 exception
477 when Invalid_Switch =>
478 Exceptions.Raise_Exception
479 (Syntax_Error'Identity,
480 Message => "Invalid Switch " & Full_Switch);
482 when Invalid_Parameter =>
483 Exceptions.Raise_Exception
484 (Syntax_Error'Identity,
485 Message => "No parameter for " & Full_Switch);
487 end Parse_Command_Line;
489 -------------------
490 -- Check_Context --
491 -------------------
493 procedure Check_Context is
494 begin
496 Check (To_String (Def_Filename));
498 -- Check that each object file specified exists and raise exception
499 -- Context_Error if it does not.
501 for F in Objects_Files'Range loop
502 Check (Objects_Files (F).all);
503 end loop;
504 end Check_Context;
506 -- Start of processing for Gnatdll
508 begin
509 if Ada.Command_Line.Argument_Count = 0 then
510 Help := True;
511 else
512 Parse_Command_Line;
513 end if;
515 if MDLL.Verbose or else Help then
516 Text_IO.New_Line;
517 Text_IO.Put_Line ("GNATDLL " & Version & " - Dynamic Libraries Builder");
518 Text_IO.New_Line;
519 end if;
521 MDLL.Utl.Locate;
523 if Help
524 or else (MDLL.Verbose and then Ada.Command_Line.Argument_Count = 1)
525 then
526 Syntax;
527 else
528 Check_Context;
530 case Build_Mode is
532 when Import_Lib =>
533 MDLL.Build_Import_Library
534 (To_String (Lib_Filename),
535 To_String (Def_Filename));
537 when Dynamic_Lib =>
538 MDLL.Build_Dynamic_Library
539 (Objects_Files.all,
540 Ali_Files.all,
541 Options.all,
542 Bargs_Options.all,
543 Largs_Options.all,
544 To_String (Lib_Filename),
545 To_String (Def_Filename),
546 To_String (DLL_Address),
547 Build_Import => True,
548 Relocatable => Must_Build_Relocatable);
550 when Dynamic_Lib_Only =>
551 MDLL.Build_Dynamic_Library
552 (Objects_Files.all,
553 Ali_Files.all,
554 Options.all,
555 Bargs_Options.all,
556 Largs_Options.all,
557 To_String (Lib_Filename),
558 To_String (Def_Filename),
559 To_String (DLL_Address),
560 Build_Import => False,
561 Relocatable => Must_Build_Relocatable);
563 when Nil =>
564 null;
566 end case;
568 end if;
570 Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Success);
572 exception
574 when SE : Syntax_Error =>
575 Text_IO.Put_Line ("Syntax error : " & Exceptions.Exception_Message (SE));
576 Text_IO.New_Line;
577 Syntax;
578 Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
580 when E : Tools_Error | Context_Error =>
581 Text_IO.Put_Line (Exceptions.Exception_Message (E));
582 Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
584 when others =>
585 Text_IO.Put_Line ("gnatdll: INTERNAL ERROR. Please report");
586 Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
588 end Gnatdll;