Home | History | Annotate | Download | only in lib
      1 //===- TripleOptions.cpp --------------------------------------------------===//
      2 //
      3 //                     The MCLinker Project
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 #include <mcld/TripleOptions.h>
     10 
     11 #include <mcld/LinkerConfig.h>
     12 #include <mcld/Support/Path.h>
     13 #include <mcld/Support/TargetRegistry.h>
     14 #include <mcld/Support/MsgHandling.h>
     15 #include <mcld/Support/SystemUtils.h>
     16 
     17 #include <llvm/ADT/StringSwitch.h>
     18 #include <llvm/MC/SubtargetFeature.h>
     19 
     20 namespace {
     21 
     22 llvm::cl::opt<std::string> ArgTargetTriple("mtriple",
     23                            llvm::cl::desc("Override target triple for module"));
     24 
     25 llvm::cl::opt<std::string> ArgMArch("march",
     26            llvm::cl::desc("Architecture to generate code for (see --version)"));
     27 
     28 llvm::cl::opt<std::string> ArgMCPU("mcpu",
     29           llvm::cl::desc("Target a specific cpu type (-mcpu=help for details)"),
     30           llvm::cl::value_desc("cpu-name"),
     31           llvm::cl::init(""));
     32 
     33 llvm::cl::list<std::string> ArgMAttrs("mattr",
     34          llvm::cl::CommaSeparated,
     35          llvm::cl::desc("Target specific attributes (-mattr=help for details)"),
     36          llvm::cl::value_desc("a1,+a2,-a3,..."));
     37 
     38 llvm::cl::opt<std::string> ArgEmulation("m",
     39                                      llvm::cl::ZeroOrMore,
     40                                      llvm::cl::desc("Set GNU linker emulation"),
     41                                      llvm::cl::value_desc("emulation"),
     42                                      llvm::cl::Prefix);
     43 
     44 /// ParseProgName - Parse program name
     45 /// This function simplifies cross-compiling by reading triple from the program
     46 /// name. For example, if the program name is `arm-linux-eabi-ld.mcld', we can
     47 /// get the triple is arm-linux-eabi by the program name.
     48 inline std::string ParseProgName(const char *pProgName)
     49 {
     50   static const char *suffixes[] = {
     51     "ld",
     52     "ld.mcld"
     53   };
     54 
     55   std::string ProgName(mcld::sys::fs::Path(pProgName).stem().native());
     56 
     57   for (size_t i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
     58     if (ProgName == suffixes[i])
     59       return std::string();
     60   }
     61 
     62   llvm::StringRef ProgNameRef(ProgName);
     63   llvm::StringRef Prefix;
     64 
     65   for (size_t i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
     66     if (!ProgNameRef.endswith(suffixes[i]))
     67       continue;
     68 
     69     llvm::StringRef::size_type LastComponent = ProgNameRef.rfind('-',
     70       ProgNameRef.size() - strlen(suffixes[i]));
     71     if (LastComponent == llvm::StringRef::npos)
     72       continue;
     73     llvm::StringRef Prefix = ProgNameRef.slice(0, LastComponent);
     74     std::string IgnoredError;
     75     if (!mcld::TargetRegistry::lookupTarget(Prefix, IgnoredError))
     76       continue;
     77     return Prefix.str();
     78   }
     79   return std::string();
     80 }
     81 
     82 inline void
     83 ParseEmulation(llvm::Triple& pTriple, const std::string& pEmulation)
     84 {
     85   llvm::Triple triple = llvm::StringSwitch<llvm::Triple>(pEmulation)
     86     .Case("aarch64linux",      llvm::Triple("aarch64", "", "linux", "gnu"))
     87     .Case("armelf_linux_eabi", llvm::Triple("arm", "", "linux", "gnueabi"))
     88     .Case("elf_i386",          llvm::Triple("i386", "", "", "gnu"))
     89     .Case("elf_x86_64",        llvm::Triple("x86_64", "", "", "gnu"))
     90     .Case("elf32_x86_64",      llvm::Triple("x86_64", "", "", "gnux32"))
     91     .Case("elf_i386_fbsd",     llvm::Triple("i386", "", "freebsd", "gnu"))
     92     .Case("elf_x86_64_fbsd",   llvm::Triple("x86_64", "", "freebsd", "gnu"))
     93     .Case("elf32ltsmip",       llvm::Triple("mipsel", "", "", "gnu"))
     94     .Default(llvm::Triple());
     95 
     96   if (triple.getArch()        == llvm::Triple::UnknownArch &&
     97       triple.getOS()          == llvm::Triple::UnknownOS &&
     98       triple.getEnvironment() == llvm::Triple::UnknownEnvironment)
     99     mcld::error(mcld::diag::err_invalid_emulation) << pEmulation << "\n";
    100 
    101   if (triple.getArch()        != llvm::Triple::UnknownArch)
    102     pTriple.setArch(triple.getArch());
    103 
    104   if (triple.getOS()          != llvm::Triple::UnknownOS)
    105     pTriple.setOS(triple.getOS());
    106 
    107   if (triple.getEnvironment() != llvm::Triple::UnknownEnvironment)
    108     pTriple.setEnvironment(triple.getEnvironment());
    109 
    110 }
    111 
    112 } // anonymous namespace
    113 
    114 using namespace mcld;
    115 
    116 //===----------------------------------------------------------------------===//
    117 // TripleOptions
    118 //===----------------------------------------------------------------------===//
    119 TripleOptions::TripleOptions()
    120   : m_TargetTriple(ArgTargetTriple),
    121     m_MArch(ArgMArch),
    122     m_MCPU(ArgMCPU),
    123     m_MAttrs(ArgMAttrs),
    124     m_Emulation(ArgEmulation) {
    125 }
    126 
    127 bool TripleOptions::parse(int pArgc, char* pArgv[], LinkerConfig& pConfig)
    128 {
    129   llvm::Triple triple;
    130   if (!m_TargetTriple.empty()) {
    131     // 1. Use the triple from command.
    132     triple.setTriple(m_TargetTriple);
    133   }
    134   else {
    135     std::string prog_triple = ParseProgName(pArgv[0]);
    136     if (!prog_triple.empty()) {
    137       // 2. Use the triple from the program name prefix.
    138       triple.setTriple(prog_triple);
    139     }
    140     else {
    141       // 3. Use the default target triple.
    142       triple.setTriple(mcld::sys::getDefaultTargetTriple());
    143     }
    144   }
    145 
    146   // If a specific emulation was requested, apply it now.
    147   if (!m_Emulation.empty())
    148     ParseEmulation(triple, m_Emulation);
    149   else
    150     pConfig.targets().setArch(m_MArch);
    151 
    152   pConfig.targets().setTriple(triple);
    153   pConfig.targets().setTargetCPU(m_MCPU);
    154 
    155   // Package up features to be passed to target/subtarget
    156   std::string feature_str;
    157   if (m_MAttrs.size()) {
    158     llvm::SubtargetFeatures features;
    159     for (unsigned i = 0; i != m_MAttrs.size(); ++i)
    160       features.AddFeature(m_MAttrs[i]);
    161     feature_str = features.getString();
    162   }
    163   pConfig.targets().setTargetFeatureString(feature_str);
    164   return true;
    165 }
    166 
    167