X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=gold%2Foptions.cc;h=671f3d5db084af848b88139dce628bf3113a194a;hb=8b2bff7fa62c20df7b3304499011fb30b8dd6b95;hp=35ed86313754e8ce5e80ac2523e688c369c2f9a9;hpb=bdf4f79d9338859820eef4596a9907f34fce506d;p=pf3gnuchains%2Fpf3gnuchains3x.git diff --git a/gold/options.cc b/gold/options.cc index 35ed863137..671f3d5db0 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -1,6 +1,6 @@ // options.c -- handle command line options for gold -// Copyright 2006, 2007, 2008 Free Software Foundation, Inc. +// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc. // Written by Ian Lance Taylor . // This file is part of gold. @@ -22,8 +22,10 @@ #include "gold.h" +#include #include #include +#include #include #include #include @@ -47,6 +49,11 @@ Position_dependent_options::default_options_; namespace options { +// This flag is TRUE if we should register the command-line options as they +// are constructed. It is set after contruction of the options within +// class Position_dependent_options. +static bool ready_to_register = false; + // This global variable is set up as General_options is constructed. static std::vector registered_options; @@ -60,6 +67,9 @@ static One_option* short_options[128]; void One_option::register_option() { + if (!ready_to_register) + return; + registered_options.push_back(this); // We can't make long_options a static Option_map because we can't @@ -75,7 +85,10 @@ One_option::register_option() const int shortname_as_int = static_cast(this->shortname); gold_assert(shortname_as_int >= 0 && shortname_as_int < 128); if (this->shortname != '\0') - short_options[shortname_as_int] = this; + { + gold_assert(short_options[shortname_as_int] == NULL); + short_options[shortname_as_int] = this; + } } void @@ -182,6 +195,16 @@ parse_uint(const char* option_name, const char* arg, int* retval) } void +parse_int(const char* option_name, const char* arg, int* retval) +{ + char* endptr; + *retval = strtol(arg, &endptr, 0); + if (*endptr != '\0') + gold_fatal(_("%s: invalid option value (expected an integer): %s"), + option_name, arg); +} + +void parse_uint64(const char* option_name, const char* arg, uint64_t *retval) { char* endptr; @@ -265,14 +288,18 @@ General_options::parse_help(const char*, const char*, Command_line*) void General_options::parse_version(const char* opt, const char*, Command_line*) { - gold::print_version(opt[0] == '-' && opt[1] == 'v'); - ::exit(EXIT_SUCCESS); + bool print_short = (opt[0] == '-' && opt[1] == 'v'); + gold::print_version(print_short); + this->printed_version_ = true; + if (!print_short) + ::exit(EXIT_SUCCESS); } void General_options::parse_V(const char*, const char*, Command_line*) { gold::print_version(true); + this->printed_version_ = true; printf(_(" Supported targets:\n")); std::vector supported_names; gold::supported_target_names(&supported_names); @@ -317,7 +344,19 @@ void General_options::parse_library(const char*, const char* arg, Command_line* cmdline) { - Input_file_argument file(arg, true, "", false, *this); + Input_file_argument::Input_file_type type; + const char *name; + if (arg[0] == ':') + { + type = Input_file_argument::INPUT_FILE_TYPE_SEARCHED_FILE; + name = arg + 1; + } + else + { + type = Input_file_argument::INPUT_FILE_TYPE_LIBRARY; + name = arg; + } + Input_file_argument file(name, type, "", false, *this); cmdline->inputs().add_file(file); } @@ -354,7 +393,8 @@ void General_options::parse_just_symbols(const char*, const char* arg, Command_line* cmdline) { - Input_file_argument file(arg, false, "", true, *this); + Input_file_argument file(arg, Input_file_argument::INPUT_FILE_TYPE_FILE, + "", true, *this); cmdline->inputs().add_file(file); } @@ -402,27 +442,68 @@ General_options::parse_end_group(const char*, const char*, cmdline->inputs().end_group(); } -} // End namespace gold. - -namespace -{ +// The function add_excluded_libs() in ld/ldlang.c of GNU ld breaks up a list +// of names seperated by commas or colons and puts them in a linked list. +// We implement the same parsing of names here but store names in an unordered +// map to speed up searching of names. void -usage() +General_options::parse_exclude_libs(const char*, const char* arg, + Command_line*) { - fprintf(stderr, - _("%s: use the --help option for usage information\n"), - gold::program_name); - ::exit(EXIT_FAILURE); + const char *p = arg; + + while (*p != '\0') + { + size_t length = strcspn(p, ",:"); + this->excluded_libs_.insert(std::string(p, length)); + p += (p[length] ? length + 1 : length); + } } -void -usage(const char* msg, const char *opt) +// The checking logic is based on the function check_excluded_libs() in +// ld/ldlang.c of GNU ld but our implementation is different because we use +// an unordered map instead of a linked list, which is what GNU ld uses. GNU +// ld searches sequentially in the excluded libs list. For a given archive, +// a match is found if the archive's name matches exactly one of the list +// entry or if the archive's name is of the form FOO.a and FOO matches exactly +// one of the list entry. An entry "ALL" in the list is considered as a +// wild-card and matches any given name. + +bool +General_options::check_excluded_libs (const std::string &name) const { - fprintf(stderr, - _("%s: %s: %s\n"), - gold::program_name, opt, msg); - usage(); + Unordered_set::const_iterator p; + + // Exit early for the most common case. + if (excluded_libs_.empty()) + return false; + + // If we see "ALL", all archives are excluded from automatic export. + p = excluded_libs_.find(std::string("ALL")); + if (p != excluded_libs_.end()) + return true; + + // First strip off any directories in name. + const char *basename = lbasename(name.c_str()); + + // Try finding an exact match. + p = excluded_libs_.find(std::string(basename)); + if (p != excluded_libs_.end()) + return true; + + // Try matching NAME without ".a" at the end. + size_t length = strlen(basename); + if ((length >= 2) + && (basename[length - 2] == '.') + && (basename[length - 1] == 'a')) + { + p = excluded_libs_.find(std::string(basename, length - 2)); + if (p != excluded_libs_.end()) + return true; + } + + return false; } // Recognize input and output target names. The GNU linker accepts @@ -432,8 +513,8 @@ usage(const char* msg, const char *opt) // "elf". Non-ELF targets would be "srec", "symbolsrec", "tekhex", // "binary", "ihex". -gold::General_options::Object_format -string_to_object_format(const char* arg) +General_options::Object_format +General_options::string_to_object_format(const char* arg) { if (strncmp(arg, "elf", 3) == 0) return gold::General_options::OBJECT_FORMAT_ELF; @@ -448,10 +529,33 @@ string_to_object_format(const char* arg) } } +} // End namespace gold. + +namespace +{ + +void +usage() +{ + fprintf(stderr, + _("%s: use the --help option for usage information\n"), + gold::program_name); + ::exit(EXIT_FAILURE); +} + +void +usage(const char* msg, const char *opt) +{ + fprintf(stderr, + _("%s: %s: %s\n"), + gold::program_name, opt, msg); + usage(); +} + // If the default sysroot is relocatable, try relocating it based on // the prefix FROM. -char* +static char* get_relative_sysroot(const char* from) { char* path = make_relative_prefix(gold::program_name, from, @@ -472,7 +576,7 @@ get_relative_sysroot(const char* from) // get_relative_sysroot, which is a small memory leak, but is // necessary since we store this pointer directly in General_options. -const char* +static const char* get_default_sysroot() { const char* sysroot = TARGET_SYSTEM_ROOT; @@ -587,7 +691,7 @@ parse_short_option(int argc, const char** argv, int pos_in_argv_i, // We handle -z as a special case. static gold::options::One_option dash_z("", gold::options::DASH_Z, - 'z', "", "-z", "Z-OPTION", false, + 'z', "", NULL, "Z-OPTION", false, NULL); gold::options::One_option* retval = NULL; if (this_argv[pos_in_argv_i] == 'z') @@ -644,22 +748,25 @@ namespace gold { General_options::General_options() - : execstack_status_(General_options::EXECSTACK_FROM_INPUT), static_(false), + : printed_version_(false), + execstack_status_(General_options::EXECSTACK_FROM_INPUT), static_(false), do_demangle_(false), plugins_(), incremental_disposition_(INCREMENTAL_CHECK), implicit_incremental_(false) { + // Turn off option registration once construction is complete. + gold::options::ready_to_register = false; } General_options::Object_format General_options::format_enum() const { - return string_to_object_format(this->format()); + return General_options::string_to_object_format(this->format()); } General_options::Object_format General_options::oformat_enum() const { - return string_to_object_format(this->oformat()); + return General_options::string_to_object_format(this->oformat()); } // Add the sysroot, if any, to the search paths. @@ -684,6 +791,26 @@ General_options::add_sysroot() free(canonical_sysroot); } +// Return whether FILENAME is in a system directory. + +bool +General_options::is_in_system_directory(const std::string& filename) const +{ + for (Dir_list::const_iterator p = this->library_path_.value.begin(); + p != this->library_path_.value.end(); + ++p) + { + // We use a straight string comparison rather than calling + // FILENAME_CMP because we are only interested in the cases + // where we found the file in a system directory, which means + // that we used the directory name as a prefix for a -L search. + if (p->is_system_directory() + && filename.compare(0, p->name().size(), p->name()) == 0) + return true; + } + return false; +} + // Add a plugin to the list of plugins. void @@ -750,6 +877,15 @@ General_options::finalize() else if (this->noexecstack()) this->set_execstack_status(EXECSTACK_NO); + // icf_status_ is a three-state variable; update it based on the + // value of this->icf(). + if (strcmp(this->icf(), "none") == 0) + this->set_icf_status(ICF_NONE); + else if (strcmp(this->icf(), "safe") == 0) + this->set_icf_status(ICF_SAFE); + else + this->set_icf_status(ICF_ALL); + // Handle the optional argument for --demangle. if (this->user_set_demangle()) { @@ -839,6 +975,25 @@ General_options::finalize() this->add_to_library_path_with_sysroot("/usr/lib"); } + // Parse the contents of -retain-symbols-file into a set. + if (this->retain_symbols_file()) + { + std::ifstream in; + in.open(this->retain_symbols_file()); + if (!in) + gold_fatal(_("unable to open -retain-symbols-file file %s: %s"), + this->retain_symbols_file(), strerror(errno)); + std::string line; + std::getline(in, line); // this chops off the trailing \n, if any + while (in) + { + if (!line.empty() && line[line.length() - 1] == '\r') // Windows + line.resize(line.length() - 1); + this->symbols_to_retain_.insert(line); + std::getline(in, line); + } + } + if (this->shared() && !this->user_set_allow_shlib_undefined()) this->set_allow_shlib_undefined(true); @@ -849,13 +1004,24 @@ General_options::finalize() // Now that we've normalized the options, check for contradictory ones. if (this->shared() && this->is_static()) gold_fatal(_("-shared and -static are incompatible")); + if (this->shared() && this->pie()) + gold_fatal(_("-shared and -pie are incompatible")); if (this->shared() && this->relocatable()) gold_fatal(_("-shared and -r are incompatible")); + if (this->pie() && this->relocatable()) + gold_fatal(_("-pie and -r are incompatible")); + + // TODO: implement support for -retain-symbols-file with -r, if needed. + if (this->relocatable() && this->retain_symbols_file()) + gold_fatal(_("-retain-symbols-file does not yet work with -r")); if (this->oformat_enum() != General_options::OBJECT_FORMAT_ELF - && (this->shared() || this->relocatable())) - gold_fatal(_("binary output format not compatible with -shared or -r")); + && (this->shared() + || this->pie() + || this->relocatable())) + gold_fatal(_("binary output format not compatible " + "with -shared or -pie or -r")); if (this->user_set_hash_bucket_empty_fraction() && (this->hash_bucket_empty_fraction() < 0.0 @@ -953,6 +1119,13 @@ Command_line::Command_line() { } +// Pre_options is the hook that sets the ready_to_register flag. + +Command_line::Pre_options::Pre_options() +{ + gold::options::ready_to_register = true; +} + // Process the command line options. For process_one_option, i is the // index of argv to process next, and must be an option (that is, // start with a dash). The return value is the index of the next @@ -1016,8 +1189,9 @@ Command_line::process(int argc, const char** argv) this->position_options_.copy_from_options(this->options()); if (no_more_options || argv[i][0] != '-') { - Input_file_argument file(argv[i], false, "", false, - this->position_options_); + Input_file_argument file(argv[i], + Input_file_argument::INPUT_FILE_TYPE_FILE, + "", false, this->position_options_); this->inputs_.add_file(file); ++i; } @@ -1035,4 +1209,15 @@ Command_line::process(int argc, const char** argv) this->options_.finalize(); } +// Finalize the version script options and return them. + +const Version_script_info& +Command_line::version_script() +{ + this->options_.finalize_dynamic_list(); + Version_script_info* vsi = this->script_options_.version_script_info(); + vsi->finalize(); + return *vsi; +} + } // End namespace gold.