//===----------------------------------------------------------------------===//
#include "llvm/Linker.h"
+#include "llvm/System/Program.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Bytecode/Reader.h"
/// This is just for convenience so it doesn't have to be passed around
/// everywhere.
-static const char* progname = 0;
+static std::string progname;
/// PrintAndReturn - Prints a message to standard error and returns true.
///
///
static int GenerateAssembly(const std::string &OutputFilename,
const std::string &InputFilename,
- const std::string &llc,
- char ** const envp) {
+ const sys::Path &llc) {
// Run LLC to convert the bytecode file into assembly code.
- const char *cmd[6];
- cmd[0] = llc.c_str();
- cmd[1] = "-f";
- cmd[2] = "-o";
- cmd[3] = OutputFilename.c_str();
- cmd[4] = InputFilename.c_str();
- cmd[5] = 0;
-
- return ExecWait(cmd, envp);
+ std::vector<const char*> args;
+ args.push_back( "-f");
+ args.push_back( "-o");
+ args.push_back( OutputFilename.c_str() );
+ args.push_back( InputFilename.c_str() );
+
+ return sys::Program::ExecuteAndWait(llc,&args[0]);
}
/// GenerateAssembly - generates a native assembly language source file from the
/// specified bytecode file.
static int GenerateCFile(const std::string &OutputFile,
const std::string &InputFile,
- const std::string &llc, char ** const envp) {
+ const sys::Path &llc) {
// Run LLC to convert the bytecode file into C.
- const char *cmd[7];
-
- cmd[0] = llc.c_str();
- cmd[1] = "-march=c";
- cmd[2] = "-f";
- cmd[3] = "-o";
- cmd[4] = OutputFile.c_str();
- cmd[5] = InputFile.c_str();
- cmd[6] = 0;
- return ExecWait(cmd, envp);
+ std::vector<const char*> args;
+ 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() );
+ return sys::Program::ExecuteAndWait(llc, &args[0]);
}
/// GenerateNative - generates a native assembly language source file from the
static int GenerateNative(const std::string &OutputFilename,
const std::string &InputFilename,
const std::vector<std::string> &Libraries,
- const std::vector<std::string> &LibPaths,
- const std::string &gcc, char ** const envp) {
+ const sys::Path &gcc, char ** const envp) {
// Remove these environment variables from the environment of the
// programs that we will execute. It appears that GCC sets these
// environment variables so that the programs it uses can configure
RemoveEnv("COMPILER_PATH", clean_env);
RemoveEnv("COLLECT_GCC", clean_env);
- std::vector<const char *> cmd;
// Run GCC to assemble and link the program into native code.
//
// We can't just assemble and link the file with the system assembler
// and linker because we don't know where to put the _start symbol.
// GCC mysteriously knows how to do it.
- cmd.push_back(gcc.c_str());
- cmd.push_back("-fno-strict-aliasing");
- cmd.push_back("-O3");
- cmd.push_back("-o");
- cmd.push_back(OutputFilename.c_str());
- cmd.push_back(InputFilename.c_str());
-
- // Adding the library paths creates a problem for native generation. If we
- // include the search paths from llvmgcc, then we'll be telling normal gcc
- // to look inside of llvmgcc's library directories for libraries. This is
- // bad because those libraries hold only bytecode files (not native object
- // files). In the end, we attempt to link the bytecode libgcc into a native
- // program.
-#if 0
- // Add in the library path options.
- for (unsigned index=0; index < LibPaths.size(); index++) {
- cmd.push_back("-L");
- cmd.push_back(LibPaths[index].c_str());
- }
-#endif
+ std::vector<const char*> args;
+ args.push_back("-fno-strict-aliasing");
+ args.push_back("-O3");
+ args.push_back("-o");
+ args.push_back(OutputFilename.c_str());
+ args.push_back(InputFilename.c_str());
// Add in the libraries to link.
- std::vector<std::string> Libs(Libraries);
- for (unsigned index = 0; index < Libs.size(); index++) {
- if (Libs[index] != "crtend") {
- Libs[index] = "-l" + Libs[index];
- cmd.push_back(Libs[index].c_str());
+ for (unsigned index = 0; index < Libraries.size(); index++)
+ if (Libraries[index] != "crtend") {
+ args.push_back("-l");
+ args.push_back(Libraries[index].c_str());
}
- }
- cmd.push_back(NULL);
// Run the compiler to assembly and link together the program.
- return ExecWait(&(cmd[0]), clean_env);
+ return sys::Program::ExecuteAndWait(gcc, &args[0], (const char**)clean_env);
}
/// EmitShellScript - Output the wrapper file that invokes the JIT on the LLVM
// Windows doesn't support #!/bin/sh style shell scripts in .exe files. To
// support windows systems, we copy the llvm-stub.exe executable from the
// build tree to the destination file.
- std::string llvmstub = FindExecutable("llvm-stub.exe", argv[0]);
- if (llvmstub.empty()) {
+ sys::Path llvmstub = FindExecutable("llvm-stub.exe", argv[0]);
+ if (llvmstub.isEmpty()) {
std::cerr << "Could not find llvm-stub.exe executable!\n";
exit(1);
}
- if (CopyFile(OutputFilename, llvmstub)) {
- std::cerr << "Could not copy the llvm-stub.exe executable!\n";
- exit(1);
- }
+ sys::CopyFile(sys::Path(OutputFilename), llvmstub);
return;
#endif
// on the command line, so that we don't have to do this manually!
for (std::vector<std::string>::iterator i = Libraries.begin(),
e = Libraries.end(); i != e; ++i) {
- std::string FullLibraryPath = FindLib(*i, LibPaths, true);
- if (!FullLibraryPath.empty() && IsSharedObject(FullLibraryPath))
- Out2 << " -load=" << FullLibraryPath << " \\\n";
+ sys::Path FullLibraryPath = sys::Path::FindLibrary(*i);
+ if (!FullLibraryPath.isEmpty() && FullLibraryPath.isDynamicLibrary())
+ Out2 << " -load=" << FullLibraryPath.toString() << " \\\n";
}
Out2 << " $0.bc ${1+\"$@\"}\n";
Out2.close();
}
+// BuildLinkItems -- This function generates a LinkItemList for the LinkItems
+// linker function by combining the Files and Libraries in the order they were
+// declared on the command line.
+static void BuildLinkItems(
+ Linker::ItemList& Items,
+ const cl::list<std::string>& Files,
+ const cl::list<std::string>& Libraries) {
+
+ // Build the list of linkage items for LinkItems.
+
+ 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)) {
+ // Add a source file
+ Items.push_back(std::make_pair(*fileIt++, false));
+ } else if (libPos != -1 && (filePos == -1 || libPos < filePos)) {
+ // Add a library
+ Items.push_back(std::make_pair(*libIt++, true));
+ }
+ }
+}
+
// Rightly this should go in a header file but it just seems such a waste.
namespace llvm {
extern void Optimize(Module*);
}
int main(int argc, char **argv, char **envp) {
- // Initial global variable above for convenience printing of program name.
- progname = argv[0];
-
- // Parse the command line options
- cl::ParseCommandLineOptions(argc, argv, " llvm linker for GCC\n");
- sys::PrintStackTraceOnErrorSignal();
-
- std::string ModuleID("llvm-ld-output");
- std::auto_ptr<Module> Composite(new Module(ModuleID));
-
- // We always look first in the current directory when searching for libraries.
- LibPaths.insert(LibPaths.begin(), ".");
-
- // If the user specified an extra search path in their environment, respect
- // it.
- if (char *SearchPath = getenv("LLVM_LIB_SEARCH_PATH"))
- LibPaths.push_back(SearchPath);
-
- // Remove any consecutive duplicates of the same library...
- Libraries.erase(std::unique(Libraries.begin(), Libraries.end()),
- Libraries.end());
-
- // Link in all of the files
- if (LinkFiles(argv[0], Composite.get(), InputFilenames, Verbose))
- return 1; // Error already printed
-
- // Link in all of the libraries next...
- if (!LinkAsLibrary)
- LinkLibraries(argv[0], Composite.get(), Libraries, LibPaths,
- Verbose, Native);
-
- // Optimize the module
- Optimize(Composite.get());
-
- // Generate the bytecode for the optimized module.
- std::string RealBytecodeOutput = OutputFilename;
- if (!LinkAsLibrary) RealBytecodeOutput += ".bc";
- GenerateBytecode(Composite.get(), RealBytecodeOutput);
-
- // If we are not linking a library, generate either a native executable
- // or a JIT shell script, depending upon what the user wants.
- if (!LinkAsLibrary) {
- // If the user wants to generate a native executable, compile it from the
- // bytecode file.
- //
- // Otherwise, create a script that will run the bytecode through the JIT.
- if (Native) {
- // Name of the Assembly Language output file
- std::string AssemblyFile = OutputFilename + ".s";
-
- // Mark the output files for removal if we get an interrupt.
- sys::RemoveFileOnSignal(sys::Path(AssemblyFile));
- sys::RemoveFileOnSignal(sys::Path(OutputFilename));
-
- // Determine the locations of the llc and gcc programs.
- std::string llc = FindExecutable("llc", argv[0]);
- std::string gcc = FindExecutable("gcc", argv[0]);
- if (llc.empty())
- return PrintAndReturn("Failed to find llc");
-
- if (gcc.empty())
- return PrintAndReturn("Failed to find gcc");
-
- // Generate an assembly language file for the bytecode.
- if (Verbose) std::cout << "Generating Assembly Code\n";
- GenerateAssembly(AssemblyFile, RealBytecodeOutput, llc, envp);
- if (Verbose) std::cout << "Generating Native Code\n";
- GenerateNative(OutputFilename, AssemblyFile, Libraries, LibPaths,
- gcc, envp);
-
- // Remove the assembly language file.
- removeFile (AssemblyFile);
- } else if (NativeCBE) {
- std::string CFile = OutputFilename + ".cbe.c";
-
- // Mark the output files for removal if we get an interrupt.
- sys::RemoveFileOnSignal(sys::Path(CFile));
- sys::RemoveFileOnSignal(sys::Path(OutputFilename));
-
- // Determine the locations of the llc and gcc programs.
- std::string llc = FindExecutable("llc", argv[0]);
- std::string gcc = FindExecutable("gcc", argv[0]);
- if (llc.empty())
- return PrintAndReturn("Failed to find llc");
- if (gcc.empty())
- return PrintAndReturn("Failed to find gcc");
-
- // Generate an assembly language file for the bytecode.
- if (Verbose) std::cout << "Generating Assembly Code\n";
- GenerateCFile(CFile, RealBytecodeOutput, llc, envp);
- if (Verbose) std::cout << "Generating Native Code\n";
- GenerateNative(OutputFilename, CFile, Libraries, LibPaths, gcc, envp);
-
- // Remove the assembly language file.
- removeFile(CFile);
-
+ try {
+ // Initial global variable above for convenience printing of program name.
+ progname = sys::Path(argv[0]).getBasename();
+ Linker TheLinker(progname, Verbose);
+
+ // Set up the library paths for the Linker
+ TheLinker.addPaths(LibPaths);
+ TheLinker.addSystemPaths();
+
+ // Parse the command line options
+ cl::ParseCommandLineOptions(argc, argv, " llvm linker\n");
+ sys::PrintStackTraceOnErrorSignal();
+
+ // Remove any consecutive duplicates of the same library...
+ 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; // Error already printed
+
+ // The libraries aren't linked in but are noted as "dependent" in the
+ // module.
+ for (cl::list<std::string>::const_iterator I = Libraries.begin(),
+ E = Libraries.end(); I != E ; ++I) {
+ TheLinker.getModule()->addLibrary(*I);
+ }
} else {
- EmitShellScript(argv);
+ // Build a list of the items from our command line
+ Linker::ItemList Items;
+ BuildLinkItems(Items, InputFilenames, Libraries);
+
+ // Link all the items together
+ if (TheLinker.LinkInItems(Items) )
+ return 1;
}
-
- // Make the script executable...
- MakeFileExecutable(OutputFilename);
- // Make the bytecode file readable and directly executable in LLEE as well
- MakeFileExecutable(RealBytecodeOutput);
- MakeFileReadable(RealBytecodeOutput);
- }
+ std::auto_ptr<Module> Composite(TheLinker.releaseModule());
+
+ // Optimize the module
+ Optimize(Composite.get());
+
+ // Generate the bytecode for the optimized module.
+ std::string RealBytecodeOutput = OutputFilename;
+ if (!LinkAsLibrary) RealBytecodeOutput += ".bc";
+ GenerateBytecode(Composite.get(), RealBytecodeOutput);
+
+ // If we are not linking a library, generate either a native executable
+ // or a JIT shell script, depending upon what the user wants.
+ if (!LinkAsLibrary) {
+ // If the user wants to generate a native executable, compile it from the
+ // bytecode file.
+ //
+ // Otherwise, create a script that will run the bytecode through the JIT.
+ if (Native) {
+ // Name of the Assembly Language output file
+ sys::Path AssemblyFile ( OutputFilename);
+ AssemblyFile.appendSuffix("s");
+
+ // Mark the output files for removal if we get an interrupt.
+ sys::RemoveFileOnSignal(AssemblyFile);
+ sys::RemoveFileOnSignal(sys::Path(OutputFilename));
+
+ // Determine the locations of the llc and gcc programs.
+ sys::Path llc = FindExecutable("llc", argv[0]);
+ if (llc.isEmpty())
+ return PrintAndReturn("Failed to find llc");
+
+ sys::Path gcc = FindExecutable("gcc", argv[0]);
+ if (gcc.isEmpty())
+ return PrintAndReturn("Failed to find gcc");
+
+ // Generate an assembly language file for the bytecode.
+ if (Verbose) std::cout << "Generating Assembly Code\n";
+ GenerateAssembly(AssemblyFile.toString(), RealBytecodeOutput, llc);
+ if (Verbose) std::cout << "Generating Native Code\n";
+ GenerateNative(OutputFilename, AssemblyFile.toString(), Libraries,
+ gcc, envp);
+
+ // Remove the assembly language file.
+ AssemblyFile.destroyFile();
+ } else if (NativeCBE) {
+ sys::Path CFile (OutputFilename);
+ CFile.appendSuffix("cbe.c");
+
+ // Mark the output files for removal if we get an interrupt.
+ sys::RemoveFileOnSignal(CFile);
+ sys::RemoveFileOnSignal(sys::Path(OutputFilename));
+
+ // Determine the locations of the llc and gcc programs.
+ sys::Path llc = FindExecutable("llc", argv[0]);
+ if (llc.isEmpty())
+ return PrintAndReturn("Failed to find llc");
+
+ sys::Path gcc = FindExecutable("gcc", argv[0]);
+ if (gcc.isEmpty())
+ return PrintAndReturn("Failed to find gcc");
+
+ // Generate an assembly language file for the bytecode.
+ if (Verbose) std::cout << "Generating Assembly Code\n";
+ GenerateCFile(CFile.toString(), RealBytecodeOutput, llc);
+ if (Verbose) std::cout << "Generating Native Code\n";
+ GenerateNative(OutputFilename, CFile.toString(), Libraries, gcc, envp);
+
+ // Remove the assembly language file.
+ CFile.destroyFile();
+
+ } else {
+ EmitShellScript(argv);
+ }
+
+ // Make the script executable...
+ sys::Path(OutputFilename).makeExecutable();
+
+ // Make the bytecode file readable and directly executable in LLEE as well
+ sys::Path(RealBytecodeOutput).makeExecutable();
+ sys::Path(RealBytecodeOutput).makeReadable();
+ }
- return 0;
+ return 0;
+ } catch (const std::string& msg) {
+ std::cerr << argv[0] << ": " << msg << "\n";
+ } catch (...) {
+ std::cerr << argv[0] << ": Unexpected unknown exception occurred.\n";
+ }
+ return 1;
}