#include "ldgram.h"
#include "ldlex.h"
#include "ldfile.h"
+#include "ldver.h"
+
+/* Somewhere above, sys/stat.h got included . . . . */
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
/* Omit args to avoid the possibility of clashing with a system header
that might disagree about consts. */
int argc;
char **argv;
{
+ int ingroup = 0;
+
/* Starting the short option string with '-' is for programs that
expect options and other ARGV-elements in any order and that care about
the ordering of the two. We describe each non-option ARGV-element
as if it were the argument of an option with character code 1. */
- const char *shortopts = "-A:B::b:cde:F::G:giL:l:Mm:NnO:o:R:rSsT:tu:VvXxY:y:";
+ const char *shortopts =
+ "-A:B::b:cde:F::G:giL:l:Mm:NnO:o:R:rSsT:tu:VvXxY:y:()";
/* 150 isn't special; it's just an arbitrary non-ASCII char value. */
+#define OPTION_CALL_SHARED 150
+#define OPTION_DEFSYM (OPTION_CALL_SHARED + 1)
+#define OPTION_DYNAMIC_LINKER (OPTION_DEFSYM + 1)
+#define OPTION_EB (OPTION_DYNAMIC_LINKER + 1)
+#define OPTION_EL (OPTION_EB + 1)
+#define OPTION_HELP (OPTION_EL + 1)
+#define OPTION_IGNORE (OPTION_HELP + 1)
+#define OPTION_MAP (OPTION_IGNORE + 1)
+#define OPTION_NO_KEEP_MEMORY (OPTION_MAP + 1)
+#define OPTION_NOINHIBIT_EXEC (OPTION_NO_KEEP_MEMORY + 1)
+#define OPTION_NON_SHARED (OPTION_NOINHIBIT_EXEC + 1)
+#define OPTION_OFORMAT (OPTION_NON_SHARED + 1)
+#define OPTION_RELAX (OPTION_OFORMAT + 1)
+#define OPTION_RETAIN_SYMBOLS_FILE (OPTION_RELAX + 1)
+#define OPTION_RPATH (OPTION_RETAIN_SYMBOLS_FILE + 1)
+#define OPTION_SHARED (OPTION_RPATH + 1)
+#define OPTION_SONAME (OPTION_SHARED + 1)
+#define OPTION_SORT_COMMON (OPTION_SONAME + 1)
+#define OPTION_STATS (OPTION_SORT_COMMON + 1)
+#define OPTION_TBSS (OPTION_STATS + 1)
+#define OPTION_TDATA (OPTION_TBSS + 1)
+#define OPTION_TTEXT (OPTION_TDATA + 1)
+#define OPTION_TRADITIONAL_FORMAT (OPTION_TTEXT + 1)
+#define OPTION_UR (OPTION_TRADITIONAL_FORMAT + 1)
+#define OPTION_VERSION (OPTION_UR + 1)
+#define OPTION_WARN_COMMON (OPTION_VERSION + 1)
+#define OPTION_WARN_ONCE (OPTION_WARN_COMMON + 1)
+
static struct option longopts[] = {
-#define OPTION_CALL_SHARED 150
+ {"Bdynamic", no_argument, NULL, OPTION_CALL_SHARED},
+ {"Bstatic", no_argument, NULL, OPTION_NON_SHARED},
{"call_shared", no_argument, NULL, OPTION_CALL_SHARED},
{"dc", no_argument, NULL, 'd'},
-#define OPTION_DEFSYM 151
{"defsym", required_argument, NULL, OPTION_DEFSYM},
- {"dn", no_argument, NULL, OPTION_CALL_SHARED},
+ {"dll-verbose", no_argument, NULL, OPTION_VERSION}, /* Linux. */
+ {"dn", no_argument, NULL, OPTION_NON_SHARED},
{"dp", no_argument, NULL, 'd'},
-#define OPTION_EB 152
+ {"dy", no_argument, NULL, OPTION_CALL_SHARED},
+ {"dynamic-linker", required_argument, NULL, OPTION_DYNAMIC_LINKER},
{"EB", no_argument, NULL, OPTION_EB},
-#define OPTION_EL 153
{"EL", no_argument, NULL, OPTION_EL},
+ {"end-group", no_argument, NULL, ')'},
{"format", required_argument, NULL, 'b'},
-#define OPTION_HELP 154
{"help", no_argument, NULL, OPTION_HELP},
-#define OPTION_MAP 155
{"Map", required_argument, NULL, OPTION_MAP},
-#define OPTION_NO_KEEP_MEMORY 156
{"no-keep-memory", no_argument, NULL, OPTION_NO_KEEP_MEMORY},
-#define OPTION_NOINHIBIT_EXEC 157
{"noinhibit-exec", no_argument, NULL, OPTION_NOINHIBIT_EXEC},
{"noinhibit_exec", no_argument, NULL, OPTION_NOINHIBIT_EXEC},
- {"non_shared", no_argument, NULL, OPTION_CALL_SHARED},
-#define OPTION_OFORMAT 158
+ {"non_shared", no_argument, NULL, OPTION_NON_SHARED},
{"oformat", required_argument, NULL, OPTION_OFORMAT},
- {"Qy", no_argument, NULL, OPTION_CALL_SHARED},
-#define OPTION_RELAX 159
+ {"Qy", no_argument, NULL, OPTION_IGNORE},
+ {"qmagic", no_argument, NULL, OPTION_IGNORE}, /* Linux compatibility. */
{"relax", no_argument, NULL, OPTION_RELAX},
-#define OPTION_RETAIN_SYMBOLS_FILE 160
- {"retain-symbols-file", no_argument, NULL, OPTION_RETAIN_SYMBOLS_FILE},
-#define OPTION_SORT_COMMON 161
+ {"retain-symbols-file", required_argument, NULL, OPTION_RETAIN_SYMBOLS_FILE},
+ {"rpath", required_argument, NULL, OPTION_RPATH},
+ {"shared", no_argument, NULL, OPTION_SHARED},
+ {"soname", required_argument, NULL, OPTION_SONAME},
{"sort-common", no_argument, NULL, OPTION_SORT_COMMON},
{"sort_common", no_argument, NULL, OPTION_SORT_COMMON},
-#define OPTION_STATS 162
+ {"start-group", no_argument, NULL, '('},
{"stats", no_argument, NULL, OPTION_STATS},
-#define OPTION_TBSS 163
+ {"static", no_argument, NULL, OPTION_NON_SHARED},
{"Tbss", required_argument, NULL, OPTION_TBSS},
-#define OPTION_TDATA 164
{"Tdata", required_argument, NULL, OPTION_TDATA},
-#define OPTION_TTEXT 165
{"Ttext", required_argument, NULL, OPTION_TTEXT},
-#define OPTION_UR 166
+ {"traditional-format", no_argument, NULL, OPTION_TRADITIONAL_FORMAT},
{"Ur", no_argument, NULL, OPTION_UR},
-#define OPTION_VERSION 167
{"version", no_argument, NULL, OPTION_VERSION},
-#define OPTION_WARN_COMMON 168
{"warn-common", no_argument, NULL, OPTION_WARN_COMMON},
+ {"warn-once", no_argument, NULL, OPTION_WARN_ONCE},
{NULL, no_argument, NULL, 0}
};
(char *) NULL);
break;
+ case OPTION_IGNORE:
+ break;
case 'A':
ldfile_add_arch (optarg);
break;
- case 'B':
- /* Ignore. */
- break;
case 'b':
lang_add_target (optarg);
break;
yyparse ();
break;
case OPTION_CALL_SHARED:
- set_default_dirlist ((char *) longopts[longind].name);
+ config.dynamic_link = true;
+ break;
+ case OPTION_NON_SHARED:
+ config.dynamic_link = false;
break;
case 'd':
command_line.force_common_definition = true;
parser_input = input_defsym;
yyparse ();
break;
+ case OPTION_DYNAMIC_LINKER:
+ command_line.interpreter = optarg;
+ break;
case OPTION_EB:
- /* FIXME: This is currently ignored. It means
- ``produce a big-endian object file''. It could
- be used to select an output format. */
+ command_line.endian = ENDIAN_BIG;
break;
case OPTION_EL:
- /* FIXME: This is currently ignored. It means
- ``produce a little-endian object file''. It could
- be used to select an output format. */
+ command_line.endian = ENDIAN_LITTLE;
break;
case 'e':
- lang_add_entry (optarg);
+ lang_add_entry (optarg, 1);
break;
case 'F':
/* Ignore. */
char *end;
g_switch_value = strtoul (optarg, &end, 0);
if (*end)
- einfo ("%P%F: invalid number `%s'", optarg);
+ einfo ("%P%F: invalid number `%s'\n", optarg);
}
break;
case 'g':
xexit (0);
break;
case 'L':
- ldfile_add_library_path (optarg);
+ ldfile_add_library_path (optarg, true);
break;
case 'l':
lang_add_input_file (optarg, lang_input_file_is_l_enum,
/* Ignore. Was handled in a pre-parse. */
break;
case OPTION_MAP:
- write_map = true;
config.map_filename = optarg;
break;
case 'N':
lang_add_output (optarg, 0);
break;
case OPTION_OFORMAT:
- lang_add_output_format (optarg, 0);
+ lang_add_output_format (optarg, (char *) NULL, (char *) NULL, 0);
break;
+ case 'i':
case 'r':
link_info.relocateable = true;
config.build_constructors = false;
config.magic_demand_paged = false;
config.text_read_only = false;
+ config.dynamic_link = false;
break;
case 'R':
- lang_add_input_file (optarg,
- lang_input_file_is_symbols_only_enum,
- (char *) NULL);
+ /* The GNU linker traditionally uses -R to mean to include
+ only the symbols from a file. The Solaris linker uses -R
+ to set the path used by the runtime linker to find
+ libraries. This is the GNU linker -rpath argument. We
+ try to support both simultaneously by checking the file
+ named. If it is a directory, rather than a regular file,
+ we assume -rpath was meant. */
+ {
+ struct stat s;
+
+ if (stat (optarg, &s) >= 0
+ && ! S_ISDIR (s.st_mode))
+ {
+ lang_add_input_file (optarg,
+ lang_input_file_is_symbols_only_enum,
+ (char *) NULL);
+ break;
+ }
+ }
+ /* Fall through. */
+ case OPTION_RPATH:
+ if (command_line.rpath == NULL)
+ command_line.rpath = buystring (optarg);
+ else
+ {
+ char *buf;
+
+ buf = xmalloc (strlen (command_line.rpath)
+ + strlen (optarg)
+ + 2);
+ sprintf (buf, "%s:%s", command_line.rpath, optarg);
+ free (command_line.rpath);
+ command_line.rpath = buf;
+ }
break;
case OPTION_RELAX:
command_line.relax = true;
case 's':
link_info.strip = strip_all;
break;
+ case OPTION_SHARED:
+ link_info.shared = true;
+ break;
+ case OPTION_SONAME:
+ command_line.soname = optarg;
+ break;
case OPTION_SORT_COMMON:
config.sort_common = true;
break;
case OPTION_TTEXT:
set_section_start (".text", optarg);
break;
+ case OPTION_TRADITIONAL_FORMAT:
+ config.traditional_format = true;
+ break;
case OPTION_UR:
link_info.relocateable = true;
config.build_constructors = true;
config.magic_demand_paged = false;
config.text_read_only = false;
+ config.dynamic_link = false;
break;
case 'u':
ldlang_add_undef (optarg);
case OPTION_WARN_COMMON:
config.warn_common = true;
break;
+ case OPTION_WARN_ONCE:
+ config.warn_once = true;
+ break;
case 'X':
link_info.discard = discard_l;
break;
case 'y':
add_ysym (optarg);
break;
+ case '(':
+ if (ingroup)
+ {
+ fprintf (stderr,
+ "%s: may not nest groups (--help for usage)\n",
+ program_name);
+ xexit (1);
+ }
+ lang_enter_group ();
+ ingroup = 1;
+ break;
+ case ')':
+ if (! ingroup)
+ {
+ fprintf (stderr,
+ "%s: group ended before it began (--help for usage)\n",
+ program_name);
+ xexit (1);
+ }
+ lang_leave_group ();
+ ingroup = 0;
+ break;
}
}
+
+ if (ingroup)
+ lang_leave_group ();
}
/* Add the (colon-separated) elements of DIRLIST_PTR to the
if (p != NULL)
*p = 0;
if (*dirlist_ptr)
- ldfile_add_library_path (dirlist_ptr);
+ ldfile_add_library_path (dirlist_ptr, true);
if (p == NULL)
break;
*p = ':';