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