From Craig Silverstein: Implement OPTION in linker scripts.
authorIan Lance Taylor <iant@google.com>
Tue, 30 Oct 2007 06:27:03 +0000 (06:27 +0000)
committerIan Lance Taylor <iant@google.com>
Tue, 30 Oct 2007 06:27:03 +0000 (06:27 +0000)
gold/options.cc
gold/options.h
gold/script.cc

index 08cbf2ae9cc3d062065c3becfa5f0d3c7dbacd95..9a0b9f8d16c0dca979651953e84b692e1d330087 100644 (file)
@@ -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())
     {
index 208c62a238ee8bd25d3e7c1865f035b3618ec11a..4b774ac3b0d2e487d3084d0eae4b091b89bd6a35 100644 (file)
@@ -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);
index 64894ca1ec7046d8b33c1a772f34e9b4eb296c64..83e490c2fcb2572b5f86a0326d1a519380761abd 100644 (file)
@@ -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);
+    }
 }
This page took 0.030981 seconds and 4 git commands to generate.