From Craig Silverstein: Implement OPTION in linker scripts.
This commit is contained in:
parent
c1866bd5e3
commit
a0451b389c
3 changed files with 189 additions and 144 deletions
290
gold/options.cc
290
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.
|
||||
|
||||
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;
|
||||
gold_assert(i < argc);
|
||||
|
||||
if (argv[i][0] != '-' || *no_more_options)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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].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;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Command_line::process(int argc, char** argv)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (argv[i][0] != '-' || no_more_options)
|
||||
{
|
||||
this->add_file(argv[i], false);
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Option starting with '-'.
|
||||
int dashes = 1;
|
||||
if (argv[i][1] == '-')
|
||||
{
|
||||
dashes = 2;
|
||||
if (argv[i][2] == '\0')
|
||||
{
|
||||
no_more_options = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
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 (j >= options_size)
|
||||
this->usage(_("unknown option"), *s);
|
||||
|
||||
++s;
|
||||
}
|
||||
}
|
||||
i = process_one_option(argc, argv, i, &no_more_options);
|
||||
|
||||
if (this->inputs_.in_group())
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue