//===- GroupReader.cpp ----------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include <mcld/LD/Archive.h> #include <mcld/LD/ArchiveReader.h> #include <mcld/LD/DynObjReader.h> #include <mcld/LD/GroupReader.h> #include <mcld/LD/ObjectReader.h> #include <mcld/LD/BinaryReader.h> #include <mcld/LinkerConfig.h> #include <mcld/MC/Attribute.h> #include <mcld/Support/MsgHandling.h> using namespace mcld; GroupReader::GroupReader(Module& pModule, ObjectReader& pObjectReader, DynObjReader& pDynObjReader, ArchiveReader& pArchiveReader, BinaryReader& pBinaryReader) : m_Module(pModule), m_ObjectReader(pObjectReader), m_DynObjReader(pDynObjReader), m_ArchiveReader(pArchiveReader), m_BinaryReader(pBinaryReader) { } GroupReader::~GroupReader() { } bool GroupReader::readGroup(Module::input_iterator pRoot, InputBuilder& pBuilder, const LinkerConfig& pConfig) { // record the number of total objects included in this sub-tree size_t cur_obj_cnt = 0; size_t last_obj_cnt = 0; size_t non_ar_obj_cnt = 0; // record the archive files in this sub-tree typedef std::vector<ArchiveListEntry*> ArchiveListType; ArchiveListType ar_list; Module::input_iterator input = --pRoot; // Since the end of a sub-tree is the same node to the end of whole tree, we // take the end of the whole input tree for conventience. Module::input_iterator input_end = m_Module.input_end(); // first time read the sub-tree while (input != input_end) { // already got type - for example, bitcode or external OIR (object // intermediate representation) if ((*input)->type() == Input::Script || (*input)->type() == Input::Archive || (*input)->type() == Input::External) { ++input; continue; } if (Input::Object == (*input)->type()) { m_Module.getObjectList().push_back(*input); continue; } if (Input::DynObj == (*input)->type()) { m_Module.getLibraryList().push_back(*input); continue; } // is an archive if (m_ArchiveReader.isMyFormat(**input)) { (*input)->setType(Input::Archive); // record the Archive used by each archive node Archive* ar = new Archive(**input, pBuilder); ArchiveListEntry* entry = new ArchiveListEntry(*ar, input); ar_list.push_back(entry); // read archive m_ArchiveReader.readArchive(*ar); cur_obj_cnt += ar->numOfObjectMember(); } // read input as a binary file else if (pConfig.options().isBinaryInput()) { (*input)->setType(Input::Object); m_BinaryReader.readBinary(**input); m_Module.getObjectList().push_back(*input); } // is a relocatable object file else if (m_ObjectReader.isMyFormat(**input)) { (*input)->setType(Input::Object); m_ObjectReader.readHeader(**input); m_ObjectReader.readSections(**input); m_ObjectReader.readSymbols(**input); m_Module.getObjectList().push_back(*input); ++cur_obj_cnt; ++non_ar_obj_cnt; } // is a shared object file else if (m_DynObjReader.isMyFormat(**input)) { (*input)->setType(Input::DynObj); m_DynObjReader.readHeader(**input); m_DynObjReader.readSymbols(**input); m_Module.getLibraryList().push_back(*input); } else { fatal(diag::err_unrecognized_input_file) << (*input)->path() << pConfig.targets().triple().str(); } ++input; } // after read in all the archives, traverse the archive list in a loop until // there is no unresolved symbols added ArchiveListType::iterator it = ar_list.begin(); ArchiveListType::iterator end = ar_list.end(); while (cur_obj_cnt != last_obj_cnt) { last_obj_cnt = cur_obj_cnt; cur_obj_cnt = non_ar_obj_cnt; for (it = ar_list.begin(); it != end; ++it) { Archive& ar = (*it)->archive; // if --whole-archive is given to this archive, no need to read it again if ( ar.getARFile().attribute()->isWholeArchive()) continue; m_ArchiveReader.readArchive(ar); cur_obj_cnt += ar.numOfObjectMember(); } } // after all needed member included, merge the archive sub-tree to main // InputTree for (it = ar_list.begin(); it != end; ++it) { Archive& ar = (*it)->archive; if (ar.numOfObjectMember() > 0) { m_Module.getInputTree().merge<InputTree::Inclusive>((*it)->input, ar.inputs()); } } // cleanup ar_list for (it = ar_list.begin(); it != end; ++it) { delete &((*it)->archive); delete (*it); } ar_list.clear(); return true; }