llvm-link.cpp revision 952d365a3a446ebfbf14a8db27e26c5c2abec651
1//===----------------------------------------------------------------------===//
2// LLVM 'LINK' UTILITY
3//
4// This utility may be invoked in the following manner:
5//  link a.bc b.bc c.bc -o x.bc
6//
7// Alternatively, this can be used as an 'ar' tool as well.  If invoked as
8// either 'ar' or 'llvm-ar', it accepts a 'rc' parameter as well.
9//
10//===----------------------------------------------------------------------===//
11
12#include "llvm/Transforms/Linker.h"
13#include "llvm/Bytecode/Reader.h"
14#include "llvm/Bytecode/Writer.h"
15#include "llvm/Assembly/Writer.h"
16#include "llvm/Module.h"
17#include "llvm/Method.h"
18#include "Support/CommandLine.h"
19#include <fstream>
20#include <memory>
21#include <sys/types.h>     // For FileExists
22#include <sys/stat.h>
23
24
25cl::StringList InputFilenames("", "Load <arg> files, linking them together",
26			      cl::OneOrMore);
27cl::String OutputFilename("o", "Override output filename", cl::NoFlags, "-");
28cl::Flag   Force         ("f", "Overwrite output files", cl::NoFlags, false);
29cl::Flag   Verbose       ("v", "Print information about actions taken");
30cl::Flag   DumpAsm       ("d", "Print assembly as linked", cl::Hidden, false);
31cl::StringList LibPaths  ("L", "Specify a library search path", cl::ZeroOrMore);
32
33
34// FileExists - Return true if the specified string is an openable file...
35static inline bool FileExists(const string &FN) {
36  struct stat StatBuf;
37  return stat(FN.c_str(), &StatBuf) != -1;
38}
39
40// LoadFile - Read the specified bytecode file in and return it.  This routine
41// searches the link path for the specified file to try to find it...
42//
43static inline std::auto_ptr<Module> LoadFile(const string &FN) {
44  string Filename = FN;
45  string ErrorMessage;
46
47  unsigned NextLibPathIdx = 0;
48  bool FoundAFile = false;
49
50  while (1) {
51    if (Verbose) cerr << "Loading '" << Filename << "'\n";
52    if (FileExists(Filename)) FoundAFile = true;
53    Module *Result = ParseBytecodeFile(Filename, &ErrorMessage);
54    if (Result) return std::auto_ptr<Module>(Result);   // Load successful!
55
56    if (Verbose) {
57      cerr << "Error opening bytecode file: '" << Filename << "'";
58      if (ErrorMessage.size()) cerr << ": " << ErrorMessage;
59      cerr << endl;
60    }
61
62    if (NextLibPathIdx == LibPaths.size()) break;
63    Filename = LibPaths[NextLibPathIdx++] + "/" + FN;
64  }
65
66  if (FoundAFile)
67    cerr << "Bytecode file '" << FN << "' corrupt!  "
68         << "Use 'link -v ...' for more info.\n";
69  else
70    cerr << "Could not locate bytecode file: '" << FN << "'\n";
71  return std::auto_ptr<Module>();
72}
73
74
75
76
77int main(int argc, char **argv) {
78  cl::ParseCommandLineOptions(argc, argv, " llvm linker\n",
79			      cl::EnableSingleLetterArgValue |
80			      cl::DisableSingleLetterArgGrouping);
81  assert(InputFilenames.size() > 0 && "OneOrMore is not working");
82
83  unsigned BaseArg = 0;
84  string ErrorMessage;
85
86  // TODO: TEST argv[0] for llvm-ar forms... for now, this is a huge hack.
87  if (InputFilenames.size() >= 3 && InputFilenames[0] == "rc" &&
88      OutputFilename == "-") {
89    BaseArg = 2;
90    OutputFilename = InputFilenames[1];
91  }
92
93  std::auto_ptr<Module> Composite(LoadFile(InputFilenames[BaseArg]));
94  if (Composite.get() == 0) return 1;
95
96  for (unsigned i = BaseArg+1; i < InputFilenames.size(); ++i) {
97    auto_ptr<Module> M(LoadFile(InputFilenames[i]));
98    if (M.get() == 0) return 1;
99
100    if (Verbose) cerr << "Linking in '" << InputFilenames[i] << "'\n";
101
102    if (LinkModules(Composite.get(), M.get(), &ErrorMessage)) {
103      cerr << "Error linking in '" << InputFilenames[i] << "': "
104	   << ErrorMessage << endl;
105      return 1;
106    }
107  }
108
109  if (DumpAsm)
110    cerr << "Here's the assembly:\n" << Composite.get();
111
112  ostream *Out = &cout;  // Default to printing to stdout...
113  if (OutputFilename != "-") {
114    Out = new ofstream(OutputFilename.c_str(),
115		       (Force ? 0 : ios::noreplace)|ios::out);
116    if (!Out->good()) {
117      cerr << "Error opening '" << OutputFilename << "'!\n";
118      return 1;
119    }
120  }
121
122  if (Verbose) cerr << "Writing bytecode...\n";
123  WriteBytecodeToFile(Composite.get(), *Out);
124
125  if (Out != &cout) delete Out;
126  return 0;
127}
128