#include "llvm/LinkAllVMCore.h"
#include "llvm/Linker.h"
#include "llvm/System/Program.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetMachineRegistry.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Streams.h"
#include "llvm/Support/SystemUtils.h"
#include "llvm/System/Signals.h"
#include "llvm/Config/config.h"
#include <fstream>
#include <memory>
#include <cstring>
using namespace llvm;
static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,
cl::desc("<input bitcode files>"));
static cl::opt<std::string> OutputFilename("o", cl::init("a.out"),
cl::desc("Override output filename"),
cl::value_desc("filename"));
static cl::opt<bool> Verbose("v",
cl::desc("Print information about actions taken"));
static cl::list<std::string> LibPaths("L", cl::Prefix,
cl::desc("Specify a library search path"),
cl::value_desc("directory"));
static cl::list<std::string> FrameworkPaths("F", cl::Prefix,
cl::desc("Specify a framework search path"),
cl::value_desc("directory"));
static cl::list<std::string> Libraries("l", cl::Prefix,
cl::desc("Specify libraries to link to"),
cl::value_desc("library prefix"));
static cl::list<std::string> Frameworks("framework",
cl::desc("Specify frameworks to link to"),
cl::value_desc("framework"));
static cl::opt<bool> LinkAsLibrary("link-as-library",
cl::desc("Link the .bc files together as a library, not an executable"));
static cl::alias Relink("r", cl::aliasopt(LinkAsLibrary),
cl::desc("Alias for -link-as-library"));
static cl::opt<bool> Native("native",
cl::desc("Generate a native binary instead of a shell script"));
static cl::opt<bool>NativeCBE("native-cbe",
cl::desc("Generate a native binary with the C backend and GCC"));
static cl::list<std::string> PostLinkOpts("post-link-opts",
cl::value_desc("path"),
cl::desc("Run one or more optimization programs after linking"));
static cl::list<std::string> XLinker("Xlinker", cl::value_desc("option"),
cl::desc("Pass options to the system linker"));
static cl::opt<std::string> CO3("soname", cl::Hidden,
cl::desc("Compatibility option: ignored"));
static cl::opt<std::string> CO4("version-script", cl::Hidden,
cl::desc("Compatibility option: ignored"));
static cl::opt<bool> CO5("eh-frame-hdr", cl::Hidden,
cl::desc("Compatibility option: ignored"));
static cl::opt<std::string> CO6("h", cl::Hidden,
cl::desc("Compatibility option: ignored"));
static cl::opt<bool> CO7("start-group", cl::Hidden,
cl::desc("Compatibility option: ignored"));
static cl::opt<bool> CO8("end-group", cl::Hidden,
cl::desc("Compatibility option: ignored"));
static cl::opt<std::string> CO9("m", cl::Hidden,
cl::desc("Compatibility option: ignored"));
static std::string progname;
static void PrintAndExit(const std::string &Message, int errcode = 1) {
cerr << progname << ": " << Message << "\n";
llvm_shutdown();
exit(errcode);
}
static void PrintCommand(const std::vector<const char*> &args) {
std::vector<const char*>::const_iterator I = args.begin(), E = args.end();
for (; I != E; ++I)
if (*I)
cout << "'" << *I << "'" << " ";
cout << "\n" << std::flush;
}
static char ** CopyEnv(char ** const envp) {
unsigned entries; for (entries = 0; envp[entries] != NULL; entries++)
;
++entries;
if (entries == 0)
return NULL;
char **newenv = new char* [entries];
if ((newenv = new char* [entries]) == NULL)
return NULL;
entries = 0;
while (envp[entries] != NULL) {
newenv[entries] = new char[strlen (envp[entries]) + 1];
strcpy (newenv[entries], envp[entries]);
++entries;
}
newenv[entries] = NULL;
return newenv;
}
static void RemoveEnv(const char * name, char ** const envp) {
for (unsigned index=0; envp[index] != NULL; index++) {
char *p = strchr (envp[index], '=');
if (p == NULL)
continue;
else
*p = '\0';
if (!strcmp(name, envp[index]))
*envp[index] = '\0';
else
*p = '=';
}
return;
}
void GenerateBitcode(Module* M, const std::string& FileName) {
if (Verbose)
cout << "Generating Bitcode To " << FileName << '\n';
std::ios::openmode io_mode = std::ios::out | std::ios::trunc |
std::ios::binary;
std::ofstream Out(FileName.c_str(), io_mode);
if (!Out.good())
PrintAndExit("error opening '" + FileName + "' for writing!");
sys::RemoveFileOnSignal(sys::Path(FileName));
WriteBitcodeToFile(M, Out);
Out.close();
}
static int GenerateAssembly(const std::string &OutputFilename,
const std::string &InputFilename,
const sys::Path &llc,
std::string &ErrMsg ) {
std::vector<const char*> args;
args.push_back(llc.c_str());
args.push_back("-x86-asm-syntax=att");
args.push_back("-f");
args.push_back("-o");
args.push_back(OutputFilename.c_str());
args.push_back(InputFilename.c_str());
args.push_back(0);
if (Verbose) {
cout << "Generating Assembly With: \n";
PrintCommand(args);
}
return sys::Program::ExecuteAndWait(llc, &args[0], 0, 0, 0, 0, &ErrMsg);
}
static int GenerateCFile(const std::string &OutputFile,
const std::string &InputFile,
const sys::Path &llc,
std::string& ErrMsg) {
std::vector<const char*> args;
args.push_back(llc.c_str());
args.push_back("-march=c");
args.push_back("-f");
args.push_back("-o");
args.push_back(OutputFile.c_str());
args.push_back(InputFile.c_str());
args.push_back(0);
if (Verbose) {
cout << "Generating C Source With: \n";
PrintCommand(args);
}
return sys::Program::ExecuteAndWait(llc, &args[0], 0, 0, 0, 0, &ErrMsg);
}
static int GenerateNative(const std::string &OutputFilename,
const std::string &InputFilename,
const Linker::ItemList &LinkItems,
const sys::Path &gcc, char ** const envp,
std::string& ErrMsg) {
char ** clean_env = CopyEnv(envp);
if (clean_env == NULL)
return 1;
RemoveEnv("LIBRARY_PATH", clean_env);
RemoveEnv("COLLECT_GCC_OPTIONS", clean_env);
RemoveEnv("GCC_EXEC_PREFIX", clean_env);
RemoveEnv("COMPILER_PATH", clean_env);
RemoveEnv("COLLECT_GCC", clean_env);
std::vector<std::string> args;
args.push_back(gcc.c_str());
args.push_back("-fno-strict-aliasing");
args.push_back("-O3");
args.push_back("-o");
args.push_back(OutputFilename);
args.push_back(InputFilename);
for (unsigned index = 0; index < LibPaths.size(); index++) {
args.push_back("-L" + LibPaths[index]);
}
for (unsigned index = 0; index < FrameworkPaths.size(); index++) {
args.push_back("-F" + FrameworkPaths[index]);
}
for (unsigned index = 0; index < XLinker.size(); index++)
args.push_back(XLinker[index]);
for (unsigned index = 0; index < LinkItems.size(); index++)
if (LinkItems[index].first != "crtend") {
if (LinkItems[index].second)
args.push_back("-l" + LinkItems[index].first);
else
args.push_back(LinkItems[index].first);
}
for (unsigned index = 0; index < Frameworks.size(); index++) {
args.push_back("-framework");
args.push_back(Frameworks[index]);
}
std::vector<const char *> Args;
for (unsigned i = 0, e = args.size(); i != e; ++i)
Args.push_back(args[i].c_str());
Args.push_back(0);
if (Verbose) {
cout << "Generating Native Executable With:\n";
PrintCommand(Args);
}
int R = sys::Program::ExecuteAndWait(
gcc, &Args[0], (const char**)clean_env, 0, 0, 0, &ErrMsg);
delete [] clean_env;
return R;
}
static void EmitShellScript(char **argv) {
if (Verbose)
cout << "Emitting Shell Script\n";
#if defined(_WIN32) || defined(__CYGWIN__)
std::string ErrMsg;
sys::Path llvmstub = FindExecutable("llvm-stub.exe", argv[0]);
if (llvmstub.isEmpty())
PrintAndExit("Could not find llvm-stub.exe executable!");
if (0 != sys::CopyFile(sys::Path(OutputFilename), llvmstub, &ErrMsg))
PrintAndExit(ErrMsg);
return;
#endif
std::ofstream Out2(OutputFilename.c_str());
if (!Out2.good())
PrintAndExit("error opening '" + OutputFilename + "' for writing!");
Out2 << "#!/bin/sh\n";
Out2 << "lli=${LLVMINTERP-lli}\n";
Out2 << "exec $lli \\\n";
LibPaths.push_back("/lib");
LibPaths.push_back("/usr/lib");
LibPaths.push_back("/usr/X11R6/lib");
std::vector<std::string>::iterator libc =
std::find(Libraries.begin(), Libraries.end(), "c");
if (libc != Libraries.end()) Libraries.erase(libc);
for (std::vector<std::string>::iterator i = Libraries.begin(),
e = Libraries.end(); i != e; ++i) {
sys::Path FullLibraryPath;
for (cl::list<std::string>::const_iterator P = LibPaths.begin(),
E = LibPaths.end(); P != E; ++P) {
FullLibraryPath = *P;
FullLibraryPath.appendComponent("lib" + *i);
FullLibraryPath.appendSuffix(&(LTDL_SHLIB_EXT[1]));
if (!FullLibraryPath.isEmpty()) {
if (!FullLibraryPath.isDynamicLibrary()) {
FullLibraryPath = sys::Path();
} else break;
}
}
if (FullLibraryPath.isEmpty())
FullLibraryPath = sys::Path::FindLibrary(*i);
if (!FullLibraryPath.isEmpty())
Out2 << " -load=" << FullLibraryPath.toString() << " \\\n";
}
Out2 << " $0.bc ${1+\"$@\"}\n";
Out2.close();
}
static void BuildLinkItems(
Linker::ItemList& Items,
const cl::list<std::string>& Files,
const cl::list<std::string>& Libraries) {
cl::list<std::string>::const_iterator fileIt = Files.begin();
cl::list<std::string>::const_iterator libIt = Libraries.begin();
int libPos = -1, filePos = -1;
while ( libIt != Libraries.end() || fileIt != Files.end() ) {
if (libIt != Libraries.end())
libPos = Libraries.getPosition(libIt - Libraries.begin());
else
libPos = -1;
if (fileIt != Files.end())
filePos = Files.getPosition(fileIt - Files.begin());
else
filePos = -1;
if (filePos != -1 && (libPos == -1 || filePos < libPos)) {
Items.push_back(std::make_pair(*fileIt++, false));
} else if (libPos != -1 && (filePos == -1 || libPos < filePos)) {
Items.push_back(std::make_pair(*libIt++, true));
}
}
}
namespace llvm {
extern void Optimize(Module*);
}
int main(int argc, char **argv, char **envp) {
sys::PrintStackTraceOnErrorSignal();
PrettyStackTraceProgram X(argc, argv);
llvm_shutdown_obj Y; try {
progname = sys::Path(argv[0]).getBasename();
cl::ParseCommandLineOptions(argc, argv, "llvm linker\n");
Linker TheLinker(progname, OutputFilename, Verbose);
Linker::ItemList NativeLinkItems;
TheLinker.addPaths(LibPaths);
TheLinker.addSystemPaths();
Libraries.erase(std::unique(Libraries.begin(), Libraries.end()),
Libraries.end());
if (LinkAsLibrary) {
std::vector<sys::Path> Files;
for (unsigned i = 0; i < InputFilenames.size(); ++i )
Files.push_back(sys::Path(InputFilenames[i]));
if (TheLinker.LinkInFiles(Files))
return 1;
for (cl::list<std::string>::const_iterator I = Libraries.begin(),
E = Libraries.end(); I != E ; ++I) {
TheLinker.getModule()->addLibrary(*I);
}
} else {
Linker::ItemList Items;
BuildLinkItems(Items, InputFilenames, Libraries);
if (TheLinker.LinkInItems(Items, NativeLinkItems) )
return 1; }
std::auto_ptr<Module> Composite(TheLinker.releaseModule());
Optimize(Composite.get());
#if defined(_WIN32) || defined(__CYGWIN__)
if (!LinkAsLibrary) {
if (OutputFilename.getNumOccurrences() == 0)
OutputFilename = "a.exe";
sys::Path ExeFile( OutputFilename );
if (ExeFile.getSuffix() == "") {
ExeFile.appendSuffix("exe");
OutputFilename = ExeFile.toString();
}
}
#endif
std::string RealBitcodeOutput = OutputFilename;
if (!LinkAsLibrary) RealBitcodeOutput += ".bc";
GenerateBitcode(Composite.get(), RealBitcodeOutput);
if (!LinkAsLibrary) {
if (!PostLinkOpts.empty()) {
std::vector<std::string> opts = PostLinkOpts;
for (std::vector<std::string>::iterator I = opts.begin(),
E = opts.end(); I != E; ++I) {
sys::Path prog(*I);
if (!prog.canExecute()) {
prog = sys::Program::FindProgramByName(*I);
if (prog.isEmpty())
PrintAndExit(std::string("Optimization program '") + *I +
"' is not found or not executable.");
}
sys::Path tmp_output("opt_result");
std::string ErrMsg;
if (tmp_output.createTemporaryFileOnDisk(true, &ErrMsg))
PrintAndExit(ErrMsg);
const char* args[4];
args[0] = I->c_str();
args[1] = RealBitcodeOutput.c_str();
args[2] = tmp_output.c_str();
args[3] = 0;
if (0 == sys::Program::ExecuteAndWait(prog, args, 0,0,0,0, &ErrMsg)) {
if (tmp_output.isBitcodeFile() || tmp_output.isBitcodeFile()) {
sys::Path target(RealBitcodeOutput);
target.eraseFromDisk();
if (tmp_output.renamePathOnDisk(target, &ErrMsg))
PrintAndExit(ErrMsg, 2);
} else
PrintAndExit("Post-link optimization output is not bitcode");
} else {
PrintAndExit(ErrMsg);
}
}
}
if (Native) {
sys::Path AssemblyFile ( OutputFilename);
AssemblyFile.appendSuffix("s");
sys::RemoveFileOnSignal(AssemblyFile);
sys::RemoveFileOnSignal(sys::Path(OutputFilename));
sys::Path llc = FindExecutable("llc", argv[0]);
if (llc.isEmpty())
PrintAndExit("Failed to find llc");
sys::Path gcc = FindExecutable("gcc", argv[0]);
if (gcc.isEmpty())
PrintAndExit("Failed to find gcc");
std::string ErrMsg;
if (0 != GenerateAssembly(AssemblyFile.toString(), RealBitcodeOutput,
llc, ErrMsg))
PrintAndExit(ErrMsg);
if (0 != GenerateNative(OutputFilename, AssemblyFile.toString(),
NativeLinkItems, gcc, envp, ErrMsg))
PrintAndExit(ErrMsg);
AssemblyFile.eraseFromDisk();
} else if (NativeCBE) {
sys::Path CFile (OutputFilename);
CFile.appendSuffix("cbe.c");
sys::RemoveFileOnSignal(CFile);
sys::RemoveFileOnSignal(sys::Path(OutputFilename));
sys::Path llc = FindExecutable("llc", argv[0]);
if (llc.isEmpty())
PrintAndExit("Failed to find llc");
sys::Path gcc = FindExecutable("gcc", argv[0]);
if (gcc.isEmpty())
PrintAndExit("Failed to find gcc");
std::string ErrMsg;
if (0 != GenerateCFile(
CFile.toString(), RealBitcodeOutput, llc, ErrMsg))
PrintAndExit(ErrMsg);
if (0 != GenerateNative(OutputFilename, CFile.toString(),
NativeLinkItems, gcc, envp, ErrMsg))
PrintAndExit(ErrMsg);
CFile.eraseFromDisk();
} else {
EmitShellScript(argv);
}
std::string ErrMsg;
if (sys::Path(OutputFilename).makeExecutableOnDisk(&ErrMsg))
PrintAndExit(ErrMsg);
if (sys::Path(RealBitcodeOutput).makeExecutableOnDisk(&ErrMsg))
PrintAndExit(ErrMsg);
if (sys::Path(RealBitcodeOutput).makeReadableOnDisk(&ErrMsg))
PrintAndExit(ErrMsg);
}
} catch (const std::string& msg) {
PrintAndExit(msg,2);
} catch (...) {
PrintAndExit("Unexpected unknown exception occurred.", 2);
}
return 0;
}