Full support for --sysroot.
[binutils-gdb.git] / gold / script.cc
index b22611fab81fe07c8e0d0d28291070877e41439e..365cedf9c2ef8d68cee4b4b9a90480c84d2bbe2f 100644 (file)
@@ -1,17 +1,38 @@
 // script.cc -- handle linker scripts for gold.
 
+// Copyright 2006, 2007 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
 #include "gold.h"
 
 #include <string>
 #include <vector>
-#include <cassert>
 #include <cstdio>
 #include <cstdlib>
+#include "filenames.h"
 
 #include "options.h"
 #include "fileread.h"
 #include "workqueue.h"
 #include "readsyms.h"
+#include "parameters.h"
 #include "yyscript.h"
 #include "script.h"
 #include "script-c.h"
@@ -50,14 +71,20 @@ class Token
   Token(Classification classification, int lineno, int charpos)
     : classification_(classification), value_(), opcode_(0),
       lineno_(lineno), charpos_(charpos)
-  { assert(classification == TOKEN_INVALID || classification == TOKEN_EOF); }
+  {
+    gold_assert(classification == TOKEN_INVALID
+               || classification == TOKEN_EOF);
+  }
 
   // A general token with a value.
   Token(Classification classification, const std::string& value,
        int lineno, int charpos)
     : classification_(classification), value_(value), opcode_(0),
       lineno_(lineno), charpos_(charpos)
-  { assert(classification != TOKEN_INVALID && classification != TOKEN_EOF); }
+  {
+    gold_assert(classification != TOKEN_INVALID
+               && classification != TOKEN_EOF);
+  }
 
   // A token representing a string of characters.
   Token(const std::string& s, int lineno, int charpos)
@@ -101,21 +128,21 @@ class Token
   const std::string&
   string_value() const
   {
-    assert(this->classification_ == TOKEN_STRING);
+    gold_assert(this->classification_ == TOKEN_STRING);
     return this->value_;
   }
 
   int
   operator_value() const
   {
-    assert(this->classification_ == TOKEN_OPERATOR);
+    gold_assert(this->classification_ == TOKEN_OPERATOR);
     return this->opcode_;
   }
 
   int64_t
   integer_value() const
   {
-    assert(this->classification_ == TOKEN_INTEGER);
+    gold_assert(this->classification_ == TOKEN_INTEGER);
     return strtoll(this->value_.c_str(), NULL, 0);
   }
 
@@ -274,16 +301,21 @@ class Lex
 void
 Lex::read_file(std::string* contents)
 {
+  off_t filesize = this->input_file_->file().filesize();
   contents->clear();
+  contents->reserve(filesize);
+
   off_t off = 0;
-  off_t got;
   unsigned char buf[BUFSIZ];
-  do
+  while (off < filesize)
     {
-      this->input_file_->file().read(off, sizeof buf, buf, &got);
-      contents->append(reinterpret_cast<char*>(&buf[0]), got);
+      off_t get = BUFSIZ;
+      if (get > filesize - off)
+       get = filesize - off;
+      this->input_file_->file().read(off, get, buf);
+      contents->append(reinterpret_cast<char*>(&buf[0]), get);
+      off += get;
     }
-  while (got == sizeof buf);
 }
 
 // Return whether C can be the start of a name, if the next character
@@ -797,10 +829,10 @@ class Parser_closure
  public:
   Parser_closure(const char* filename,
                 const Position_dependent_options& posdep_options,
-                bool in_group,
+                bool in_group, bool is_in_sysroot,
                 const Lex::Token_sequence* tokens)
     : filename_(filename), posdep_options_(posdep_options),
-      in_group_(in_group), tokens_(tokens),
+      in_group_(in_group), is_in_sysroot_(is_in_sysroot), tokens_(tokens),
       next_token_index_(0), inputs_(NULL)
   { }
 
@@ -820,6 +852,12 @@ class Parser_closure
   in_group() const
   { return this->in_group_; }
 
+  // Return whether this script was found using a directory in the
+  // sysroot.
+  bool
+  is_in_sysroot() const
+  { return this->is_in_sysroot_; }
+
   // Whether we are at the end of the token list.
   bool
   at_eof() const
@@ -856,6 +894,8 @@ class Parser_closure
   Position_dependent_options posdep_options_;
   // Whether we are currently in a --start-group/--end-group.
   bool in_group_;
+  // Whether the script was found in a sysrooted directory.
+  bool is_in_sysroot_;
 
   // The tokens to be returned by the lexer.
   const Lex::Token_sequence* tokens_;
@@ -885,6 +925,7 @@ read_input_script(Workqueue* workqueue, const General_options& options,
   Parser_closure closure(input_file->filename().c_str(),
                         input_argument->file().options(),
                         input_group != NULL,
+                        input_file->is_in_sysroot(),
                         &lex.tokens());
 
   if (yyparse(&closure) != 0)
@@ -1097,7 +1138,7 @@ yylex(YYSTYPE* lvalp, void* closurev)
     default:
     case Token::TOKEN_INVALID:
     case Token::TOKEN_EOF:
-      abort();
+      gold_unreachable();
 
     case Token::TOKEN_STRING:
       {
@@ -1136,7 +1177,39 @@ extern "C" void
 script_add_file(void* closurev, const char* name)
 {
   Parser_closure* closure = static_cast<Parser_closure*>(closurev);
-  Input_file_argument file(name, false, closure->position_dependent_options());
+
+  // If this is an absolute path, and we found the script in the
+  // sysroot, then we want to prepend the sysroot to the file name.
+  // For example, this is how we handle a cross link to the x86_64
+  // libc.so, which refers to /lib/libc.so.6.
+  std::string name_string;
+  const char* extra_search_path = ".";
+  std::string script_directory;
+  if (IS_ABSOLUTE_PATH (name))
+    {
+      if (closure->is_in_sysroot())
+       {
+         const std::string& sysroot(parameters->sysroot());
+         gold_assert(!sysroot.empty());
+         name_string = sysroot + name;
+         name = name_string.c_str();
+       }
+    }
+  else
+    {
+      // In addition to checking the normal library search path, we
+      // also want to check in the script-directory.
+      const char *slash = strrchr(closure->filename(), '/');
+      if (slash != NULL)
+       {
+         script_directory.assign(closure->filename(),
+                                 slash - closure->filename() + 1);
+         extra_search_path = script_directory.c_str();
+       }
+    }
+
+  Input_file_argument file(name, false, extra_search_path,
+                          closure->position_dependent_options());
   closure->inputs()->add_file(file);
 }