//===- PositionalOptions.cpp ----------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include <mcld/PositionalOptions.h> #include <mcld/LinkerConfig.h> #include <mcld/LinkerScript.h> #include <mcld/MC/InputAction.h> #include <mcld/MC/CommandAction.h> #include <mcld/MC/FileAction.h> #include <mcld/Support/MsgHandling.h> namespace { //===----------------------------------------------------------------------===// // Normal input files //===----------------------------------------------------------------------===// llvm::cl::list<mcld::sys::fs::Path> ArgInputObjectFiles(llvm::cl::Positional, llvm::cl::desc("[input object files]"), llvm::cl::ZeroOrMore); // --script is an alias, but cl::alias doesn't work correctly with cl::list. llvm::cl::list<std::string> ArgLinkerScript("T", llvm::cl::ZeroOrMore, llvm::cl::desc("Linker script"), llvm::cl::value_desc("file")); //===----------------------------------------------------------------------===// // Namespecs //===----------------------------------------------------------------------===// llvm::cl::list<std::string> ArgNameSpecList("l", llvm::cl::ZeroOrMore, llvm::cl::desc("Add the archive or object file specified by namespec to\n" "the list of files to link."), llvm::cl::value_desc("namespec"), llvm::cl::Prefix); llvm::cl::alias ArgNameSpecListAlias("library", llvm::cl::desc("alias for -l"), llvm::cl::aliasopt(ArgNameSpecList)); //===----------------------------------------------------------------------===// // Attributes //===----------------------------------------------------------------------===// llvm::cl::list<bool> ArgWholeArchiveList("whole-archive", llvm::cl::ValueDisallowed, llvm::cl::desc("For each archive mentioned on the command line after\n" "the --whole-archive option, include all object files\n" "in the archive.")); llvm::cl::list<bool> ArgNoWholeArchiveList("no-whole-archive", llvm::cl::ValueDisallowed, llvm::cl::desc("Turn off the effect of the --whole-archive option for\n" "subsequent archive files.")); llvm::cl::list<bool> ArgAsNeededList("as-needed", llvm::cl::ValueDisallowed, llvm::cl::desc("This option affects ELF DT_NEEDED tags for dynamic\n" "libraries mentioned on the command line after the\n" "--as-needed option.")); llvm::cl::list<bool> ArgNoAsNeededList("no-as-needed", llvm::cl::ValueDisallowed, llvm::cl::desc("Turn off the effect of the --as-needed option for\n" "subsequent dynamic libraries")); llvm::cl::list<bool> ArgAddNeededList("add-needed", llvm::cl::ValueDisallowed, llvm::cl::desc("--add-needed causes DT_NEEDED tags are always\n" "emitted for those libraries from DT_NEEDED tags.\n" "This is the default behavior.")); llvm::cl::list<bool> ArgNoAddNeededList("no-add-needed", llvm::cl::ValueDisallowed, llvm::cl::desc("--no-add-needed causes DT_NEEDED tags will never be\n" "emitted for those libraries from DT_NEEDED tags")); llvm::cl::list<bool> ArgBDynamicList("Bdynamic", llvm::cl::ValueDisallowed, llvm::cl::desc("Link against dynamic library")); llvm::cl::alias ArgBDynamicListAlias1("dy", llvm::cl::desc("alias for --Bdynamic"), llvm::cl::aliasopt(ArgBDynamicList)); llvm::cl::alias ArgBDynamicListAlias2("call_shared", llvm::cl::desc("alias for --Bdynamic"), llvm::cl::aliasopt(ArgBDynamicList)); llvm::cl::list<bool> ArgBStaticList("Bstatic", llvm::cl::ValueDisallowed, llvm::cl::desc("Link against static library")); llvm::cl::alias ArgBStaticListAlias1("dn", llvm::cl::desc("alias for --Bstatic"), llvm::cl::aliasopt(ArgBStaticList)); llvm::cl::alias ArgBStaticListAlias2("static", llvm::cl::desc("alias for --Bstatic"), llvm::cl::aliasopt(ArgBStaticList)); llvm::cl::alias ArgBStaticListAlias3("non_shared", llvm::cl::desc("alias for --Bstatic"), llvm::cl::aliasopt(ArgBStaticList)); //===----------------------------------------------------------------------===// // Groups //===----------------------------------------------------------------------===// llvm::cl::list<bool> ArgStartGroupList("start-group", llvm::cl::ValueDisallowed, llvm::cl::desc("start to record a group of archives")); llvm::cl::alias ArgStartGroupListAlias("(", llvm::cl::desc("alias for --start-group"), llvm::cl::aliasopt(ArgStartGroupList)); llvm::cl::list<bool> ArgEndGroupList("end-group", llvm::cl::ValueDisallowed, llvm::cl::desc("stop recording a group of archives")); llvm::cl::alias ArgEndGroupListAlias(")", llvm::cl::desc("alias for --end-group"), llvm::cl::aliasopt(ArgEndGroupList)); //===----------------------------------------------------------------------===// // --defsym //===----------------------------------------------------------------------===// llvm::cl::list<std::string> ArgDefSymList("defsym", llvm::cl::ZeroOrMore, llvm::cl::desc("Define a symbol"), llvm::cl::value_desc("symbol=expression")); //===----------------------------------------------------------------------===// // Help Functions //===----------------------------------------------------------------------===// inline bool CompareAction(const mcld::InputAction* X, const mcld::InputAction* Y) { return (X->position() < Y->position()); } } // anonymous namespace using namespace mcld; //===----------------------------------------------------------------------===// // PositionalOptions //===----------------------------------------------------------------------===// PositionalOptions::PositionalOptions() : m_InputObjectFiles(ArgInputObjectFiles), m_LinkerScript(ArgLinkerScript), m_NameSpecList(ArgNameSpecList), m_WholeArchiveList(ArgWholeArchiveList), m_NoWholeArchiveList(ArgNoWholeArchiveList), m_AsNeededList(ArgAsNeededList), m_NoAsNeededList(ArgNoAsNeededList), m_AddNeededList(ArgAddNeededList), m_NoAddNeededList(ArgNoAddNeededList), m_BDynamicList(ArgBDynamicList), m_BStaticList(ArgBStaticList), m_StartGroupList(ArgStartGroupList), m_EndGroupList(ArgEndGroupList), m_DefSymList(ArgDefSymList) { } size_t PositionalOptions::numOfActions() const { return m_InputObjectFiles.size() + m_LinkerScript.size() + m_NameSpecList.size() + m_WholeArchiveList.size() + m_NoWholeArchiveList.size() + m_AsNeededList.size() + m_NoAsNeededList.size() + m_AddNeededList.size() + m_NoAddNeededList.size() + m_BDynamicList.size() + m_BStaticList.size() + m_StartGroupList.size() + m_EndGroupList.size() + m_DefSymList.size(); } size_t PositionalOptions::numOfInputs() const { return (m_InputObjectFiles.size() + m_LinkerScript.size() + m_NameSpecList.size()); } bool PositionalOptions::parse(std::vector<InputAction*>& pActions, const LinkerConfig& pConfig, const LinkerScript& pScript) { if (0 == numOfInputs()) { fatal(diag::err_no_inputs); return false; } pActions.reserve(numOfActions()); // -T/--script // FIXME: llvm::cl::list<std::string>::iterator sp; llvm::cl::list<std::string>::iterator spEnd = m_LinkerScript.end(); for (sp = m_LinkerScript.begin(); sp != spEnd; ++sp) { pActions.push_back(new ScriptAction(0x0, *sp, ScriptFile::LDScript, pScript.directories())); pActions.push_back(new ContextAction(0x0)); pActions.push_back(new MemoryAreaAction(0x0, FileHandle::ReadOnly)); } // --defsym llvm::cl::list<std::string>::iterator defsym, dsBegin, dsEnd; dsBegin = m_DefSymList.begin(); dsEnd = m_DefSymList.end(); for (defsym = dsBegin; defsym != dsEnd; ++defsym) { unsigned int pos = m_DefSymList.getPosition(defsym - dsBegin); pActions.push_back(new DefSymAction(pos, *defsym)); } // set input llvm::cl::list<mcld::sys::fs::Path>::iterator input, inBegin, inEnd; inBegin = m_InputObjectFiles.begin(); inEnd = m_InputObjectFiles.end(); for (input = inBegin; input != inEnd; ++input) { unsigned int pos = m_InputObjectFiles.getPosition(input - inBegin); pActions.push_back(new InputFileAction(pos, *input)); pActions.push_back(new ContextAction(pos)); pActions.push_back(new MemoryAreaAction(pos, FileHandle::ReadOnly)); } // set -l[namespec] llvm::cl::list<std::string>::iterator namespec, nsBegin, nsEnd; nsBegin = m_NameSpecList.begin(); nsEnd = m_NameSpecList.end(); for (namespec = nsBegin; namespec != nsEnd; ++namespec) { unsigned int pos = m_NameSpecList.getPosition(namespec - nsBegin); pActions.push_back(new NamespecAction(pos, *namespec, pScript.directories())); pActions.push_back(new ContextAction(pos)); pActions.push_back(new MemoryAreaAction(pos, FileHandle::ReadOnly)); } // set --whole-archive llvm::cl::list<bool>::iterator attr, attrBegin, attrEnd; attrBegin = m_WholeArchiveList.begin(); attrEnd = m_WholeArchiveList.end(); for (attr = attrBegin; attr != attrEnd; ++attr) { unsigned int pos = m_WholeArchiveList.getPosition(attr - attrBegin); pActions.push_back(new WholeArchiveAction(pos)); } // set --no-whole-archive attrBegin = m_NoWholeArchiveList.begin(); attrEnd = m_NoWholeArchiveList.end(); for (attr = attrBegin; attr != attrEnd; ++attr) { unsigned int pos = m_NoWholeArchiveList.getPosition(attr - attrBegin); pActions.push_back(new NoWholeArchiveAction(pos)); } // set --as-needed attrBegin = m_AsNeededList.begin(); attrEnd = m_AsNeededList.end(); for (attr = attrBegin; attr != attrEnd; ++attr) { unsigned int pos = m_AsNeededList.getPosition(attr - attrBegin); pActions.push_back(new AsNeededAction(pos)); } // set --no-as-needed attrBegin = m_NoAsNeededList.begin(); attrEnd = m_NoAsNeededList.end(); for (attr = attrBegin; attr != attrEnd; ++attr) { unsigned int pos = m_NoAsNeededList.getPosition(attr - attrBegin); pActions.push_back(new NoAsNeededAction(pos)); } // set --add--needed attrBegin = m_AddNeededList.begin(); attrEnd = m_AddNeededList.end(); for (attr = attrBegin; attr != attrEnd; ++attr) { unsigned int pos = m_AddNeededList.getPosition(attr - attrBegin); pActions.push_back(new AddNeededAction(pos)); } // set --no-add--needed attrBegin = m_NoAddNeededList.begin(); attrEnd = m_NoAddNeededList.end(); for (attr = attrBegin; attr != attrEnd; ++attr) { unsigned int pos = m_NoAddNeededList.getPosition(attr - attrBegin); pActions.push_back(new NoAddNeededAction(pos)); } // set --Bdynamic attrBegin = m_BDynamicList.begin(); attrEnd = m_BDynamicList.end(); for (attr = attrBegin; attr != attrEnd; ++attr) { unsigned int pos = m_BDynamicList.getPosition(attr - attrBegin); pActions.push_back(new BDynamicAction(pos)); } // set --Bstatic attrBegin = m_BStaticList.begin(); attrEnd = m_BStaticList.end(); for (attr = attrBegin; attr != attrEnd; ++attr) { unsigned int pos = m_BStaticList.getPosition(attr - attrBegin); pActions.push_back(new BStaticAction(pos)); } // set --start-group llvm::cl::list<bool>::iterator group, gsBegin, gsEnd; gsBegin = m_StartGroupList.begin(); gsEnd = m_StartGroupList.end(); for (group = gsBegin; group != gsEnd; ++group) { unsigned int pos = m_StartGroupList.getPosition(group - gsBegin); pActions.push_back(new StartGroupAction(pos)); } // set --end-group gsBegin = m_EndGroupList.begin(); gsEnd = m_EndGroupList.end(); for (group = gsBegin; group != gsEnd; ++group) { unsigned int pos = m_EndGroupList.getPosition(group - gsBegin); pActions.push_back(new EndGroupAction(pos)); } // stable sort std::stable_sort(pActions.begin(), pActions.end(), CompareAction); return true; }