TripleOptions.cpp revision 533eae20118036f425f27bf0536ef0ccbb090b65
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
20namespace {
21
22llvm::cl::opt<std::string> ArgTargetTriple("mtriple",
23                           llvm::cl::desc("Override target triple for module"));
24
25llvm::cl::opt<std::string> ArgMArch("march",
26           llvm::cl::desc("Architecture to generate code for (see --version)"));
27
28llvm::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
33llvm::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
38llvm::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.
48inline 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
82inline void
83ParseEmulation(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
114using namespace mcld;
115
116//===----------------------------------------------------------------------===//
117// TripleOptions
118//===----------------------------------------------------------------------===//
119TripleOptions::TripleOptions()
120  : m_TargetTriple(ArgTargetTriple),
121    m_MArch(ArgMArch),
122    m_MCPU(ArgMCPU),
123    m_MAttrs(ArgMAttrs),
124    m_Emulation(ArgEmulation) {
125}
126
127bool 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