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