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
100//===----------------------------------------------------------------------===//
101// Inputs
102//===----------------------------------------------------------------------===//
103static llvm::cl::list<std::string>
104OptInputObjectFiles(llvm::cl::Positional,
105                    llvm::cl::desc("[input object files]"),
106                    llvm::cl::OneOrMore);
107
108static llvm::cl::list<std::string>
109OptNameSpecList("l",
110                llvm::cl::ZeroOrMore,
111                llvm::cl::desc("Add the archive or object file specified by "
112                               "namespec to the list of files to link."),
113                llvm::cl::value_desc("namespec"),
114                llvm::cl::Prefix);
115
116//===----------------------------------------------------------------------===//
117// Scripting Options
118//===----------------------------------------------------------------------===//
119static llvm::cl::list<std::string>
120OptWrapList("wrap",
121            llvm::cl::ZeroOrMore,
122            llvm::cl::desc("Use a wrap function fo symbol."),
123            llvm::cl::value_desc("symbol"));
124
125static llvm::cl::list<std::string>
126OptPortableList("portable",
127                llvm::cl::ZeroOrMore,
128                llvm::cl::desc("Use a portable function to symbol."),
129                llvm::cl::value_desc("symbol"));
130
131//===----------------------------------------------------------------------===//
132// Helper Functions
133//===----------------------------------------------------------------------===//
134// Override "mcld -version"
135static void MCLDVersionPrinter() {
136  llvm::raw_ostream &os = llvm::outs();
137  os << "mcld (The MCLinker Project, http://mclinker.googlecode.com/):\n"
138     << "  version: "MCLD_VERSION"\n"
139     << "  Default target: " << DEFAULT_TARGET_TRIPLE_STRING << "\n";
140
141  os << "\n";
142
143  os << "LLVM (http://llvm.org/):\n";
144
145  return;
146}
147
148#define DEFAULT_OUTPUT_PATH "a.out"
149static inline
150std::string DetermineOutputFilename(const std::string &pOutputPath) {
151  if (!pOutputPath.empty()) {
152    return pOutputPath;
153  }
154
155  // User does't specify the value to -o
156  if (OptInputObjectFiles.size() > 1) {
157    llvm::errs() << "Use " DEFAULT_OUTPUT_PATH " for output file!\n";
158    return DEFAULT_OUTPUT_PATH;
159  }
160
161  // There's only one input file
162  const std::string &input_path = OptInputObjectFiles[0];
163  llvm::SmallString<200> output_path(input_path);
164
165  llvm::error_code err = llvm::sys::fs::make_absolute(output_path);
166  if (llvm::errc::success != err) {
167    llvm::errs() << "Failed to determine the absolute path of `" << input_path
168                 << "'! (detail: " << err.message() << ")\n";
169    return "";
170  }
171
172  llvm::sys::path::remove_filename(output_path);
173  llvm::sys::path::append(output_path, "a.out");
174
175  return output_path.c_str();
176}
177
178static inline
179bool ConfigLinker(Linker &pLinker, const std::string &pOutputFilename) {
180  LinkerConfig* config = NULL;
181
182#ifdef TARGET_BUILD
183  config = new (std::nothrow) DefaultLinkerConfig();
184#else
185  config = new (std::nothrow) LinkerConfig(OptTargetTriple);
186#endif
187  if (config == NULL) {
188    llvm::errs() << "Out of memory when create the linker configuration!\n";
189    return false;
190  }
191
192  // Setup the configuration accroding to the command line options.
193
194  // 1. Set up soname.
195  if (!OptSOName.empty()) {
196    config->setSOName(OptSOName);
197  } else {
198    config->setSOName(pOutputFilename);
199  }
200
201  // 2. If given, set up sysroot.
202  if (!OptSysRoot.empty()) {
203    config->setSysRoot(OptSysRoot);
204  }
205
206  // 3. If given, set up dynamic linker path.
207  if (!OptDyld.empty()) {
208    config->setDyld(OptDyld);
209  }
210
211  // 4. If given, set up wrapped symbols.
212  llvm::cl::list<std::string>::iterator wrap, wrap_end = OptWrapList.end();
213  for (wrap = OptWrapList.begin(); wrap != wrap_end; ++wrap) {
214    config->addWrap(*wrap);
215  }
216
217  // 5. If given, set up portable symbols.
218  llvm::cl::list<std::string>::iterator portable, portable_end = OptPortableList.end();
219  for (portable = OptPortableList.begin(); portable != portable_end; ++portable) {
220    config->addPortable(*portable);
221  }
222
223  // 6. if given, set up search directories.
224  llvm::cl::list<std::string>::iterator sdir, sdir_end = OptSearchDirList.end();
225  for (sdir = OptSearchDirList.begin(); sdir != sdir_end; ++sdir) {
226    config->addSearchDir(*sdir);
227  }
228
229  // set up default search directories
230  config->addSearchDir("=/lib");
231  config->addSearchDir("=/usr/lib");
232
233  // 7. Set up output's type.
234  config->setShared(OptShared);
235
236  // 8. Set up -Bsymbolic.
237  config->setBsymbolic(OptBsymbolic);
238
239  Linker::ErrorCode result = pLinker.config(*config);
240  if (Linker::kSuccess != result) {
241    llvm::errs() << "Failed to configure the linker! (detail: "
242                 << Linker::GetErrorString(result) << ")\n";
243    return false;
244  }
245
246  return true;
247}
248
249static inline
250bool PrepareInputOutput(Linker &pLinker, const std::string &pOutputPath) {
251  // -----  Set output  ----- //
252
253  // FIXME: Current MCLinker requires one to set up output before inputs. The
254  // constraint will be relaxed in the furture.
255  Linker::ErrorCode result = pLinker.setOutput(pOutputPath);
256
257  if (Linker::kSuccess != result) {
258    llvm::errs() << "Failed to open the output file! (detail: "
259                 << pOutputPath << ": "
260                 << Linker::GetErrorString(result) << ")\n";
261    return false;
262  }
263
264  // -----  Set inputs  ----- //
265  llvm::cl::list<std::string>::iterator file_it = OptInputObjectFiles.begin();
266  llvm::cl::list<std::string>::iterator lib_it  = OptNameSpecList.begin();
267
268  llvm::cl::list<std::string>::iterator file_begin = OptInputObjectFiles.begin();
269  llvm::cl::list<std::string>::iterator lib_begin = OptNameSpecList.begin();
270  llvm::cl::list<std::string>::iterator file_end = OptInputObjectFiles.end();
271  llvm::cl::list<std::string>::iterator lib_end = OptNameSpecList.end();
272
273  unsigned lib_pos = 0, file_pos = 0;
274  while (true) {
275    if (lib_it != lib_end) {
276      lib_pos = OptNameSpecList.getPosition(lib_it - lib_begin);
277    } else {
278      lib_pos = 0;
279    }
280
281    if (file_it != file_end) {
282      file_pos = OptInputObjectFiles.getPosition(file_it - file_begin);
283    } else {
284      file_pos = 0;
285    }
286
287    if ((file_pos != 0) && ((lib_pos == 0) || (file_pos < lib_pos))) {
288      result = pLinker.addObject(*file_it);
289      if (Linker::kSuccess != result) {
290        llvm::errs() << "Failed to open the input file! (detail: " << *file_it
291                     << ": " << Linker::GetErrorString(result) << ")\n";
292        return false;
293      }
294      ++file_it;
295    } else if ((lib_pos != 0) && ((file_pos == 0) || (lib_pos < file_pos))) {
296      result = pLinker.addNameSpec(*lib_it);
297      if (Linker::kSuccess != result) {
298        llvm::errs() << "Failed to open the namespec! (detail: " << *lib_it
299                     << ": " << Linker::GetErrorString(result) << ")\n";
300        return false;
301      }
302      ++lib_it;
303    } else {
304      break; // we're done with the list
305    }
306  }
307
308  return true;
309}
310
311static inline bool LinkFiles(Linker &pLinker) {
312  Linker::ErrorCode result = pLinker.link();
313  if (Linker::kSuccess != result) {
314    llvm::errs() << "Failed to linking! (detail: "
315                 << Linker::GetErrorString(result) << "\n";
316    return false;
317  }
318  return true;
319}
320
321int main(int argc, char** argv) {
322  llvm::cl::SetVersionPrinter(MCLDVersionPrinter);
323  llvm::cl::ParseCommandLineOptions(argc, argv);
324  init::Initialize();
325
326  std::string OutputFilename = DetermineOutputFilename(OptOutputFilename);
327  if (OutputFilename.empty()) {
328    return EXIT_FAILURE;
329  }
330
331  Linker linker;
332  if (!ConfigLinker(linker, OutputFilename)) {
333    return EXIT_FAILURE;
334  }
335
336  if (!PrepareInputOutput(linker, OutputFilename)) {
337    return EXIT_FAILURE;
338  }
339
340  if (!LinkFiles(linker)) {
341    return EXIT_FAILURE;
342  }
343
344  return EXIT_SUCCESS;
345}
346
347