summaryrefslogtreecommitdiff
path: root/tools/gccld/gccld.cpp
blob: c2aa8379a11c856e4bca528e9ef922cf1512db29 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//===----------------------------------------------------------------------===//
// LLVM 'GCCLD' UTILITY 
//
// This utility is intended to be compatible with GCC, and follows standard
// system ld conventions.  As such, the default output file is ./a.out.
// Additionally, this program outputs a shell script that is used to invoke LLI
// to execute the program.  In this manner, the generated executable (a.out for
// example), is directly executable, whereas the bytecode file actually lives in
// the a.out.bc file generated by this program.  Also, Force is on by default.
//
// Note that if someone (or a script) deletes the executable program generated,
// the .bc file will be left around.  Considering that this is a temporary hack,
// I'm not to worried about this.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Linker.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/Writer.h"
#include "llvm/Module.h"
#include "llvm/Method.h"
#include "Support/CommandLine.h"
#include <fstream>
#include <memory>
#include <algorithm>
#include <sys/types.h>     // For FileExists
#include <sys/stat.h>


cl::StringList InputFilenames("", "Load <arg> files, linking them together", 
			      cl::OneOrMore);
cl::String OutputFilename("o", "Override output filename", cl::NoFlags,"a.out");
cl::Flag   Verbose       ("v", "Print information about actions taken");
cl::StringList LibPaths  ("L", "Specify a library search path", cl::ZeroOrMore);
cl::StringList Libraries ("l", "Specify libraries to link to", cl::ZeroOrMore);


// FileExists - Return true if the specified string is an openable file...
static inline bool FileExists(const std::string &FN) {
  struct stat StatBuf;
  return stat(FN.c_str(), &StatBuf) != -1;
}

// LoadFile - Read the specified bytecode file in and return it.  This routine
// searches the link path for the specified file to try to find it...
//
static inline std::auto_ptr<Module> LoadFile(const std::string &FN) {
  std::string Filename = FN;
  std::string ErrorMessage;

  unsigned NextLibPathIdx = 0;
  bool FoundAFile = false;

  while (1) {
    if (Verbose) cerr << "Loading '" << Filename << "'\n";
    if (FileExists(Filename)) FoundAFile = true;
    Module *Result = ParseBytecodeFile(Filename, &ErrorMessage);
    if (Result) return std::auto_ptr<Module>(Result);   // Load successful!

    if (Verbose) {
      cerr << "Error opening bytecode file: '" << Filename << "'";
      if (ErrorMessage.size()) cerr << ": " << ErrorMessage;
      cerr << endl;
    }
    
    if (NextLibPathIdx == LibPaths.size()) break;
    Filename = LibPaths[NextLibPathIdx++] + "/" + FN;
  }

  if (FoundAFile)
    cerr << "Bytecode file '" << FN << "' corrupt!  "
         << "Use 'link -v ...' for more info.\n";
  else
    cerr << "Could not locate bytecode file: '" << FN << "'\n";
  return std::auto_ptr<Module>();
}




int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv, " llvm linker for GCC\n",
			      cl::EnableSingleLetterArgValue |
			      cl::DisableSingleLetterArgGrouping);
  assert(InputFilenames.size() > 0 && "OneOrMore is not working");

  unsigned BaseArg = 0;
  std::string ErrorMessage;

  if (!Libraries.empty()) {
    // Sort libraries list...
    sort(Libraries.begin(), Libraries.end());

    // Remove duplicate libraries entries...
    Libraries.erase(unique(Libraries.begin(), Libraries.end()),
                    Libraries.end());

    // Add all of the libraries to the end of the link line...
    for (unsigned i = 0; i < Libraries.size(); ++i)
      InputFilenames.push_back("lib" + Libraries[i] + ".bc");
  }

  std::auto_ptr<Module> Composite(LoadFile(InputFilenames[BaseArg]));
  if (Composite.get() == 0) return 1;

  for (unsigned i = BaseArg+1; i < InputFilenames.size(); ++i) {
    std::auto_ptr<Module> M(LoadFile(InputFilenames[i]));
    if (M.get() == 0) return 1;

    if (Verbose) cerr << "Linking in '" << InputFilenames[i] << "'\n";

    if (LinkModules(Composite.get(), M.get(), &ErrorMessage)) {
      cerr << "Error linking in '" << InputFilenames[i] << "': "
	   << ErrorMessage << endl;
      return 1;
    }
  }

  std::ofstream Out((OutputFilename+".bc").c_str());
  if (!Out.good()) {
    cerr << "Error opening '" << OutputFilename << ".bc' for writing!\n";
    return 1;
  }

  if (Verbose) cerr << "Writing bytecode...\n";
  WriteBytecodeToFile(Composite.get(), Out);
  Out.close();

  // Output the script to start the program...
  std::ofstream Out2(OutputFilename.c_str());
  if (!Out2.good()) {
    cerr << "Error openeing '" << OutputFilename << "' for writing!\n";
    return 1;
  }
  Out2 << "#!/bin/sh\nlli -q $0.bc $*\n";
  Out2.close();
  
  // Make the script executable...
  chmod(OutputFilename.c_str(), 0755);

  return 0;
}