Implement --whole-archive.
authorIan Lance Taylor <iant@google.com>
Tue, 21 Aug 2007 23:37:56 +0000 (23:37 +0000)
committerIan Lance Taylor <iant@google.com>
Tue, 21 Aug 2007 23:37:56 +0000 (23:37 +0000)
gold/archive.cc
gold/archive.h
gold/fileread.h
gold/options.cc
gold/options.h

index d0854036a6728b895b38dea3a640f7813b9e7476..51a0f484453c052c6a4b9ea85d1a1d81cab02422 100644 (file)
@@ -57,16 +57,45 @@ Archive::setup()
   // The first member of the archive should be the symbol table.
   std::string armap_name;
   off_t armap_size = this->read_header(sarmag, &armap_name);
-  if (!armap_name.empty())
+  off_t off;
+  if (armap_name.empty())
+    {
+      this->read_armap(sarmag + sizeof(Archive_header), armap_size);
+      off = sarmag + sizeof(Archive_header) + armap_size;
+    }
+  else if (!this->input_file_->options().include_whole_archive())
     {
       fprintf(stderr, _("%s: %s: no archive symbol table (run ranlib)\n"),
              program_name, this->name().c_str());
       gold_exit(false);
     }
+  else
+    off = sarmag;
+
+  // See if there is an extended name table.
+  if ((off & 1) != 0)
+    ++off;
+  std::string xname;
+  off_t extended_size = this->read_header(off, &xname);
+  if (xname == "/")
+    {
+      const unsigned char* p = this->get_view(off + sizeof(Archive_header),
+                                              extended_size);
+      const char* px = reinterpret_cast<const char*>(p);
+      this->extended_names_.assign(px, extended_size);
+    }
+
+  // Opening the file locked it.  Unlock it now.
+  this->input_file_->file().unlock();
+}
 
+// Read the archive symbol map.
+
+void
+Archive::read_armap(off_t start, off_t size)
+{
   // Read in the entire armap.
-  const unsigned char* p = this->get_view(sarmag + sizeof(Archive_header),
-                                         armap_size);
+  const unsigned char* p = this->get_view(start, size);
 
   // Numbers in the armap are always big-endian.
   const elfcpp::Elf_Word* pword = reinterpret_cast<const elfcpp::Elf_Word*>(p);
@@ -86,32 +115,16 @@ Archive::setup()
       ++pword;
     }
 
-  if (reinterpret_cast<const unsigned char*>(pnames) - p > armap_size)
+  if (reinterpret_cast<const unsigned char*>(pnames) - p > size)
     {
       fprintf(stderr, _("%s: %s: bad archive symbol table names\n"),
              program_name, this->name().c_str());
       gold_exit(false);
     }
 
-  // See if there is an extended name table.
-  off_t off = sarmag + sizeof(Archive_header) + armap_size;
-  if ((off & 1) != 0)
-    ++off;
-  std::string xname;
-  off_t extended_size = this->read_header(off, &xname);
-  if (xname == "/")
-    {
-      p = this->get_view(off + sizeof(Archive_header), extended_size);
-      const char* px = reinterpret_cast<const char*>(p);
-      this->extended_names_.assign(px, extended_size);
-    }
-
   // This array keeps track of which symbols are for archive elements
   // which we have already included in the link.
   this->seen_.resize(nsyms);
-
-  // Opening the file locked it.  Unlock it now.
-  this->input_file_->file().unlock();
 }
 
 // Read the header of an archive member at OFF.  Fail if something
@@ -123,7 +136,17 @@ Archive::read_header(off_t off, std::string* pname)
 {
   const unsigned char* p = this->get_view(off, sizeof(Archive_header));
   const Archive_header* hdr = reinterpret_cast<const Archive_header*>(p);
+  return this->interpret_header(hdr, off,  pname);
+}
 
+// Interpret the header of HDR, the header of the archive member at
+// file offset OFF.  Fail if something goes wrong.  Return the size of
+// the member.  Set *PNAME to the name of the member.
+
+off_t
+Archive::interpret_header(const Archive_header* hdr, off_t off,
+                          std::string* pname)
+{
   if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
     {
       fprintf(stderr, _("%s; %s: malformed archive header at %ld\n"),
@@ -218,6 +241,9 @@ void
 Archive::add_symbols(const General_options& options, Symbol_table* symtab,
                     Layout* layout, Input_objects* input_objects)
 {
+  if (this->input_file_->options().include_whole_archive())
+    return this->include_all_members(options, symtab, layout, input_objects);
+
   const size_t armap_size = this->armap_.size();
 
   bool added_new_object;
@@ -256,6 +282,52 @@ Archive::add_symbols(const General_options& options, Symbol_table* symtab,
   while (added_new_object);
 }
 
+// Include all the archive members in the link.  This is for --whole-archive.
+
+void
+Archive::include_all_members(const General_options& options,
+                             Symbol_table* symtab, Layout* layout,
+                             Input_objects* input_objects)
+{
+  off_t off = sarmag;
+  while (true)
+    {
+      off_t bytes;
+      const unsigned char* p = this->get_view(off, sizeof(Archive_header),
+                                              &bytes);
+      if (bytes < sizeof(Archive_header))
+        {
+          if (bytes != 0)
+            {
+              fprintf(stderr, _("%s: %s: short archive header at %ld\n"),
+                      program_name, this->name().c_str(),
+                      static_cast<long>(off));
+              gold_exit(false);
+            }
+
+          break;
+        }
+
+      const Archive_header* hdr = reinterpret_cast<const Archive_header*>(p);
+      std::string name;
+      off_t size = this->interpret_header(hdr, off, &name);
+      if (name.empty())
+        {
+          // Symbol table.
+        }
+      else if (name == "/")
+        {
+          // Extended name table.
+        }
+      else
+        this->include_member(options, symtab, layout, input_objects, off);
+
+      off += sizeof(Archive_header) + size;
+      if ((off & 1) != 0)
+        ++off;
+    }
+}
+
 // Include an archive member in the link.  OFF is the file offset of
 // the member header.
 
@@ -339,7 +411,7 @@ class Add_archive_symbols::Add_archive_symbols_locker : public Task_locker
 
  private:
   Task_locker_block blocker_;
-  Task_locker_obj<File_read> filelock_;                             
+  Task_locker_obj<File_read> filelock_;
 };
 
 Task_locker*
@@ -354,7 +426,7 @@ void
 Add_archive_symbols::run(Workqueue*)
 {
   this->archive_->add_symbols(this->options_, this->symtab_, this->layout_,
-                             this->input_objects_);
+                              this->input_objects_);
 
   if (this->input_group_ != NULL)
     this->input_group_->add_archive(this->archive_);
index 193a9e2de8203e00a9e94bc0457a62e13685cb43..ddd665f070c4800b0ce8cab36001aa0c2fa0a04c 100644 (file)
@@ -79,14 +79,28 @@ class Archive
 
   // Get a view into the underlying file.
   const unsigned char*
-  get_view(off_t start, off_t size)
-  { return this->input_file_->file().get_view(start, size); }
+  get_view(off_t start, off_t size, off_t* pbytes = NULL)
+  { return this->input_file_->file().get_view(start, size, pbytes); }
+
+  // Read the archive symbol map.
+  void
+  read_armap(off_t start, off_t size);
 
   // Read an archive member header at OFF.  Return the size of the
   // member, and set *PNAME to the name.
   off_t
   read_header(off_t off, std::string* pname);
 
+  // Interpret an archive header HDR at OFF.  Return the size of the
+  // member, and set *PNAME to the name.
+  off_t
+  interpret_header(const Archive_header* hdr, off_t off, std::string* pname);
+
+  // Include all the archive members in the link.
+  void
+  include_all_members(const General_options&, Symbol_table*, Layout*,
+                      Input_objects*);
+
   // Include an archive member in the link.
   void
   include_member(const General_options&, Symbol_table*, Layout*,
index 178e7f355e446f2afb8678f8bfb679596aa27234..f3ac753b140ec780e48485785d790d3af5843b71 100644 (file)
@@ -55,7 +55,7 @@ class File_read
   // Unlock the descriptor, permitting it to be closed if necessary.
   void
   unlock();
-  
+
   // Test whether the object is locked.
   bool
   is_locked();
@@ -65,12 +65,12 @@ class File_read
   // we can not read enough data.  Otherwise *PBYTES is set to the
   // number of bytes read.
   const unsigned char*
-  get_view(off_t start, off_t size, off_t *pbytes = NULL);
+  get_view(off_t start, off_t size, off_tpbytes = NULL);
 
   // Read data from the file into the buffer P.  PBYTES is as in
   // get_view.
   void
-  read(off_t start, off_t size, void* p, off_t *pbytes = NULL);
+  read(off_t start, off_t size, void* p, off_tpbytes = NULL);
 
   // Return a lasting view into the file.  This is allocated with new,
   // and the caller is responsible for deleting it when done.  The
@@ -240,6 +240,12 @@ class Input_file
   filename() const
   { return this->file_.filename(); }
 
+  // Return the position dependent options.
+  const Position_dependent_options&
+  options() const
+  { return this->input_argument_->options(); }
+
+  // Return the file.
   File_read&
   file()
   { return this->file_; }
index 36e0044c2334e9ffee170962f72791ee1cdd10a9..0b858a2e0ceb1bd487784a90e31985d1b96f26ea 100644 (file)
@@ -257,6 +257,14 @@ options::Command_line_options::options[] =
   POSDEP_NOARG('\0', "no-as-needed",
               N_("Always DT_NEEDED for following dynamic libs (default)"),
               NULL, TWO_DASHES, &Position_dependent_options::clear_as_needed),
+  POSDEP_NOARG('\0', "whole-archive",
+               N_("Include all archive contents"),
+               NULL, TWO_DASHES,
+               &Position_dependent_options::set_whole_archive),
+  POSDEP_NOARG('\0', "no-whole-archive",
+               N_("Include only needed archive contents"),
+               NULL, TWO_DASHES,
+               &Position_dependent_options::clear_whole_archive),
   SPECIAL('\0', "help", N_("Report usage information"), NULL,
          TWO_DASHES, &help)
 };
@@ -271,6 +279,7 @@ General_options::General_options()
     search_path_(),
     output_file_name_("a.out"),
     is_relocatable_(false),
+    rpath_(),
     is_shared_(false),
     is_static_(false)
 {
@@ -279,7 +288,9 @@ General_options::General_options()
 // The default values for the position dependent options.
 
 Position_dependent_options::Position_dependent_options()
-  : do_static_search_(false)
+  : do_static_search_(false),
+    as_needed_(false),
+    include_whole_archive_(false)
 {
 }
 
index dc38b2f1c7967972fbca6d12f20e49ceae0d5a8a..3c13deb0b034477306d763ead7aaf8df06dacd8e 100644 (file)
@@ -142,6 +142,12 @@ class Position_dependent_options
   as_needed() const
   { return this->as_needed_; }
 
+  // --whole-archive: Whether to include the entire contents of an
+  // --archive.
+  bool
+  include_whole_archive() const
+  { return this->include_whole_archive_; }
+
   void
   set_static_search()
   { this->do_static_search_ = true; }
@@ -158,9 +164,18 @@ class Position_dependent_options
   clear_as_needed()
   { this->as_needed_ = false; }
 
+  void
+  set_whole_archive()
+  { this->include_whole_archive_ = true; }
+
+  void
+  clear_whole_archive()
+  { this->include_whole_archive_ = false; }
+
  private:
   bool do_static_search_;
   bool as_needed_;
+  bool include_whole_archive_;
 };
 
 // A single file or library argument from the command line.