main.cpp revision d0fbbb227051be16931a1aa9b4a7722ac039c698
1//===- mcld.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
10#include <stdlib.h>
11#include <string>
12
13#include <llvm/ADT/SmallString.h>
14#include <llvm/Support/CommandLine.h>
15#include <llvm/Support/FileSystem.h>
16#include <llvm/Support/Path.h>
17#include <llvm/Support/raw_ostream.h>
18#include <llvm/Support/system_error.h>
19
20#include <mcld/Config/Config.h>
21
22#include <alone/Config/Config.h>
23#include <alone/Support/LinkerConfig.h>
24#include <alone/Support/Initialization.h>
25#include <alone/Support/TargetLinkerConfigs.h>
26#include <alone/Linker.h>
27
28using namespace alone;
29
30//===----------------------------------------------------------------------===//
31// Compiler Options
32//===----------------------------------------------------------------------===//
33#ifdef TARGET_BUILD
34static const std::string OptTargetTripe(DEFAULT_TARGET_TRIPLE_STRING);
35#else
36static llvm::cl::opt<std::string>
37OptTargetTriple("mtriple",
38                llvm::cl::desc("Specify the target triple (default: "
39                                DEFAULT_TARGET_TRIPLE_STRING ")"),
40                llvm::cl::init(DEFAULT_TARGET_TRIPLE_STRING),
41                llvm::cl::value_desc("triple"));
42
43static llvm::cl::alias OptTargetTripleC("C", llvm::cl::NotHidden,
44                                        llvm::cl::desc("Alias for -mtriple"),
45                                        llvm::cl::aliasopt(OptTargetTriple));
46#endif
47
48//===----------------------------------------------------------------------===//
49// Command Line Options
50// There are four kinds of command line options:
51//   1. input, (may be a file, such as -m and /tmp/XXXX.o.)
52//   2. scripting options, (represent a subset of link scripting language, such
53//      as --defsym.)
54//   3. and general options. (the rest of options)
55//===----------------------------------------------------------------------===//
56// General Options
57//===----------------------------------------------------------------------===//
58static llvm::cl::opt<std::string>
59OptOutputFilename("o",
60                  llvm::cl::desc("Output filename"),
61                  llvm::cl::value_desc("filename"));
62
63static llvm::cl::opt<std::string>
64OptSysRoot("sysroot", llvm::cl::desc("Use directory as the location of the "
65                                     "sysroot, overriding the configure-time "
66                                     "default."),
67           llvm::cl::value_desc("directory"),
68           llvm::cl::ValueRequired);
69
70static llvm::cl::list<std::string>
71OptSearchDirList("L",
72                 llvm::cl::ZeroOrMore,
73                 llvm::cl::desc("Add path searchdir to the list of paths that "
74                                "mcld will search for archive libraries and "
75                                "mcld control scripts."),
76                 llvm::cl::value_desc("searchdir"),
77                 llvm::cl::Prefix);
78
79static llvm::cl::opt<std::string>
80OptSOName("soname",
81          llvm::cl::desc("Set internal name of shared library"),
82          llvm::cl::value_desc("name"));
83
84
85static llvm::cl::opt<bool>
86OptShared("shared",
87          llvm::cl::desc("Create a shared library."),
88          llvm::cl::init(false));
89
90static llvm::cl::opt<bool>
91OptBsymbolic("Bsymbolic",
92             llvm::cl::desc("Bind references within the shared library."),
93             llvm::cl::init(true));
94
95static llvm::cl::opt<std::string>
96OptDyld("dynamic-linker",
97        llvm::cl::desc("Set the name of the dynamic linker."),
98        llvm::cl::value_desc("Program"));
99
100static llvm::cl::opt<bool>
101OptRelocatable("relocatable",
102               llvm::cl::desc("Generate relocatable output"),
103               llvm::cl::init(false));
104
105static llvm::cl::alias
106OptRelocatableAlias("r",
107                    llvm::cl::desc("alias for --relocatable"),
108                    llvm::cl::aliasopt(OptRelocatable));
109
110static llvm::cl::opt<bool>
111OptDefineCommon("d",
112                llvm::cl::ZeroOrMore,
113                llvm::cl::desc("Define common symbol"),
114                llvm::cl::init(false));
115
116static llvm::cl::alias
117OptDefineCommonAlias1("dc",
118                      llvm::cl::desc("alias for -d"),
119                      llvm::cl::aliasopt(OptDefineCommon));
120
121static llvm::cl::alias
122OptDefineCommonAlias2("dp",
123                      llvm::cl::desc("alias for -d"),
124                      llvm::cl::aliasopt(OptDefineCommon));
125
126
127//===----------------------------------------------------------------------===//
128// Inputs
129//===----------------------------------------------------------------------===//
130static llvm::cl::list<std::string>
131OptInputObjectFiles(llvm::cl::Positional,
132                    llvm::cl::desc("[input object files]"),
133                    llvm::cl::OneOrMore);
134
135static llvm::cl::list<std::string>
136OptNameSpecList("l",
137                llvm::cl::ZeroOrMore,
138                llvm::cl::desc("Add the archive or object file specified by "
139                               "namespec to the list of files to link."),
140                llvm::cl::value_desc("namespec"),
141                llvm::cl::Prefix);
142
143//===----------------------------------------------------------------------===//
144// Scripting Options
145//===----------------------------------------------------------------------===//
146static llvm::cl::list<std::string>
147OptWrapList("wrap",
148            llvm::cl::ZeroOrMore,
149            llvm::cl::desc("Use a wrap function fo symbol."),
150            llvm::cl::value_desc("symbol"));
151
152static llvm::cl::list<std::string>
153OptPortableList("portable",
154                llvm::cl::ZeroOrMore,
155                llvm::cl::desc("Use a portable function to symbol."),
156                llvm::cl::value_desc("symbol"));
157
158//===----------------------------------------------------------------------===//
159// Helper Functions
160//===----------------------------------------------------------------------===//
161// Override "mcld -version"
162static void MCLDVersionPrinter() {
163  llvm::raw_ostream &os = llvm::outs();
164  os << "mcld (The MCLinker Project, http://mclinker.googlecode.com/):\n"
165     << "  version: " MCLD_VERSION "\n"
166     << "  Default target: " << DEFAULT_TARGET_TRIPLE_STRING << "\n";
167
168  os << "\n";
169
170  os << "LLVM (http://llvm.org/):\n";
171
172  return;
173}
174
175#define DEFAULT_OUTPUT_PATH "a.out"
176static inline
177std::string DetermineOutputFilename(const std::string &pOutputPath) {
178  if (!pOutputPath.empty()) {
179    return pOutputPath;
180  }
181
182  // User does't specify the value to -o
183  if (OptInputObjectFiles.size() > 1) {
184    llvm::errs() << "Use " DEFAULT_OUTPUT_PATH " for output file!\n";
185    return DEFAULT_OUTPUT_PATH;
186  }
187
188  // There's only one input file
189  const std::string &input_path = OptInputObjectFiles[0];
190  llvm::SmallString<200> output_path(input_path);
191
192  llvm::error_code err = llvm::sys::fs::make_absolute(output_path);
193  if (llvm::errc::success != err) {
194    llvm::errs() << "Failed to determine the absolute path of `" << input_path
195                 << "'! (detail: " << err.message() << ")\n";
196    return "";
197  }
198
199  llvm::sys::path::remove_filename(output_path);
200  llvm::sys::path::append(output_path, "a.out");
201
202  return output_path.c_str();
203}
204
205static inline
206bool ConfigLinker(Linker &pLinker, const std::string &pOutputFilename) {
207  LinkerConfig* config = NULL;
208
209#ifdef TARGET_BUILD
210  config = new (std::nothrow) DefaultLinkerConfig();
211#else
212  config = new (std::nothrow) GeneralLinkerConfig(OptTargetTriple);
213#endif
214  if (config == NULL) {
215    llvm::errs() << "Out of memory when create the linker configuration!\n";
216    return false;
217  }
218
219  // Setup the configuration accroding to the command line options.
220
221  // 1. Set up soname.
222  if (!OptSOName.empty()) {
223    config->setSOName(OptSOName);
224  } else {
225    config->setSOName(pOutputFilename);
226  }
227
228  // 2. If given, set up sysroot.
229  if (!OptSysRoot.empty()) {
230    config->setSysRoot(OptSysRoot);
231  }
232
233  // 3. If given, set up dynamic linker path.
234  if (!OptDyld.empty()) {
235    config->setDyld(OptDyld);
236  }
237
238  // 4. If given, set up wrapped symbols.
239  llvm::cl::list<std::string>::iterator wrap, wrap_end = OptWrapList.end();
240  for (wrap = OptWrapList.begin(); wrap != wrap_end; ++wrap) {
241    config->addWrap(*wrap);
242  }
243
244  // 5. If given, set up portable symbols.
245  llvm::cl::list<std::string>::iterator portable, portable_end = OptPortableList.end();
246  for (portable = OptPortableList.begin(); portable != portable_end; ++portable) {
247    config->addPortable(*portable);
248  }
249
250  // 6. if given, set up search directories.
251  llvm::cl::list<std::string>::iterator sdir, sdir_end = OptSearchDirList.end();
252  for (sdir = OptSearchDirList.begin(); sdir != sdir_end; ++sdir) {
253    config->addSearchDir(*sdir);
254  }
255
256  // set up default search directories
257  config->addSearchDir("=/lib");
258  config->addSearchDir("=/usr/lib");
259
260  // 7. Set up output's type.
261  config->setShared(OptShared);
262
263  // 8. Set up -Bsymbolic.
264  config->setBsymbolic(OptBsymbolic);
265
266  // 9. Set up -d (define common symbols)
267  config->setDefineCommon(OptDefineCommon);
268
269  Linker::ErrorCode result = pLinker.config(*config);
270  if (Linker::kSuccess != result) {
271    llvm::errs() << "Failed to configure the linker! (detail: "
272                 << Linker::GetErrorString(result) << ")\n";
273    return false;
274  }
275
276  return true;
277}
278
279static inline
280bool PrepareInputOutput(Linker &pLinker, const std::string &pOutputPath) {
281  // -----  Set output  ----- //
282
283  // FIXME: Current MCLinker requires one to set up output before inputs. The
284  // constraint will be relaxed in the furture.
285  Linker::ErrorCode result = pLinker.setOutput(pOutputPath);
286
287  if (Linker::kSuccess != result) {
288    llvm::errs() << "Failed to open the output file! (detail: "
289                 << pOutputPath << ": "
290                 << Linker::GetErrorString(result) << ")\n";
291    return false;
292  }
293
294  // -----  Set inputs  ----- //
295  llvm::cl::list<std::string>::iterator file_it = OptInputObjectFiles.begin();
296  llvm::cl::list<std::string>::iterator lib_it  = OptNameSpecList.begin();
297
298  llvm::cl::list<std::string>::iterator file_begin = OptInputObjectFiles.begin();
299  llvm::cl::list<std::string>::iterator lib_begin = OptNameSpecList.begin();
300  llvm::cl::list<std::string>::iterator file_end = OptInputObjectFiles.end();
301  llvm::cl::list<std::string>::iterator lib_end = OptNameSpecList.end();
302
303  unsigned lib_pos = 0, file_pos = 0;
304  while (true) {
305    if (lib_it != lib_end) {
306      lib_pos = OptNameSpecList.getPosition(lib_it - lib_begin);
307    } else {
308      lib_pos = 0;
309    }
310
311    if (file_it != file_end) {
312      file_pos = OptInputObjectFiles.getPosition(file_it - file_begin);
313    } else {
314      file_pos = 0;
315    }
316
317    if ((file_pos != 0) && ((lib_pos == 0) || (file_pos < lib_pos))) {
318      result = pLinker.addObject(*file_it);
319      if (Linker::kSuccess != result) {
320        llvm::errs() << "Failed to open the input file! (detail: " << *file_it
321                     << ": " << Linker::GetErrorString(result) << ")\n";
322        return false;
323      }
324      ++file_it;
325    } else if ((lib_pos != 0) && ((file_pos == 0) || (lib_pos < file_pos))) {
326      result = pLinker.addNameSpec(*lib_it);
327      if (Linker::kSuccess != result) {
328        llvm::errs() << "Failed to open the namespec! (detail: " << *lib_it
329                     << ": " << Linker::GetErrorString(result) << ")\n";
330        return false;
331      }
332      ++lib_it;
333    } else {
334      break; // we're done with the list
335    }
336  }
337
338  return true;
339}
340
341static inline bool LinkFiles(Linker &pLinker) {
342  Linker::ErrorCode result = pLinker.link();
343  if (Linker::kSuccess != result) {
344    llvm::errs() << "Failed to linking! (detail: "
345                 << Linker::GetErrorString(result) << "\n";
346    return false;
347  }
348  return true;
349}
350
351int main(int argc, char** argv) {
352  llvm::cl::SetVersionPrinter(MCLDVersionPrinter);
353  llvm::cl::ParseCommandLineOptions(argc, argv);
354  init::Initialize();
355
356  std::string OutputFilename = DetermineOutputFilename(OptOutputFilename);
357  if (OutputFilename.empty()) {
358    return EXIT_FAILURE;
359  }
360
361  Linker linker;
362  if (!ConfigLinker(linker, OutputFilename)) {
363    return EXIT_FAILURE;
364  }
365
366  if (!PrepareInputOutput(linker, OutputFilename)) {
367    return EXIT_FAILURE;
368  }
369
370  if (!LinkFiles(linker)) {
371    return EXIT_FAILURE;
372  }
373
374  return EXIT_SUCCESS;
375}
376
377