• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
ParseProgName(const char * pProgName)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
ParseEmulation(llvm::Triple & pTriple,const std::string & pEmulation)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 //===----------------------------------------------------------------------===//
TripleOptions()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 
parse(int pArgc,char * pArgv[],LinkerConfig & pConfig)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