From a0451b389c933e7b8938bdaa5c057c2c9a7428f1 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 30 Oct 2007 06:27:03 +0000 Subject: [PATCH] From Craig Silverstein: Implement OPTION in linker scripts. --- gold/options.cc | 282 +++++++++++++++++++++++++----------------------- gold/options.h | 5 + gold/script.cc | 38 ++++++- 3 files changed, 185 insertions(+), 140 deletions(-) diff --git a/gold/options.cc b/gold/options.cc index 08cbf2ae9cc..9a0b9f8d16c 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 208c62a238e..4b774ac3b0d 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 64894ca1ec7..83e490c2fcb 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(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); + } } -- 2.30.2