From Craig Silverstein and Ian Lance Taylor: Process --script option.

This commit is contained in:
Ian Lance Taylor 2007-10-27 00:29:34 +00:00
parent 4af13c269b
commit 3c2fafa531
7 changed files with 255 additions and 69 deletions

View File

@ -54,6 +54,10 @@ main(int argc, char** argv)
Errors errors(program_name);
// Initialize the global parameters, to let random code get to the
// errors object.
initialize_parameters(&errors);
// Handle the command line options.
Command_line command_line;
command_line.process(argc - 1, argv + 1);
@ -62,7 +66,8 @@ main(int argc, char** argv)
if (command_line.options().print_stats())
start_time = get_run_time();
initialize_parameters(&command_line.options(), &errors);
// Store some options in the globally accessible parameters.
set_parameters_from_options(&command_line.options());
// The work queue.
Workqueue workqueue(command_line.options());

View File

@ -69,7 +69,8 @@ struct options::One_option
// be 0 if this function changes *argv. ARG points to the location
// in *ARGV where the option starts, which may be helpful for a
// short option.
int (*special)(int argc, char** argv, char *arg, Command_line*);
int (*special)(int argc, char** argv, char *arg, bool long_option,
Command_line*);
// If this is a position independent option which does not take an
// argument, this is the member function to call to record it.
@ -121,15 +122,32 @@ namespace
// Handle the special -l option, which adds an input file.
int
library(int argc, char** argv, char* arg, gold::Command_line* cmdline)
library(int argc, char** argv, char* arg, bool long_option,
gold::Command_line* cmdline)
{
return cmdline->process_l_option(argc, argv, arg);
return cmdline->process_l_option(argc, argv, arg, long_option);
}
// Handle the special -T/--script option, which reads a linker script.
int
invoke_script(int argc, char** argv, char* arg, bool long_option,
gold::Command_line* cmdline)
{
int ret;
const char* script_name = cmdline->get_special_argument("script", argc, argv,
arg, long_option,
&ret);
if (!read_commandline_script(script_name, cmdline))
gold::gold_error(_("%s: unable to parse script file %s\n"),
gold::program_name, arg);
return ret;
}
// Handle the special --start-group option.
int
start_group(int, char**, char* arg, gold::Command_line* cmdline)
start_group(int, char**, char* arg, bool, gold::Command_line* cmdline)
{
cmdline->start_group(arg);
return 1;
@ -138,7 +156,7 @@ start_group(int, char**, char* arg, gold::Command_line* cmdline)
// Handle the special --end-group option.
int
end_group(int, char**, char* arg, gold::Command_line* cmdline)
end_group(int, char**, char* arg, bool, gold::Command_line* cmdline)
{
cmdline->end_group(arg);
return 1;
@ -147,7 +165,7 @@ end_group(int, char**, char* arg, gold::Command_line* cmdline)
// Report usage information for ld --help, and exit.
int
help(int, char**, char*, gold::Command_line*)
help(int, char**, char*, bool, gold::Command_line*)
{
printf(_("Usage: %s [options] file...\nOptions:\n"), gold::program_name);
@ -236,7 +254,7 @@ help(int, char**, char*, gold::Command_line*)
// Report version information.
int
version(int, char**, char* opt, gold::Command_line*)
version(int, char**, char* opt, bool, gold::Command_line*)
{
gold::print_version(opt[0] == 'v' && opt[1] == '\0');
::exit(0);
@ -377,9 +395,9 @@ 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),
GENERAL_ARG('T', "script", N_("Read linker script"),
N_("-T FILE, --script FILE"), TWO_DASHES,
&General_options::set_script),
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),
@ -664,7 +682,12 @@ Command_line::process(int argc, char** argv)
&& strcmp(opt, options[j].long_option) == 0)
{
if (options[j].special)
i += options[j].special(argc - 1, argv + i, opt, this);
{
// 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())
@ -709,7 +732,8 @@ Command_line::process(int argc, char** argv)
{
// Undo the argument skip done above.
--i;
i += options[j].special(argc - i, argv + i, s, this);
i += options[j].special(argc - i, argv + i, s, false,
this);
done = true;
}
else
@ -759,6 +783,49 @@ Command_line::process(int argc, char** argv)
this->normalize_options();
}
// Extract an option argument for a special option. LONGNAME is the
// long name of the option. This sets *PRET to the return value for
// the special function handler to skip to the next option.
const char*
Command_line::get_special_argument(const char* longname, int argc, char** argv,
const char* arg, bool long_option,
int *pret)
{
if (long_option)
{
size_t longlen = strlen(longname);
gold_assert(strncmp(arg, longname, longlen) == 0);
arg += longlen;
if (*arg == '=')
{
*pret = 1;
return arg + 1;
}
else if (argc > 1)
{
gold_assert(*arg == '\0');
*pret = 2;
return argv[1];
}
}
else
{
if (arg[1] != '\0')
{
*pret = 1;
return arg + 1;
}
else if (argc > 1)
{
*pret = 2;
return argv[1];
}
}
this->usage(_("missing argument"), arg);
}
// Ensure options don't contradict each other and are otherwise kosher.
void
@ -814,25 +881,13 @@ Command_line::add_file(const char* name, bool is_lib)
// Handle the -l option, which requires special treatment.
int
Command_line::process_l_option(int argc, char** argv, char* arg)
Command_line::process_l_option(int argc, char** argv, char* arg,
bool long_option)
{
int ret;
const char* libname;
if (arg[1] != '\0')
{
ret = 1;
libname = arg + 1;
}
else if (argc > 1)
{
ret = 2;
libname = argv[argc + 1];
}
else
this->usage(_("missing argument"), arg);
const char* libname = this->get_special_argument("library", argc, argv, arg,
long_option, &ret);
this->add_file(libname, true);
return ret;
}

View File

@ -37,11 +37,14 @@
#include <string>
#include <vector>
#include "script.h"
namespace gold
{
class Command_line;
class Input_file_group;
class Position_dependent_options;
namespace options {
@ -316,14 +319,6 @@ class General_options
set_static()
{ this->is_static_ = true; }
void
set_script(const char* arg)
{
fprintf(stderr, _("%s: cannot parse %s: -T/--script not yet supported\n"),
program_name, arg);
::exit(1);
}
void
set_stats()
{ this->print_stats_ = true; }
@ -703,7 +698,7 @@ class Command_line
// Handle a -l option.
int
process_l_option(int, char**, char*);
process_l_option(int, char**, char*, bool);
// Handle a --start-group option.
void
@ -713,11 +708,22 @@ class Command_line
void
end_group(const char* arg);
// Get an option argument--a helper function for special processing.
const char*
get_special_argument(const char* longname, int argc, char** argv,
const char* arg, bool long_option,
int *pret);
// Get the general options.
const General_options&
options() const
{ return this->options_; }
// Get the position dependent options.
const Position_dependent_options&
position_dependent_options() const
{ return this->position_options_; }
// The number of input files.
int
number_of_input_files() const

View File

@ -30,14 +30,27 @@ namespace gold
// Initialize the parameters from the options.
Parameters::Parameters(const General_options* options, Errors* errors)
: errors_(errors), output_file_name_(options->output_file_name()),
sysroot_(options->sysroot()), symbolic_(options->symbolic()),
Parameters::Parameters(Errors* errors)
: errors_(errors), output_file_name_(NULL),
output_file_type_(OUTPUT_INVALID), sysroot_(),
strip_(STRIP_INVALID), symbolic_(false),
optimization_level_(0), export_dynamic_(false),
is_doing_static_link_valid_(false), doing_static_link_(false),
is_size_and_endian_valid_(false), size_(0), is_big_endian_(false),
optimization_level_(options->optimization_level()),
export_dynamic_(options->export_dynamic())
is_size_and_endian_valid_(false), size_(0), is_big_endian_(false)
{
}
// Set fields from the command line options.
void
Parameters::set_from_options(const General_options* options)
{
this->output_file_name_ = options->output_file_name();
this->sysroot_ = options->sysroot();
this->symbolic_ = options->symbolic();
this->optimization_level_ = options->optimization_level();
this->export_dynamic_ = options->export_dynamic();
if (options->is_shared())
this->output_file_type_ = OUTPUT_SHARED;
else if (options->is_relocatable())
@ -51,6 +64,8 @@ Parameters::Parameters(const General_options* options, Errors* errors)
this->strip_ = STRIP_DEBUG;
else
this->strip_ = STRIP_NONE;
this->options_valid_ = true;
}
// Set whether we are doing a static link.
@ -91,9 +106,17 @@ const Parameters* parameters;
// Initialize the global variable.
void
initialize_parameters(const General_options* options, Errors* errors)
initialize_parameters(Errors* errors)
{
parameters = static_parameters = new Parameters(options, errors);
parameters = static_parameters = new Parameters(errors);
}
// Set values from the options.
void
set_parameters_from_options(const General_options* options)
{
static_parameters->set_from_options(options);
}
// Set whether we are doing a static link.

View File

@ -40,7 +40,7 @@ class Errors;
class Parameters
{
public:
Parameters(const General_options*, Errors*);
Parameters(Errors*);
// Return the error object.
Errors*
@ -50,22 +50,34 @@ class Parameters
// Return the output file name.
const char*
output_file_name() const
{ return this->output_file_name_; }
{
gold_assert(this->options_valid_);
return this->output_file_name_;
}
// Whether we are generating a regular executable.
bool
output_is_executable() const
{ return this->output_file_type_ == OUTPUT_EXECUTABLE; }
{
gold_assert(this->output_file_type_ != OUTPUT_INVALID);
return this->output_file_type_ == OUTPUT_EXECUTABLE;
}
// Whether we are generating a shared library.
bool
output_is_shared() const
{ return this->output_file_type_ == OUTPUT_SHARED; }
{
gold_assert(this->output_file_type_ != OUTPUT_INVALID);
return this->output_file_type_ == OUTPUT_SHARED;
}
// Whether we are generating an object file.
bool
output_is_object() const
{ return this->output_file_type_ == OUTPUT_OBJECT; }
{
gold_assert(this->output_file_type_ != OUTPUT_INVALID);
return this->output_file_type_ == OUTPUT_OBJECT;
}
// Whether we are generating position-independent output.
// This is the case when generating either a shared library
@ -79,23 +91,51 @@ class Parameters
// one.
const std::string&
sysroot() const
{ return this->sysroot_; }
{
gold_assert(this->options_valid_);
return this->sysroot_;
}
// Whether to strip all symbols.
bool
strip_all() const
{ return this->strip_ == STRIP_ALL; }
{
gold_assert(this->strip_ != STRIP_INVALID);
return this->strip_ == STRIP_ALL;
}
// Whether to strip debugging information.
bool
strip_debug() const
{ return this->strip_ == STRIP_ALL || this->strip_ == STRIP_DEBUG; }
{
gold_assert(this->strip_ != STRIP_INVALID);
return this->strip_ == STRIP_ALL || this->strip_ == STRIP_DEBUG;
}
// Whether we are doing a symbolic link, in which all defined
// symbols are bound locally.
bool
symbolic() const
{ return this->symbolic_; }
{
gold_assert(this->options_valid_);
return this->symbolic_;
}
// The general linker optimization level.
int
optimization_level() const
{
gold_assert(this->options_valid_);
return this->optimization_level_;
}
// Whether the -E/--export-dynamic flag is set.
bool
export_dynamic() const
{
gold_assert(this->options_valid_);
return this->export_dynamic_;
}
// Whether we are doing a static link--a link in which none of the
// input files are shared libraries. This is only known after we
@ -124,15 +164,9 @@ class Parameters
return this->is_big_endian_;
}
// The general linker optimization level.
int
optimization_level() const
{ return this->optimization_level_; }
// Whether the -E/--export-dynamic flag is set.
bool
export_dynamic() const
{ return this->export_dynamic_; }
// Set values recorded from options.
void
set_from_options(const General_options*);
// Set whether we are doing a static link.
void
@ -146,6 +180,8 @@ class Parameters
// The types of output files.
enum Output_file_type
{
// Uninitialized.
OUTPUT_INVALID,
// Generating executable.
OUTPUT_EXECUTABLE,
// Generating shared library.
@ -157,6 +193,8 @@ class Parameters
// Which symbols to strip.
enum Strip
{
// Uninitialize.
STRIP_INVALID,
// Don't strip any symbols.
STRIP_NONE,
// Strip all symbols.
@ -168,6 +206,8 @@ class Parameters
// A pointer to the error handling object.
Errors* errors_;
// Whether the fields set from the options are valid.
bool options_valid_;
// The output file name.
const char* output_file_name_;
// The type of the output file.
@ -178,6 +218,10 @@ class Parameters
Strip strip_;
// Whether we are doing a symbolic link.
bool symbolic_;
// The optimization level.
int optimization_level_;
// Whether the -E/--export-dynamic flag is set.
bool export_dynamic_;
// Whether the doing_static_link_ field is valid.
bool is_doing_static_link_valid_;
@ -189,17 +233,16 @@ class Parameters
int size_;
// Whether the output file is big endian.
bool is_big_endian_;
// The optimization level.
int optimization_level_;
// Whether the -E/--export-dynamic flag is set.
bool export_dynamic_;
};
// This is a global variable.
extern const Parameters* parameters;
// Initialize the global variable.
extern void initialize_parameters(const General_options*, Errors*);
extern void initialize_parameters(Errors*);
// Set the options.
extern void set_parameters_from_options(const General_options*);
// Set the size and endianness of the global parameters variable.
extern void set_parameters_size_and_endianness(int size, bool is_big_endian);

View File

@ -28,6 +28,7 @@
#include <cstdlib>
#include "filenames.h"
#include "dirsearch.h"
#include "options.h"
#include "fileread.h"
#include "workqueue.h"
@ -931,6 +932,10 @@ read_input_script(Workqueue* workqueue, const General_options& options,
if (yyparse(&closure) != 0)
return false;
// If this routine was called from the main thread rather than a
// work queue -- as it is for the --script option -- then our
// work here is done.
// THIS_BLOCKER must be clear before we may add anything to the
// symbol table. We are responsible for unblocking NEXT_BLOCKER
// when we are done. We are responsible for deleting THIS_BLOCKER
@ -966,6 +971,46 @@ read_input_script(Workqueue* workqueue, const General_options& options,
return true;
}
// FILENAME was found as an argument to --script (-T).
// Read it as a script, and execute its contents immediately.
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.
Dirsearch dirsearch;
Input_file_argument input_argument(filename, false, "",
cmdline->position_dependent_options());
Input_file input_file(&input_argument);
if (!input_file.open(cmdline->options(), dirsearch))
return false;
Lex lex(&input_file);
if (lex.tokenize().is_invalid())
{
// Opening the file locked it, so now we need to unlock it.
input_file.file().unlock();
return false;
}
Parser_closure closure(filename,
cmdline->position_dependent_options(),
false,
input_file.is_in_sysroot(),
&lex.tokens());
if (yyparse(&closure) != 0)
{
input_file.file().unlock();
return false;
}
input_file.file().unlock();
return true;
}
// Manage mapping from keywords to the codes expected by the bison
// parser.

View File

@ -34,12 +34,15 @@ namespace gold
{
class General_options;
class Command_line;
class Symbol_table;
class Layout;
class Input_argument;
class Input_objects;
class Input_group;
class Input_file;
class Task_token;
class Workqueue;
// FILE was found as an argument on the command line, but was not
// recognized as an ELF file. Try to read it as a script. We've
@ -54,6 +57,12 @@ read_input_script(Workqueue*, const General_options&, Symbol_table*, Layout*,
off_t bytes, Task_token* this_blocker,
Task_token* next_blocker);
// FILE was found as an argument to --script (-T).
// Read it as a script, and execute its contents immediately.
bool
read_commandline_script(const char* filename, Command_line*);
} // End namespace gold.
#endif // !defined(GOLD_SCRIPT_H)