2 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
3 Free Software Foundation, Inc.
4 Contributed by Douglas B. Rupp (rupp@gnat.com).
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING. If not, write to
20 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA. */
23 /* This program is a wrapper around the VMS linker.
24 It translates Unix style command line options into corresponding
25 VMS style qualifiers and then spawns the VMS linker. */
29 #include "coretypes.h"
32 typedef struct dsc
{unsigned short len
, mbz
; char *adr
; } Descr
;
35 #undef PATH_SEPARATOR_STR
36 #define PATH_SEPARATOR ','
37 #define PATH_SEPARATOR_STR ","
39 /* Local variable declarations. */
41 /* File specification for vms-dwarf2.o. */
42 static char *vmsdwarf2spec
= 0;
44 /* File specification for vms-dwarf2eh.o. */
45 static char *vmsdwarf2ehspec
= 0;
47 /* verbose = 1 if -v passed. */
48 static int verbose
= 0;
50 /* save_temps = 1 if -save-temps passed. */
51 static int save_temps
= 0;
53 /* By default don't generate executable file if there are errors
54 in the link. Override with --noinhibit-exec. */
55 static int inhibit_exec
= 1;
57 /* debug = 1 if -g passed. */
60 /* By default prefer to link with shareable image libraries.
61 Override with -static. */
62 static int staticp
= 0;
64 /* By default generate an executable, not a shareable image library.
65 Override with -shared. */
68 /* Remember if IDENTIFICATION given on command line. */
71 /* Keep track of arg translations. */
72 static int link_arg_max
= -1;
73 static const char **link_args
= 0;
74 static int link_arg_index
= -1;
76 /* Keep track of filenames */
77 static char optfilefullname
[267];
78 static char *sharefilename
= 0;
79 static char *exefilename
= 0;
81 /* System search dir list. Leave blank since link handles this
83 static char *system_search_dirs
= "";
85 /* Search dir list passed on command line (with -L). */
86 static char *search_dirs
;
88 /* Local function declarations. */
90 /* Add STR to the list of arguments to pass to the linker. Expand the list as
91 necessary to accommodate. */
92 static void addarg (const char *);
94 /* Check to see if NAME is a regular file, i.e. not a directory */
95 static int is_regular_file (char *);
97 /* Translate a Unix syntax file specification FILESPEC into VMS syntax.
98 If indicators of VMS syntax found, return input string. */
99 static char *to_host_file_spec (char *);
101 /* Locate the library named LIB_NAME in the set of paths PATH_VAL. */
102 static char *locate_lib (char *, char *);
104 /* Given a library name NAME, i.e. foo, Look for libfoo.lib and then
105 libfoo.a in the set of directories we are allowed to search in. */
106 static const char *expand_lib (char *);
108 /* Preprocess the number of args P_ARGC in ARGV.
109 Look for special flags, etc. that must be handled first. */
110 static void preprocess_args (int *, char **);
112 /* Preprocess the number of args P_ARGC in ARGV. Look for
113 special flags, etc. that must be handled for the VMS linker. */
114 static void process_args (int *, char **);
116 /* Action routine called by decc$to_vms. NAME is a file name or
117 directory name. TYPE is unused. */
118 static int translate_unix (char *, int);
120 int main (int, char **);
123 addarg (const char *str
)
127 if (++link_arg_index
>= link_arg_max
)
129 const char **new_link_args
130 = (const char **) xcalloc (link_arg_max
+ 1000, sizeof (char *));
132 for (i
= 0; i
<= link_arg_max
; i
++)
133 new_link_args
[i
] = link_args
[i
];
138 link_arg_max
+= 1000;
139 link_args
= new_link_args
;
142 link_args
[link_arg_index
] = str
;
146 locate_lib (char *lib_name
, char *path_val
)
148 int lib_len
= strlen (lib_name
);
151 for (sptr
= path_val
; *sptr
; sptr
= eptr
)
155 while (*sptr
== PATH_SEPARATOR
)
158 eptr
= strchr (sptr
, PATH_SEPARATOR
);
160 eptr
= strchr (sptr
, 0);
162 buf
= alloca ((eptr
-sptr
) + lib_len
+ 4 + 2);
163 strncpy (buf
, sptr
, eptr
-sptr
);
166 strcat (buf
, lib_name
);
167 ptr
= strchr (buf
, 0);
169 if (debug
|| staticp
)
171 /* For debug or static links, look for shareable image libraries
174 if (is_regular_file (buf
))
175 return xstrdup (to_host_file_spec (buf
));
177 strcpy (ptr
, ".olb");
178 if (is_regular_file (buf
))
179 return xstrdup (to_host_file_spec (buf
));
181 strcpy (ptr
, ".exe");
182 if (is_regular_file (buf
))
183 return xstrdup (to_host_file_spec (buf
));
187 /* Otherwise look for shareable image libraries first. */
188 strcpy (ptr
, ".exe");
189 if (is_regular_file (buf
))
190 return xstrdup (to_host_file_spec (buf
));
193 if (is_regular_file (buf
))
194 return xstrdup (to_host_file_spec (buf
));
196 strcpy (ptr
, ".olb");
197 if (is_regular_file (buf
))
198 return xstrdup (to_host_file_spec (buf
));
206 expand_lib (char *name
)
208 char *lib
, *lib_path
;
210 if (strcmp (name
, "c") == 0)
211 /* IEEE VAX C compatible library for non-prefixed (e.g. no DECC$)
213 return "sys$library:vaxcrtltx.olb";
215 else if (strcmp (name
, "m") == 0)
216 /* No separate library for math functions */
221 lib
= xmalloc (strlen (name
) + 14);
225 lib_path
= locate_lib (lib
, search_dirs
);
232 "Couldn't locate library: lib%s.exe, lib%s.a or lib%s.olb\n",
239 is_regular_file (char *name
)
244 ret
= stat (name
, &statbuf
);
245 return !ret
&& S_ISREG (statbuf
.st_mode
);
249 preprocess_args (int *p_argc
, char **argv
)
253 for (i
= 1; i
< *p_argc
; i
++)
254 if (strlen (argv
[i
]) >= 6 && strncmp (argv
[i
], "-shared", 7) == 0)
257 for (i
= 1; i
< *p_argc
; i
++)
258 if (strcmp (argv
[i
], "-o") == 0)
265 ptr
= to_host_file_spec (argv
[i
]);
266 exefilename
= xstrdup (ptr
);
267 out_len
= strlen (ptr
);
268 buff
= xmalloc (out_len
+ 18);
271 strcpy (buff
, "/share=");
273 strcpy (buff
, "/exe=");
280 sharefilename
= xmalloc (out_len
+5);
281 if (ptr
== strchr (argv
[i
], ']'))
282 strcpy (sharefilename
, ++ptr
);
283 else if (ptr
== strchr (argv
[i
], ':'))
284 strcpy (sharefilename
, ++ptr
);
285 else if (ptr
== strrchr (argv
[i
], '/'))
286 strcpy (sharefilename
, ++ptr
);
288 strcpy (sharefilename
, argv
[i
]);
290 len
= strlen (sharefilename
);
291 if (strncasecmp (&sharefilename
[len
-4], ".exe", 4) == 0)
292 sharefilename
[len
-4] = 0;
294 for (ptr
= sharefilename
; *ptr
; ptr
++)
295 *ptr
= TOUPPER (*ptr
);
301 process_args (int *p_argc
, char **argv
)
305 for (i
= 1; i
< *p_argc
; i
++)
307 if (strlen (argv
[i
]) < 2)
310 if (strncmp (argv
[i
], "-L", 2) == 0)
313 int new_len
, search_dirs_len
;
316 new_len
= strlen (ptr
);
317 search_dirs_len
= strlen (search_dirs
);
319 nbuff
= xmalloc (new_len
+ 1);
322 /* Remove trailing slashes. */
323 while (new_len
> 1 && nbuff
[new_len
- 1] == '/')
325 nbuff
[new_len
- 1] = 0;
329 search_dirs
= xrealloc (search_dirs
, search_dirs_len
+ new_len
+ 2);
330 if (search_dirs_len
> 0)
331 strcat (search_dirs
, PATH_SEPARATOR_STR
);
333 strcat (search_dirs
, nbuff
);
337 /* -v turns on verbose option here and is passed on to gcc. */
338 else if (strcmp (argv
[i
], "-v") == 0)
340 else if (strcmp (argv
[i
], "-g0") == 0)
341 addarg ("/notraceback");
342 else if (strncmp (argv
[i
], "-g", 2) == 0)
347 else if (strcmp (argv
[i
], "-static") == 0)
349 else if (strcmp (argv
[i
], "-map") == 0)
353 buff
= xmalloc (strlen (exefilename
) + 5);
354 strcpy (buff
, exefilename
);
355 ptr
= strchr (buff
, '.');
359 strcat (buff
, ".map");
364 else if (strcmp (argv
[i
], "-save-temps") == 0)
366 else if (strcmp (argv
[i
], "--noinhibit-exec") == 0)
371 /* The main program. Spawn the VMS linker after fixing up the Unix-like flags
372 and args to be what the VMS linker wants. */
375 main (int argc
, char **argv
)
378 char cwdev
[128], *devptr
;
382 char *cwd
= getcwd (0, 1024);
385 devptr
= strchr (cwd
, ':');
386 devlen
= (devptr
- cwd
) + 1;
387 strncpy (cwdev
, cwd
, devlen
);
388 cwdev
[devlen
] = '\0';
390 search_dirs
= xstrdup (system_search_dirs
);
394 /* Pass to find args that have to be append first. */
395 preprocess_args (&argc
, argv
);
397 /* Pass to find the rest of the args. */
398 process_args (&argc
, argv
);
400 /* Create a temp file to hold args, otherwise we can easily exceed the VMS
401 command line length limits. */
402 optfilename
= alloca (strlen ("LDXXXXXX") + 1);
403 strcpy (optfilename
, "LDXXXXXX");
404 optfd
= mkstemp (optfilename
);
405 getcwd (optfilefullname
, 256, 1); /* VMS style cwd. */
406 strcat (optfilefullname
, optfilename
);
407 strcat (optfilefullname
, ".");
408 optfile
= fdopen (optfd
, "w");
410 /* Write out the IDENTIFICATION argument first so that it can be overridden
411 by an options file. */
412 for (i
= 1; i
< argc
; i
++)
414 int arg_len
= strlen (argv
[i
]);
416 if (arg_len
> 6 && strncasecmp (argv
[i
], "IDENT=", 6) == 0)
418 /* Comes from command line. If present will always appear before
419 IDENTIFICATION=... and will override. */
424 else if (arg_len
> 15
425 && strncasecmp (argv
[i
], "IDENTIFICATION=", 15) == 0)
427 /* Comes from pragma Ident (). */
431 fprintf (optfile
, "case_sensitive=yes\n");
432 fprintf (optfile
, "IDENTIFICATION=\"%15.15s\"\n", &argv
[i
][15]);
433 fprintf (optfile
, "case_sensitive=NO\n");
439 for (i
= 1; i
< argc
; i
++)
441 int arg_len
= strlen (argv
[i
]);
443 if (strcmp (argv
[i
], "-o") == 0)
445 else if (arg_len
> 2 && strncmp (argv
[i
], "-l", 2) == 0)
447 const char *libname
= expand_lib (&argv
[i
][2]);
451 if ((len
= strlen (libname
)) > 0)
455 if (len
> 4 && strcasecmp (&libname
[len
-4], ".exe") == 0)
460 if (libname
[0] == '[')
461 sprintf (buff
, "%s%s", cwdev
, libname
);
463 sprintf (buff
, "%s", libname
);
465 fprintf (optfile
, "%s%s\n", buff
, ext
);
469 else if (strcmp (argv
[i
], "-v" ) == 0
470 || strncmp (argv
[i
], "-g", 2 ) == 0
471 || strcmp (argv
[i
], "-static" ) == 0
472 || strcmp (argv
[i
], "-map" ) == 0
473 || strcmp (argv
[i
], "-save-temps") == 0
474 || strcmp (argv
[i
], "--noinhibit-exec") == 0
475 || (arg_len
> 2 && strncmp (argv
[i
], "-L", 2) == 0)
476 || (arg_len
>= 6 && strncmp (argv
[i
], "-share", 6) == 0))
478 else if (arg_len
> 1 && argv
[i
][0] == '@')
486 if (stat (&argv
[i
][1], &statbuf
))
488 fprintf (stderr
, "Couldn't open linker response file: %s\n",
493 buff
= xmalloc (statbuf
.st_size
+ 1);
494 atfile
= fopen (&argv
[i
][1], "r");
495 fgets (buff
, statbuf
.st_size
+ 1, atfile
);
499 if (buff
[len
- 1] == '\n')
509 ptr1
= strchr (ptr
, ' ');
512 ptr
= to_host_file_spec (ptr
);
514 fprintf (optfile
, "%s%s\n", cwdev
, ptr
);
516 fprintf (optfile
, "%s\n", ptr
);
521 /* Unix style file specs and VMS style switches look alike, so assume an
522 arg consisting of one and only one slash, and that being first, is
524 else if ((argv
[i
][0] == '/') && (strchr (&argv
[i
][1], '/') == 0))
527 && strncasecmp (&argv
[i
][arg_len
-4], ".OPT", 4) == 0)
532 optfile1
= fopen (argv
[i
], "r");
533 while (fgets (buff
, 256, optfile1
))
534 fputs (buff
, optfile
);
538 else if (arg_len
> 7 && strncasecmp (argv
[i
], "GSMATCH", 7) == 0)
539 fprintf (optfile
, "%s\n", argv
[i
]);
540 else if (arg_len
> 6 && strncasecmp (argv
[i
], "IDENT=", 6) == 0)
542 /* Comes from command line and will override pragma. */
543 fprintf (optfile
, "case_sensitive=yes\n");
544 fprintf (optfile
, "IDENT=\"%15.15s\"\n", &argv
[i
][6]);
545 fprintf (optfile
, "case_sensitive=NO\n");
548 else if (arg_len
> 15
549 && strncasecmp (argv
[i
], "IDENTIFICATION=", 15) == 0)
553 /* Assume filename arg. */
554 const char *addswitch
= "";
559 argv
[i
] = to_host_file_spec (argv
[i
]);
560 arg_len
= strlen (argv
[i
]);
562 if (arg_len
> 4 && strcasecmp (&argv
[i
][arg_len
-4], ".exe") == 0)
563 addswitch
= "/shareable";
565 if (arg_len
> 4 && strcasecmp (&argv
[i
][arg_len
-4], ".cld") == 0)
567 addswitch
= "/shareable";
571 if (arg_len
> 2 && strcasecmp (&argv
[i
][arg_len
-2], ".a") == 0)
574 if (arg_len
> 4 && strcasecmp (&argv
[i
][arg_len
-4], ".olb") == 0)
577 if (argv
[i
][0] == '[')
578 sprintf (buff
, "%s%s%s\n", cwdev
, argv
[i
], addswitch
);
579 else if (strchr (argv
[i
], ':'))
580 sprintf (buff
, "%s%s\n", argv
[i
], addswitch
);
582 sprintf (buff
, "%s%s%s\n", cwd
, argv
[i
], addswitch
);
584 buff_len
= strlen (buff
);
587 && strcasecmp (&buff
[buff_len
- 15], "vms-dwarf2eh.o\n") == 0)
588 vmsdwarf2ehspec
= xstrdup (buff
);
589 else if (buff_len
>= 13
590 && strcasecmp (&buff
[buff_len
- 13],"vms-dwarf2.o\n") == 0)
591 vmsdwarf2spec
= xstrdup (buff
);
598 fprintf (optfile
, buff
);
604 fprintf (optfile
, "symbol_vector=(main=procedure)\n");
609 fprintf (optfile
, "case_sensitive=yes\n");
610 fprintf (optfile
, "cluster=DWARF2eh,,,%s", vmsdwarf2ehspec
);
611 fprintf (optfile
, "collect=DWARF2eh,eh_frame\n");
612 fprintf (optfile
, "case_sensitive=NO\n");
615 if (debug
&& vmsdwarf2spec
)
617 fprintf (optfile
, "case_sensitive=yes\n");
618 fprintf (optfile
, "cluster=DWARF2debug,,,%s", vmsdwarf2spec
);
619 fprintf (optfile
, "collect=DWARF2debug,debug_abbrev,debug_aranges,-\n");
620 fprintf (optfile
, " debug_frame,debug_info,debug_line,debug_loc,-\n");
621 fprintf (optfile
, " debug_macinfo,debug_pubnames,debug_str,-\n");
622 fprintf (optfile
, " debug_zzzzzz\n");
623 fprintf (optfile
, "case_sensitive=NO\n");
628 fprintf (optfile
, "case_sensitive=yes\n");
629 fprintf (optfile
, "symbol_vector=(-\n");
631 "%s$DWARF2.DEBUG_ABBREV/$dwarf2.debug_abbrev=DATA,-\n",
634 "%s$DWARF2.DEBUG_ARANGES/$dwarf2.debug_aranges=DATA,-\n",
636 fprintf (optfile
, "%s$DWARF2.DEBUG_FRAME/$dwarf2.debug_frame=DATA,-\n",
638 fprintf (optfile
, "%s$DWARF2.DEBUG_INFO/$dwarf2.debug_info=DATA,-\n",
640 fprintf (optfile
, "%s$DWARF2.DEBUG_LINE/$dwarf2.debug_line=DATA,-\n",
642 fprintf (optfile
, "%s$DWARF2.DEBUG_LOC/$dwarf2.debug_loc=DATA,-\n",
645 "%s$DWARF2.DEBUG_MACINFO/$dwarf2.debug_macinfo=DATA,-\n",
648 "%s$DWARF2.DEBUG_PUBNAMES/$dwarf2.debug_pubnames=DATA,-\n",
650 fprintf (optfile
, "%s$DWARF2.DEBUG_STR/$dwarf2.debug_str=DATA,-\n",
652 fprintf (optfile
, "%s$DWARF2.DEBUG_ZZZZZZ/$dwarf2.debug_zzzzzz=DATA)\n",
654 fprintf (optfile
, "case_sensitive=NO\n");
658 addarg (optfilefullname
);
667 for (i
= 0; i
< link_arg_index
; i
++)
668 printf ("%s ", link_args
[i
]);
676 for (i
= 0; link_args
[i
]; i
++)
677 len
= len
+ strlen (link_args
[i
]) + 1;
680 char *allargs
= (char *) alloca (len
+ 1);
685 for (i
= 0; i
< len
+ 1; i
++)
688 for (i
= 0; link_args
[i
]; i
++)
690 strcat (allargs
, link_args
[i
]);
691 strcat (allargs
, " ");
698 i
= LIB$
SPAWN (&cmd
, 0, 0, 0, 0, 0, &status
);
707 strcpy (allargs
, "@gnu:[bin]set_exe ");
708 strcat (allargs
, exefilename
);
709 strcat (allargs
, " /nodebug /silent");
710 len
= strlen (allargs
);
718 i
= LIB$
SPAWN (&cmd
, 0, 0, 0, 0, 0, &status1
);
728 remove (optfilefullname
);
730 if ((status
& 1) == 1 && (status1
& 1) == 1)
733 if (exefilename
&& inhibit_exec
== 1)
734 remove (exefilename
);
741 static char new_host_filespec
[255];
742 static char filename_buff
[256];
745 translate_unix (char *name
, int type ATTRIBUTE_UNUSED
)
747 strcpy (filename_buff
, name
);
752 to_host_file_spec (char *filespec
)
754 strcpy (new_host_filespec
, "");
755 if (strchr (filespec
, ']') || strchr (filespec
, ':'))
756 strcpy (new_host_filespec
, filespec
);
759 decc$
to_vms (filespec
, translate_unix
, 1, 1);
760 strcpy (new_host_filespec
, filename_buff
);
763 return new_host_filespec
;