From 837149c08da7d9015c5dcfa9f62110ce14e5b949 Mon Sep 17 00:00:00 2001 From: Reid Spencer Date: Mon, 28 Feb 2005 08:45:35 +0000 Subject: [PATCH] Changes to enable creation of native executables directly from gccld and to ensure that -L paths don't contain both bytecode and native libraries. This patch contributed by Adam Treat. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@20370 91177308-0d34-0410-b5e6-96231b3b80d8 --- tools/gccld/GenerateCode.cpp | 91 ++++++++++++++++++++- tools/gccld/gccld.cpp | 154 +++++++++++++++++++---------------- tools/gccld/gccld.h | 12 ++- 3 files changed, 183 insertions(+), 74 deletions(-) diff --git a/tools/gccld/GenerateCode.cpp b/tools/gccld/GenerateCode.cpp index 1d4c5205cff..a75d6f1cd80 100644 --- a/tools/gccld/GenerateCode.cpp +++ b/tools/gccld/GenerateCode.cpp @@ -20,6 +20,7 @@ #include "llvm/Analysis/LoadValueNumbering.h" #include "llvm/Analysis/Passes.h" #include "llvm/Analysis/Verifier.h" +#include "llvm/Bytecode/Archive.h" #include "llvm/Bytecode/WriteBytecodePass.h" #include "llvm/Target/TargetData.h" #include "llvm/Transforms/IPO.h" @@ -127,6 +128,62 @@ static inline void addPass(PassManager &PM, Pass *P) { if (Verify) PM.add(createVerifierPass()); } +static bool isBytecodeLibrary(const sys::Path &FullPath) { + // Check for a bytecode file + if (FullPath.isBytecodeFile()) return true; + // Check for a dynamic library file + if (FullPath.isDynamicLibrary()) return false; + // Check for a true bytecode archive file + if (FullPath.isArchive() ) { + std::string ErrorMessage; + Archive* ar = Archive::OpenAndLoadSymbols( FullPath, &ErrorMessage ); + return ar->isBytecodeArchive(); + } + return false; +} + +static bool isBytecodeLPath(const std::string &LibPath) { + bool isBytecodeLPath = false; + + // Make sure the -L path has a '/' character + // because llvm-g++ passes them without the ending + // '/' char and sys::Path doesn't think it is a + // directory (see: sys::Path::isDirectory) without it + std::string dir = LibPath; + if ( dir[dir.length()-1] != '/' ) + dir.append("/"); + + sys::Path LPath(dir); + + // Grab the contents of the -L path + std::set Files; + LPath.getDirectoryContents(Files); + + // Iterate over the contents one by one to determine + // if this -L path has any bytecode shared libraries + // or archives + std::set::iterator File = Files.begin(); + for (; File != Files.end(); ++File) { + + if ( File->isDirectory() ) + continue; + + std::string path = File->toString(); + std::string dllsuffix = sys::Path::GetDLLSuffix(); + + // Check for an ending '.dll,.so' or '.a' suffix as all + // other files are not of interest to us here + if ( path.find(dllsuffix, path.size()-dllsuffix.size()) == std::string::npos + && path.find(".a", path.size()-2) == std::string::npos ) + continue; + + // Finally, check to see if the file is a true bytecode file + if (isBytecodeLibrary(*File)) + isBytecodeLPath = true; + } + return isBytecodeLPath; +} + /// GenerateBytecode - generates a bytecode file from the specified module. /// /// Inputs: @@ -285,8 +342,12 @@ int llvm::GenerateCFile(const std::string &OutputFile, /// int llvm::GenerateNative(const std::string &OutputFilename, const std::string &InputFilename, + const std::vector &LibPaths, const std::vector &Libraries, - const sys::Path &gcc, char ** const envp) { + const sys::Path &gcc, char ** const envp, + bool Shared, + const std::string &RPath, + const std::string &SOName) { // 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 @@ -316,7 +377,33 @@ int llvm::GenerateNative(const std::string &OutputFilename, args.push_back("-o"); args.push_back(OutputFilename.c_str()); args.push_back(InputFilename.c_str()); - + + if (Shared) args.push_back("-shared"); + if (!RPath.empty()) { + std::string rp = "-Wl,-rpath," + RPath; + args.push_back(rp.c_str()); + } + if (!SOName.empty()) { + std::string so = "-Wl,-soname," + SOName; + args.push_back(so.c_str()); + } + + // Add in the libpaths to find the libraries. + // + // Note: + // When gccld is called from the llvm-gxx frontends, the -L paths for + // the LLVM cfrontend install paths are appended. We don't want the + // native linker to use these -L paths as they contain bytecode files. + // Further, we don't want any -L paths that contain bytecode shared + // libraries or true bytecode archive files. We omit them in all such + // cases. + for (unsigned index = 0; index < LibPaths.size(); index++) { + if (!isBytecodeLPath( LibPaths[index]) ) { + args.push_back("-L"); + args.push_back(LibPaths[index].c_str()); + } + } + // Add in the libraries to link. for (unsigned index = 0; index < Libraries.size(); index++) { if (Libraries[index] != "crtend") { diff --git a/tools/gccld/gccld.cpp b/tools/gccld/gccld.cpp index 00cf6571927..8698cc88991 100644 --- a/tools/gccld/gccld.cpp +++ b/tools/gccld/gccld.cpp @@ -83,11 +83,21 @@ namespace { cl::opt NativeCBE("native-cbe", cl::desc("Generate a native binary with the C backend and GCC")); + + cl::opt + RPath("rpath", + cl::desc("Set runtime shared library search path (requires -native or" + " -native-cbe)"), + cl::Prefix, cl::value_desc("directory")); + + cl::opt + SOName("soname", + cl::desc("Set internal name of shared library (requires -native or" + " -native-cbe)"), + cl::Prefix, cl::value_desc("name")); // Compatibility options that are ignored but supported by LD cl::opt - CO3("soname", cl::Hidden, cl::desc("Compatibility option: ignored")); - cl::opt CO4("version-script", cl::Hidden, cl::desc("Compatibility option: ignored")); cl::opt CO5("eh-frame-hdr", cl::Hidden, cl::desc("Compatibility option: ignored")); @@ -237,7 +247,7 @@ int main(int argc, char **argv, char **envp ) { // Create the output file. std::string RealBytecodeOutput = OutputFilename; - if (!LinkAsLibrary) RealBytecodeOutput += ".bc"; + if (!LinkAsLibrary || Native || NativeCBE) RealBytecodeOutput += ".bc"; std::ios::openmode io_mode = std::ios::out | std::ios::trunc | std::ios::binary; std::ofstream Out(RealBytecodeOutput.c_str(), io_mode); @@ -266,77 +276,83 @@ int main(int argc, char **argv, char **envp ) { // Close the bytecode file. Out.close(); - // 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(argv[0], "Failed to find llc"); - - sys::Path gcc = FindExecutable("gcc", argv[0]); - if (gcc.isEmpty()) - return PrintAndReturn(argv[0], "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(argv[0], "Failed to find llc"); - - sys::Path gcc = FindExecutable("gcc", argv[0]); - if (gcc.isEmpty()) - return PrintAndReturn(argv[0], "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); - } + // Generate either a native file or a JIT shell script. If the user wants + // to generate a native file, compile it from the bytecode file. Otherwise, + // if the target is not a library, 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(argv[0], "Failed to find llc"); + + sys::Path gcc = FindExecutable("gcc", argv[0]); + if (gcc.isEmpty()) + return PrintAndReturn(argv[0], "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(), + LibPaths, Libraries, gcc, envp, LinkAsLibrary, RPath, + SOName ); + + // Remove the assembly language file. + AssemblyFile.destroyFile(); + // Remove the bytecode language file. + sys::Path(RealBytecodeOutput).destroyFile(); - // Make the script executable... - sys::Path(OutputFilename).makeExecutable(); + } 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(argv[0], "Failed to find llc"); + + sys::Path gcc = FindExecutable("gcc", argv[0]); + if (gcc.isEmpty()) + return PrintAndReturn(argv[0], "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(), + LibPaths, Libraries, gcc, envp, LinkAsLibrary, RPath, + SOName ); + + // Remove the assembly language file. + CFile.destroyFile(); + + // Remove the bytecode language file. + sys::Path(RealBytecodeOutput).destroyFile(); - // Make the bytecode file readable and directly executable in LLEE as well + } else if (!LinkAsLibrary) { + EmitShellScript(argv); + + // Make the bytecode file readable and directly executable in LLEE sys::Path(RealBytecodeOutput).makeExecutable(); sys::Path(RealBytecodeOutput).makeReadable(); } + + // Make the output, whether native or script, executable as well... + sys::Path(OutputFilename).makeExecutable(); + } catch (const char*msg) { std::cerr << argv[0] << ": " << msg << "\n"; exitCode = 1; diff --git a/tools/gccld/gccld.h b/tools/gccld/gccld.h index 922d535183d..ea9a8ee3a1d 100644 --- a/tools/gccld/gccld.h +++ b/tools/gccld/gccld.h @@ -31,13 +31,19 @@ GenerateAssembly (const std::string & OutputFilename, const std::string & InputFilename, const sys::Path & llc); -int GenerateCFile(const std::string &OutputFile, const std::string &InputFile, - const sys::Path &llc); +int +GenerateCFile (const std::string &OutputFile, + const std::string &InputFile, + const sys::Path &llc); int GenerateNative (const std::string & OutputFilename, const std::string & InputFilename, + const std::vector & LibPaths, const std::vector & Libraries, const sys::Path & gcc, - char ** const envp); + char ** const envp, + bool Shared, + const std::string & RPath, + const std::string & SOName); } // End llvm namespace -- 2.34.1