1//===- OutputFormatOptions.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/OutputFormatOptions.h>
10#include <mcld/Module.h>
11#include <mcld/Support/MsgHandling.h>
12
13namespace {
14
15llvm::cl::opt<mcld::sys::fs::Path,
16              false,
17              llvm::cl::parser<mcld::sys::fs::Path> > ArgOutputFilename("o",
18  llvm::cl::desc("Output filename"),
19  llvm::cl::value_desc("filename"));
20
21llvm::cl::alias AliasOutputFilename("output",
22  llvm::cl::desc("alias for -o"),
23  llvm::cl::aliasopt(ArgOutputFilename));
24
25llvm::cl::opt<mcld::LinkerConfig::CodeGenType> ArgFileType("filetype",
26  llvm::cl::init(mcld::LinkerConfig::Exec),
27  llvm::cl::desc("Choose a file type\n"
28                 "(not all types are supported by all targets):"),
29  llvm::cl::values(
30       clEnumValN(mcld::LinkerConfig::Object, "obj",
31                  "Emit a relocatable object ('.o') file"),
32       clEnumValN(mcld::LinkerConfig::DynObj, "dso",
33                  "Emit an dynamic shared object ('.so') file"),
34       clEnumValN(mcld::LinkerConfig::Exec, "exe",
35                  "Emit an executable ('.exe') file"),
36       clEnumValN(mcld::LinkerConfig::Binary, "bin",
37                  "Emit a binary file"),
38       clEnumValN(mcld::LinkerConfig::External, "null",
39                  "Emit nothing for performance testing"),
40       clEnumValEnd));
41
42llvm::cl::opt<mcld::LinkerConfig::CodeGenType> ArgOFormat("oformat",
43  llvm::cl::value_desc("Format"),
44  llvm::cl::desc("set output format"),
45  llvm::cl::init(mcld::LinkerConfig::Unknown),
46  llvm::cl::values(
47    clEnumValN(mcld::LinkerConfig::Binary, "binary",
48      "generate binary machine code."),
49    clEnumValEnd));
50
51llvm::cl::opt<bool> ArgShared("shared",
52  llvm::cl::ZeroOrMore,
53  llvm::cl::desc("Create a shared library."),
54  llvm::cl::init(false));
55
56llvm::cl::alias ArgSharedAlias("Bshareable",
57  llvm::cl::desc("alias for -shared"),
58  llvm::cl::aliasopt(ArgShared));
59
60llvm::cl::opt<bool> ArgPIE("pie",
61  llvm::cl::desc("Emit a position-independent executable file"),
62  llvm::cl::init(false));
63
64llvm::cl::opt<bool> ArgRelocatable("relocatable",
65  llvm::cl::desc("Generate relocatable output"),
66  llvm::cl::init(false));
67
68llvm::cl::alias ArgRelocatableAlias("r",
69  llvm::cl::desc("alias for --relocatable"),
70  llvm::cl::aliasopt(ArgRelocatable));
71
72llvm::cl::opt<mcld::Input::Type> ArgFormat("b",
73  llvm::cl::value_desc("Format"),
74  llvm::cl::desc("set input format"),
75  llvm::cl::init(mcld::Input::Unknown),
76  llvm::cl::values(
77    clEnumValN(mcld::Input::Binary, "binary",
78      "read in binary machine code."),
79    clEnumValEnd));
80
81llvm::cl::alias ArgFormatAlias("format",
82  llvm::cl::desc("alias for -b"),
83  llvm::cl::aliasopt(ArgFormat));
84
85llvm::cl::opt<bool> ArgStripDebug("strip-debug",
86  llvm::cl::desc("Omit debugger symbol information from the output file."),
87  llvm::cl::init(false));
88
89llvm::cl::alias ArgStripDebugAlias("S",
90  llvm::cl::desc("alias for --strip-debug"),
91  llvm::cl::aliasopt(ArgStripDebug));
92
93llvm::cl::opt<bool> ArgStripAll("strip-all",
94  llvm::cl::desc("Omit all symbol information from the output file."),
95  llvm::cl::init(false));
96
97llvm::cl::alias ArgStripAllAlias("s",
98  llvm::cl::desc("alias for --strip-all"),
99  llvm::cl::aliasopt(ArgStripAll));
100
101llvm::cl::opt<bool> ArgDiscardAll("discard-all",
102  llvm::cl::desc("Delete all local symbols."),
103  llvm::cl::init(false));
104
105llvm::cl::alias ArgDiscardAllAlias("x",
106  llvm::cl::desc("alias for --discard-all"),
107  llvm::cl::aliasopt(ArgDiscardAll));
108
109llvm::cl::opt<bool> ArgDiscardLocals("discard-locals",
110  llvm::cl::desc("Delete all temporary local symbols."),
111  llvm::cl::init(false));
112
113llvm::cl::alias ArgDiscardLocalsAlias("X",
114  llvm::cl::desc("alias for --discard-locals"),
115  llvm::cl::aliasopt(ArgDiscardLocals));
116
117llvm::cl::opt<bool> ArgEhFrameHdr("eh-frame-hdr",
118  llvm::cl::ZeroOrMore,
119  llvm::cl::desc("Request creation of \".eh_frame_hdr\" section and\n"
120                 "ELF \"PT_GNU_EH_FRAME\" segment header."),
121  llvm::cl::init(false));
122
123llvm::cl::opt<bool> ArgNMagic("nmagic",
124  llvm::cl::desc("Do not page align data"),
125  llvm::cl::init(false));
126
127llvm::cl::alias ArgNMagicAlias("n",
128  llvm::cl::desc("alias for --nmagic"),
129  llvm::cl::aliasopt(ArgNMagic));
130
131llvm::cl::opt<bool> ArgOMagic("omagic",
132  llvm::cl::desc("Do not page align data, do not make text readonly"),
133  llvm::cl::init(false));
134
135llvm::cl::alias ArgOMagicAlias("N",
136  llvm::cl::desc("alias for --omagic"),
137  llvm::cl::aliasopt(ArgOMagic));
138
139llvm::cl::opt<mcld::GeneralOptions::HashStyle> ArgHashStyle("hash-style",
140  llvm::cl::init(mcld::GeneralOptions::SystemV),
141  llvm::cl::desc("Set the type of linker's hash table(s)."),
142  llvm::cl::values(
143       clEnumValN(mcld::GeneralOptions::SystemV, "sysv",
144                 "classic ELF .hash section"),
145       clEnumValN(mcld::GeneralOptions::GNU, "gnu",
146                 "new style GNU .gnu.hash section"),
147       clEnumValN(mcld::GeneralOptions::Both, "both",
148                 "both the classic ELF and new style GNU hash tables"),
149       clEnumValEnd));
150
151llvm::cl::opt<bool> ArgNoWarnMismatch("no-warn-mismatch",
152  llvm::cl::desc("Allow linking together mismatched input files."),
153  llvm::cl::init(false));
154
155// Not supported yet {
156llvm::cl::opt<bool> ArgExportDynamic("export-dynamic",
157  llvm::cl::desc("Export all dynamic symbols"),
158  llvm::cl::init(false));
159
160llvm::cl::alias ArgExportDynamicAlias("E",
161  llvm::cl::desc("alias for --export-dynamic"),
162  llvm::cl::aliasopt(ArgExportDynamic));
163
164llvm::cl::opt<std::string> ArgBuildID("build-id",
165  llvm::cl::desc("Request creation of \".note.gnu.build-id\" ELF note section."),
166  llvm::cl::value_desc("style"),
167  llvm::cl::ValueOptional);
168
169llvm::cl::list<std::string> ArgExcludeLIBS("exclude-libs",
170  llvm::cl::CommaSeparated,
171  llvm::cl::desc("Exclude libraries from automatic export"),
172  llvm::cl::value_desc("lib1,lib2,..."));
173
174// } Not supported yet
175
176} // anonymous namespace
177
178using namespace mcld;
179
180//===----------------------------------------------------------------------===//
181// OutputFormatOptions
182//===----------------------------------------------------------------------===//
183OutputFormatOptions::OutputFormatOptions()
184  : m_OutputFilename(ArgOutputFilename),
185    m_FileType(ArgFileType),
186    m_OFormat(ArgOFormat),
187    m_Shared(ArgShared),
188    m_PIE(ArgPIE),
189    m_Relocatable(ArgRelocatable),
190    m_Format(ArgFormat),
191    m_StripDebug(ArgStripDebug),
192    m_StripAll(ArgStripAll),
193    m_DiscardAll(ArgDiscardAll),
194    m_DiscardLocals(ArgDiscardLocals),
195    m_EhFrameHdr(ArgEhFrameHdr),
196    m_NMagic(ArgNMagic),
197    m_OMagic(ArgOMagic),
198    m_HashStyle(ArgHashStyle),
199    m_ExportDynamic(ArgExportDynamic),
200    m_BuildID(ArgBuildID),
201    m_ExcludeLIBS(ArgExcludeLIBS),
202    m_NoWarnMismatch(ArgNoWarnMismatch) {
203}
204
205bool OutputFormatOptions::parse(mcld::Module& pModule, LinkerConfig& pConfig)
206{
207  if (!parseOutput(pModule, pConfig)) {
208    mcld::unreachable(mcld::diag::unrecognized_output_file) << pModule.name();
209    return false;
210  }
211
212  if (mcld::Input::Binary == m_Format)
213    pConfig.options().setBinaryInput();
214
215  pConfig.options().setStripDebug(m_StripDebug || m_StripAll);
216  if (m_StripAll)
217    pConfig.options().setStripSymbols(mcld::GeneralOptions::StripAllSymbols);
218  else if (m_DiscardAll)
219    pConfig.options().setStripSymbols(mcld::GeneralOptions::StripLocals);
220  else if (m_DiscardLocals)
221    pConfig.options().setStripSymbols(mcld::GeneralOptions::StripTemporaries);
222  else
223    pConfig.options().setStripSymbols(mcld::GeneralOptions::KeepAllSymbols);
224
225  pConfig.options().setEhFrameHdr(m_EhFrameHdr);
226  pConfig.options().setPIE(m_PIE);
227  pConfig.options().setNMagic(m_NMagic);
228  pConfig.options().setOMagic(m_OMagic);
229  pConfig.options().setHashStyle(m_HashStyle);
230  pConfig.options().setExportDynamic(m_ExportDynamic);
231
232  // --exclude-libs
233  llvm::cl::list<std::string>::iterator exclude,
234                                        excludeEnd = m_ExcludeLIBS.end();
235  for (exclude = m_ExcludeLIBS.begin(); exclude != excludeEnd; ++exclude) {
236    pConfig.options().excludeLIBS().insert(*exclude);
237  }
238
239  if (m_NoWarnMismatch)
240    pConfig.options().setWarnMismatch(false);
241  else
242    pConfig.options().setWarnMismatch(true);
243  // build-id
244  // exclude-libs
245
246  return true;
247}
248
249/// configure the output filename
250bool OutputFormatOptions::parseOutput(Module& pModule, LinkerConfig& pConfig)
251{
252  if (true == m_Shared || true == m_PIE) {
253    // -shared or -pie
254    m_FileType = mcld::LinkerConfig::DynObj;
255  }
256  else if (true == m_Relocatable) {
257    // partial linking
258    m_FileType = mcld::LinkerConfig::Object;
259  }
260  else if (mcld::LinkerConfig::Binary == m_OFormat) {
261    // binary output
262    m_FileType = mcld::LinkerConfig::Binary;
263  }
264
265  pConfig.setCodeGenType(m_FileType);
266
267  std::string output_filename(m_OutputFilename.native());
268
269  if (m_OutputFilename.empty()) {
270
271    if (llvm::Triple::Win32 == pConfig.targets().triple().getOS()) {
272      output_filename.assign("_out");
273      switch (m_FileType) {
274        case mcld::LinkerConfig::Object: {
275          output_filename += ".obj";
276        break;
277        }
278        case mcld::LinkerConfig::DynObj: {
279          output_filename += ".dll";
280          break;
281        }
282        case mcld::LinkerConfig::Exec: {
283          output_filename += ".exe";
284          break;
285        }
286        case mcld::LinkerConfig::External:
287          break;
288        default: {
289          return false;
290          break;
291        }
292      } // switch
293    }
294    else {
295      if (mcld::LinkerConfig::Object   == m_FileType ||
296          mcld::LinkerConfig::DynObj   == m_FileType ||
297          mcld::LinkerConfig::Exec     == m_FileType ||
298          mcld::LinkerConfig::External == m_FileType) {
299        output_filename.assign("a.out");
300      }
301      else {
302        return false;
303      }
304    }
305  } // end of if empty m_OutputFilename
306
307  pModule.setName(output_filename);
308  return true;
309}
310