aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/options.cc282
-rw-r--r--gold/options.h5
-rw-r--r--gold/script.cc38
3 files changed, 185 insertions, 140 deletions
diff --git a/gold/options.cc b/gold/options.cc
index 08cbf2a..9a0b9f8 100644
--- a/gold/options.cc
+++ b/gold/options.cc
@@ -395,12 +395,13 @@ options::Command_line_options::options[] =
NULL, TWO_DASHES, &General_options::set_stats),
GENERAL_ARG('\0', "sysroot", N_("Set target system root directory"),
N_("--sysroot DIR"), TWO_DASHES, &General_options::set_sysroot),
- SPECIAL('T', "script", N_("Read linker script"),
- N_("-T FILE, --script FILE"), TWO_DASHES,
- &invoke_script),
GENERAL_ARG('\0', "Ttext", N_("Set the address of the .text section"),
N_("-Ttext ADDRESS"), ONE_DASH,
&General_options::set_text_segment_address),
+ // This must come after -Ttext since it's a prefix of it.
+ SPECIAL('T', "script", N_("Read linker script"),
+ N_("-T FILE, --script FILE"), TWO_DASHES,
+ &invoke_script),
GENERAL_NOARG('\0', "threads", N_("Run the linker multi-threaded"),
NULL, TWO_DASHES, &General_options::set_threads),
GENERAL_NOARG('\0', "no-threads", N_("Do not run the linker multi-threaded"),
@@ -623,149 +624,160 @@ Command_line::Command_line()
{
}
-// Process the command line options.
+// Process the command line options. For process_one_option,
+// i is the index of argv to process next, and the return value
+// is the index of the next option to process (i+1 or i+2, or argc
+// to indicate processing is done). no_more_options is set to true
+// if (and when) "--" is seen as an option.
-void
-Command_line::process(int argc, char** argv)
+int
+Command_line::process_one_option(int argc, char** argv, int i,
+ bool* no_more_options)
{
const int options_size = options::Command_line_options::options_size;
- const options::One_option* options =
- options::Command_line_options::options;
- bool no_more_options = false;
- int i = 0;
- while (i < argc)
+ const options::One_option* options = options::Command_line_options::options;
+ gold_assert(i < argc);
+
+ if (argv[i][0] != '-' || *no_more_options)
{
- if (argv[i][0] != '-' || no_more_options)
- {
- this->add_file(argv[i], false);
- ++i;
- continue;
- }
+ this->add_file(argv[i], false);
+ return i + 1;
+ }
- // Option starting with '-'.
- int dashes = 1;
- if (argv[i][1] == '-')
- {
- dashes = 2;
- if (argv[i][2] == '\0')
- {
- no_more_options = true;
- continue;
- }
- }
+ // Option starting with '-'.
+ int dashes = 1;
+ if (argv[i][1] == '-')
+ {
+ dashes = 2;
+ if (argv[i][2] == '\0')
+ {
+ *no_more_options = true;
+ return i + 1;
+ }
+ }
- // Look for a long option match.
- char* opt = argv[i] + dashes;
- char first = opt[0];
- int skiparg = 0;
- char* arg = strchr(opt, '=');
- bool argument_with_equals = arg != NULL;
- if (arg != NULL)
- {
- *arg = '\0';
- ++arg;
- }
- else if (i + 1 < argc)
- {
- arg = argv[i + 1];
- skiparg = 1;
- }
+ // Look for a long option match.
+ char* opt = argv[i] + dashes;
+ char first = opt[0];
+ int skiparg = 0;
+ char* arg = strchr(opt, '=');
+ bool argument_with_equals = arg != NULL;
+ if (arg != NULL)
+ {
+ *arg = '\0';
+ ++arg;
+ }
+ else if (i + 1 < argc)
+ {
+ arg = argv[i + 1];
+ skiparg = 1;
+ }
+ int j;
+ for (j = 0; j < options_size; ++j)
+ {
+ if (options[j].long_option != NULL
+ && (dashes == 2
+ || (options[j].dash
+ != options::One_option::EXACTLY_TWO_DASHES))
+ && first == options[j].long_option[0]
+ && strcmp(opt, options[j].long_option) == 0)
+ {
+ if (options[j].special)
+ {
+ // Restore the '=' we clobbered above.
+ if (arg != NULL && skiparg == 0)
+ arg[-1] = '=';
+ i += options[j].special(argc - i, argv + i, opt, true, this);
+ }
+ else
+ {
+ if (!options[j].takes_argument())
+ {
+ if (argument_with_equals)
+ this->usage(_("unexpected argument"), argv[i]);
+ arg = NULL;
+ skiparg = 0;
+ }
+ else
+ {
+ if (arg == NULL)
+ this->usage(_("missing argument"), argv[i]);
+ }
+ this->apply_option(options[j], arg);
+ i += skiparg + 1;
+ }
+ break;
+ }
+ }
+ if (j < options_size)
+ return i;
+
+ // If we saw two dashes, we needed to have seen a long option.
+ if (dashes == 2)
+ this->usage(_("unknown option"), argv[i]);
+
+ // Look for a short option match. There may be more than one
+ // short option in a given argument.
+ bool done = false;
+ char* s = argv[i] + 1;
+ ++i;
+ while (*s != '\0' && !done)
+ {
+ char opt = *s;
int j;
for (j = 0; j < options_size; ++j)
- {
- if (options[j].long_option != NULL
- && (dashes == 2
- || (options[j].dash
- != options::One_option::EXACTLY_TWO_DASHES))
- && first == options[j].long_option[0]
- && strcmp(opt, options[j].long_option) == 0)
- {
- if (options[j].special)
- {
- // Restore the '=' we clobbered above.
- if (arg != NULL && skiparg == 0)
- arg[-1] = '=';
- i += options[j].special(argc - i, argv + i, opt, true, this);
- }
- else
- {
- if (!options[j].takes_argument())
- {
- if (argument_with_equals)
- this->usage(_("unexpected argument"), argv[i]);
- arg = NULL;
- skiparg = 0;
- }
- else
- {
- if (arg == NULL)
- this->usage(_("missing argument"), argv[i]);
- }
- this->apply_option(options[j], arg);
- i += skiparg + 1;
- }
- break;
- }
- }
- if (j < options_size)
- continue;
-
- // If we saw two dashes, we need to see a long option.
- if (dashes == 2)
- this->usage(_("unknown option"), argv[i]);
-
- // Look for a short option match. There may be more than one
- // short option in a given argument.
- bool done = false;
- char* s = argv[i] + 1;
- ++i;
- while (*s != '\0' && !done)
- {
- char opt = *s;
- int j;
- for (j = 0; j < options_size; ++j)
- {
- if (options[j].short_option == opt)
- {
- if (options[j].special)
- {
- // Undo the argument skip done above.
- --i;
- i += options[j].special(argc - i, argv + i, s, false,
- this);
- done = true;
- }
- else
- {
- arg = NULL;
- if (options[j].takes_argument())
- {
- if (s[1] != '\0')
- {
- arg = s + 1;
- done = true;
- }
- else if (i < argc)
- {
- arg = argv[i];
- ++i;
- }
- else
- this->usage(_("missing argument"), opt);
- }
- this->apply_option(options[j], arg);
- }
- break;
- }
- }
+ {
+ if (options[j].short_option == opt)
+ {
+ if (options[j].special)
+ {
+ // Undo the argument skip done above.
+ --i;
+ i += options[j].special(argc - i, argv + i, s, false,
+ this);
+ done = true;
+ }
+ else
+ {
+ arg = NULL;
+ if (options[j].takes_argument())
+ {
+ if (s[1] != '\0')
+ {
+ arg = s + 1;
+ done = true;
+ }
+ else if (i < argc)
+ {
+ arg = argv[i];
+ ++i;
+ }
+ else
+ this->usage(_("missing argument"), opt);
+ }
+ this->apply_option(options[j], arg);
+ }
+ break;
+ }
+ }
+
+ if (j >= options_size)
+ this->usage(_("unknown option"), *s);
+
+ ++s;
+ }
+ return i;
+}
- if (j >= options_size)
- this->usage(_("unknown option"), *s);
- ++s;
- }
- }
+void
+Command_line::process(int argc, char** argv)
+{
+ bool no_more_options = false;
+ int i = 0;
+ while (i < argc)
+ i = process_one_option(argc, argv, i, &no_more_options);
if (this->inputs_.in_group())
{
diff --git a/gold/options.h b/gold/options.h
index 208c62a..4b774ac 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -696,6 +696,11 @@ class Command_line
void
process(int argc, char** argv);
+ // Process one command-line option. This takes the index of argv to
+ // process, and returns the index for the next option.
+ int
+ process_one_option(int argc, char** argv, int i, bool* no_more_options);
+
// Handle a -l option.
int
process_l_option(int, char**, char*, bool);
diff --git a/gold/script.cc b/gold/script.cc
index 64894ca..83e490c 100644
--- a/gold/script.cc
+++ b/gold/script.cc
@@ -831,9 +831,11 @@ class Parser_closure
Parser_closure(const char* filename,
const Position_dependent_options& posdep_options,
bool in_group, bool is_in_sysroot,
+ Command_line* command_line,
const Lex::Token_sequence* tokens)
: filename_(filename), posdep_options_(posdep_options),
- in_group_(in_group), is_in_sysroot_(is_in_sysroot), tokens_(tokens),
+ in_group_(in_group), is_in_sysroot_(is_in_sysroot),
+ command_line_(command_line), tokens_(tokens),
next_token_index_(0), inputs_(NULL)
{ }
@@ -859,6 +861,12 @@ class Parser_closure
is_in_sysroot() const
{ return this->is_in_sysroot_; }
+ // Returns the Command_line structure passed in at constructor time.
+ // This value may be NULL. The caller may modify this, which modifies
+ // the passed-in Command_line object (not a copy).
+ Command_line* command_line()
+ { return this->command_line_; }
+
// Whether we are at the end of the token list.
bool
at_eof() const
@@ -897,6 +905,8 @@ class Parser_closure
bool in_group_;
// Whether the script was found in a sysrooted directory.
bool is_in_sysroot_;
+ // May be NULL if the user chooses not to pass one in.
+ Command_line* command_line_;
// The tokens to be returned by the lexer.
const Lex::Token_sequence* tokens_;
@@ -927,6 +937,7 @@ read_input_script(Workqueue* workqueue, const General_options& options,
input_argument->file().options(),
input_group != NULL,
input_file->is_in_sysroot(),
+ NULL,
&lex.tokens());
if (yyparse(&closure) != 0)
@@ -973,9 +984,8 @@ read_input_script(Workqueue* workqueue, const General_options& options,
bool
read_commandline_script(const char* filename, Command_line* cmdline)
{
- // We don't need to use the real directory search path here:
- // FILENAME was specified on the command line, and we don't want to
- // search for it.
+ // TODO: if filename is a relative filename, search for it manually
+ // using "." + cmdline->options()->search_path() -- not dirsearch.
Dirsearch dirsearch;
Input_file_argument input_argument(filename, false, "",
@@ -996,6 +1006,7 @@ read_commandline_script(const char* filename, Command_line* cmdline)
cmdline->position_dependent_options(),
false,
input_file.is_in_sysroot(),
+ cmdline,
&lex.tokens());
if (yyparse(&closure) != 0)
{
@@ -1306,5 +1317,22 @@ extern "C" void
script_parse_option(void* closurev, const char* option)
{
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- printf("%s: Saw option %s\n", closure->filename(), option); //!!
+ // We treat the option as a single command-line option, even if
+ // it has internal whitespace.
+ if (closure->command_line() == NULL)
+ {
+ // There are some options that we could handle here--e.g.,
+ // -lLIBRARY. Should we bother?
+ gold_warning(_("%s: Ignoring command OPTION; OPTION is only valid"
+ " for scripts specified via -T"),
+ closure->filename());
+ }
+ else
+ {
+ bool past_a_double_dash_option = false;
+ char* mutable_option = strdup(option);
+ closure->command_line()->process_one_option(1, &mutable_option, 0,
+ &past_a_double_dash_option);
+ free(mutable_option);
+ }
}