[llvm-commits] CVS: llvm/tools/gccld/linker.cpp gccld.cpp gencode.cpp util.cpp util.h

John Criswell criswell at cs.uiuc.edu
Fri Sep 19 15:26:03 PDT 2003


Changes in directory llvm/tools/gccld:

linker.cpp added (r1.1)
gccld.cpp updated: 1.50 -> 1.51
gencode.cpp updated: 1.1 -> 1.2
util.cpp (r1.1) removed
util.h (r1.1) removed

---
Log message:

Removed linking functionality from gccld.cpp and moved it to linker.cpp.
Renamed functions that were all lower-case.
Moved functions from util.cpp into linker.cpp or gccld.cpp.
Removed util.h and created gccld.h.
Refactored the linker functionality in linker.cpp so that it is easier to
follow, easier to modify, and it's library/object file search behavior is
easier to understand and document.
Added code to include library paths when doing native linking, but this
causes problems and is currently #ifdef'd out.



---
Diffs of the changes:

Index: llvm/tools/gccld/linker.cpp
diff -c /dev/null llvm/tools/gccld/linker.cpp:1.1
*** /dev/null	Fri Sep 19 15:25:04 2003
--- llvm/tools/gccld/linker.cpp	Fri Sep 19 15:24:23 2003
***************
*** 0 ****
--- 1,601 ----
+ //===- gccld.cpp - LLVM 'ld' compatible linker ----------------------------===//
+ //
+ // 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 too worried about this.
+ //
+ //===----------------------------------------------------------------------===//
+ 
+ #include "llvm/Transforms/Utils/Linker.h"
+ #include "llvm/Module.h"
+ #include "llvm/PassManager.h"
+ #include "llvm/Bytecode/Reader.h"
+ #include "llvm/Bytecode/WriteBytecodePass.h"
+ #include "llvm/Target/TargetData.h"
+ #include "llvm/Transforms/IPO.h"
+ #include "llvm/Transforms/Scalar.h"
+ #include "Support/FileUtilities.h"
+ #include "Support/SystemUtils.h"
+ #include "Support/CommandLine.h"
+ #include "Support/Signals.h"
+ #include "Config/stdlib.h"
+ #include "gccld.h"
+ 
+ #include <fstream>
+ #include <memory>
+ #include <set>
+ #include <algorithm>
+ 
+ //
+ // Function: FileExists ()
+ //
+ // Description:
+ //  Determine if the specified filename exists and is readable.
+ //
+ // Inputs:
+ //  FN - The name of the file.
+ //
+ // Outputs:
+ //  None.
+ //
+ // Return Value:
+ //  TRUE - The file exists and is readable.
+ //  FALSE - The file does not exist or is unreadable.
+ //
+ static inline bool
+ FileExists(const std::string &FN)
+ {
+   return access(FN.c_str(), R_OK | F_OK) != -1;
+ }
+ 
+ //
+ // Function: IsArchive ()
+ //
+ // Description:
+ //  Determine if the specified file is an ar archive.  It determines this by
+ //  checking the magic string at the beginning of the file.
+ //
+ // Inputs:
+ //  filename - A C++ string containing the name of the file.
+ //
+ // Outputs:
+ //  None.
+ //
+ // Return value:
+ //  TRUE  - The file is an archive.
+ //  FALSE - The file is not an archive.
+ //
+ static inline bool
+ IsArchive (const std::string &filename)
+ {
+   std::string ArchiveMagic("!<arch>\012");
+   char buf[1 + ArchiveMagic.size()];
+ 
+   std::ifstream f(filename.c_str());
+   f.read(buf, ArchiveMagic.size());
+   buf[ArchiveMagic.size()] = '\0';
+   return ArchiveMagic == buf;
+ }
+ 
+ //
+ // Function: FindLib ()
+ //
+ // Description:
+ //  This function locates a particular library.  It will prepend and append
+ //  various directories, prefixes, and suffixes until it can find the library.
+ //
+ // Inputs:
+ //  Filename  - Name of the file to find.
+ //  Paths     - List of directories to search.
+ //
+ // Outputs:
+ //  None.
+ //
+ // Return value:
+ //  The name of the file is returned.
+ //  If the file is not found, an empty string is returned.
+ //
+ static std::string
+ FindLib (const std::string & Filename, const std::vector<std::string> & Paths)
+ {
+   //
+   // Determine if the pathname can be found as it stands.
+   //
+   if (FileExists (Filename))
+   {
+     return Filename;
+   }
+ 
+   //
+   // If that doesn't work, convert the name into a library name.
+   //
+   std::string LibName = "lib" + Filename;
+ 
+   //
+   // Iterate over the directories in Paths to see if we can find the library
+   // there.
+   //
+   for (unsigned Index = 0; Index != Paths.size(); ++Index)
+   {
+     std::string Directory = Paths[Index] + "/";
+ 
+     if (FileExists (Directory + LibName + ".bc"))
+     {
+       return Directory + LibName + ".bc";
+     }
+ 
+     if (FileExists (Directory + LibName + ".so"))
+     {
+       return Directory + LibName + ".so";
+     }
+ 
+     if (FileExists (Directory + LibName + ".a"))
+     {
+       return Directory + LibName + ".a";
+     }
+   }
+ 
+   //
+   // One last hope: Check LLVM_LIB_SEARCH_PATH.
+   //
+   char *SearchPath = getenv("LLVM_LIB_SEARCH_PATH");
+   if (SearchPath == NULL)
+   {
+         return std::string();
+   }
+ 
+   LibName = std::string(SearchPath) + "/" + LibName;
+   if (FileExists (LibName))
+   {
+     return LibName;
+   }
+ 
+   return std::string();
+ }
+ 
+ //
+ // Function: GetAllDefinedSymbols ()
+ //
+ // Description:
+ //  Find all of the defined symbols in the specified module.
+ //
+ // Inputs:
+ //  M - The module in which to find defined symbols.
+ //
+ // Outputs:
+ //  DefinedSymbols - A set of C++ strings that will contain the name of all
+ //                   defined symbols.
+ //
+ // Return value:
+ //  None.
+ //
+ void
+ GetAllDefinedSymbols (Module *M, std::set<std::string> &DefinedSymbols)
+ {
+   for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
+     if (I->hasName() && !I->isExternal() && !I->hasInternalLinkage())
+       DefinedSymbols.insert(I->getName());
+   for (Module::giterator I = M->gbegin(), E = M->gend(); I != E; ++I)
+     if (I->hasName() && !I->isExternal() && !I->hasInternalLinkage())
+       DefinedSymbols.insert(I->getName());
+ }
+ 
+ //
+ // Function: GetAllUndefinedSymbols ()
+ //
+ // Description:
+ //  This calculates the set of undefined symbols that still exist in an LLVM
+ //  module.  This is a bit tricky because there may be two symbols with the
+ //  same name but different LLVM types that will be resolved to each other but
+ //  aren't currently (thus we need to treat it as resolved).
+ //
+ // Inputs:
+ //  M - The module in which to find undefined symbols.
+ //
+ // Outputs:
+ //  UndefinedSymbols - A set of C++ strings containing the name of all
+ //                     undefined symbols.
+ //
+ // Return value:
+ //  None.
+ //
+ void
+ GetAllUndefinedSymbols(Module *M, std::set<std::string> &UndefinedSymbols)
+ {
+   std::set<std::string> DefinedSymbols;
+   UndefinedSymbols.clear();   // Start out empty
+   
+   for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
+     if (I->hasName()) {
+       if (I->isExternal())
+         UndefinedSymbols.insert(I->getName());
+       else if (!I->hasInternalLinkage())
+         DefinedSymbols.insert(I->getName());
+     }
+   for (Module::giterator I = M->gbegin(), E = M->gend(); I != E; ++I)
+     if (I->hasName()) {
+       if (I->isExternal())
+         UndefinedSymbols.insert(I->getName());
+       else if (!I->hasInternalLinkage())
+         DefinedSymbols.insert(I->getName());
+     }
+   
+   // Prune out any defined symbols from the undefined symbols set...
+   for (std::set<std::string>::iterator I = UndefinedSymbols.begin();
+        I != UndefinedSymbols.end(); )
+     if (DefinedSymbols.count(*I))
+       UndefinedSymbols.erase(I++);  // This symbol really is defined!
+     else
+       ++I; // Keep this symbol in the undefined symbols list
+ }
+ 
+ 
+ //
+ // Function: LoadObject ()
+ //
+ // Description:
+ //  Read the specified bytecode object file.
+ //
+ // Inputs:
+ //  FN - The name of the file to load.
+ //
+ // Outputs:
+ //  OutErrorMessage - The error message to give back to the caller.
+ //
+ // Return Value:
+ //  A pointer to a module represening the bytecode file is returned.
+ //  If an error occurs, the pointer is 0.
+ //
+ std::auto_ptr<Module>
+ LoadObject (const std::string & FN, std::string &OutErrorMessage)
+ {
+   std::string ErrorMessage;
+   Module *Result = ParseBytecodeFile(FN, &ErrorMessage);
+   if (Result) return std::auto_ptr<Module>(Result);
+ 
+   OutErrorMessage = "Bytecode file '" + FN + "' corrupt!";
+   if (ErrorMessage.size()) OutErrorMessage += ": " + ErrorMessage;
+   return std::auto_ptr<Module>();
+ }
+ 
+ //
+ // Function: LinkInArchive ()
+ //
+ // Description:
+ //  This function will open an archive library and link in all objects which
+ //  provide symbols that are currently undefined.
+ //
+ // Inputs:
+ //  M        - The module in which to link the archives.
+ //  Filename - The pathname of the archive.
+ //  Verbose  - Flags whether verbose messages should be printed.
+ //
+ // Outputs:
+ //  ErrorMessage - A C++ string detailing what error occurred, if any.
+ //
+ // Return Value:
+ //  TRUE  - An error occurred.
+ //  FALSE - No errors.
+ //
+ static bool
+ LinkInArchive (Module * M,
+                const std::string & Filename,
+                std::string & ErrorMessage,
+                bool Verbose)
+ {
+   //
+   // Find all of the symbols currently undefined in the bytecode program.
+   // If all the symbols are defined, the program is complete, and there is
+   // no reason to link in any archive files.
+   //
+   std::set<std::string> UndefinedSymbols;
+   GetAllUndefinedSymbols (M, UndefinedSymbols);
+   if (UndefinedSymbols.empty())
+   {
+     if (Verbose) std::cerr << "  No symbols undefined, don't link library!\n";
+     return false;  // No need to link anything in!
+   }
+ 
+   //
+   // Load in the archive objects.
+   //
+   if (Verbose) std::cerr << "  Loading '" << Filename << "'\n";
+   std::vector<Module*> Objects;
+   if (ReadArchiveFile (Filename, Objects, &ErrorMessage))
+   {
+     return true;
+   }
+ 
+   //
+   // Figure out which symbols are defined by all of the modules in the archive.
+   //
+   std::vector<std::set<std::string> > DefinedSymbols;
+   DefinedSymbols.resize (Objects.size());
+   for (unsigned i = 0; i != Objects.size(); ++i)
+   {
+     GetAllDefinedSymbols(Objects[i], DefinedSymbols[i]);
+   }
+ 
+   // While we are linking in object files, loop.
+   bool Linked = true;
+   while (Linked)
+   {     
+     Linked = false;
+ 
+     for (unsigned i = 0; i != Objects.size(); ++i) {
+       // Consider whether we need to link in this module...  we only need to
+       // link it in if it defines some symbol which is so far undefined.
+       //
+       const std::set<std::string> &DefSymbols = DefinedSymbols[i];
+ 
+       bool ObjectRequired = false;
+       for (std::set<std::string>::iterator I = UndefinedSymbols.begin(),
+              E = UndefinedSymbols.end(); I != E; ++I)
+         if (DefSymbols.count(*I)) {
+           if (Verbose)
+             std::cerr << "  Found object providing symbol '" << *I << "'...\n";
+           ObjectRequired = true;
+           break;
+         }
+       
+       // We DO need to link this object into the program...
+       if (ObjectRequired) {
+         if (LinkModules(M, Objects[i], &ErrorMessage))
+           return true;   // Couldn't link in the right object file...        
+         
+         // Since we have linked in this object, delete it from the list of
+         // objects to consider in this archive file.
+         std::swap(Objects[i], Objects.back());
+         std::swap(DefinedSymbols[i], DefinedSymbols.back());
+         Objects.pop_back();
+         DefinedSymbols.pop_back();
+         --i;   // Do not skip an entry
+         
+         // The undefined symbols set should have shrunk.
+         GetAllUndefinedSymbols(M, UndefinedSymbols);
+         Linked = true;  // We have linked something in!
+       }
+     }
+   }
+   
+   return false;
+ }
+ 
+ //
+ // Function: LinkInFile ()
+ //
+ // Description:
+ //  This function will open an archive library and link in all objects which
+ //  provide symbols that are currently undefined.
+ //
+ // Inputs:
+ //  HeadModule - The module in which to link the archives.
+ //  Filename   - The pathname of the archive.
+ //  Verbose    - Flags whether verbose messages should be printed.
+ //
+ // Outputs:
+ //  ErrorMessage - A C++ string detailing what error occurred, if any.
+ //
+ // Return Value:
+ //  TRUE  - An error occurred.
+ //  FALSE - No errors.
+ //
+ static bool
+ LinkInFile (Module * HeadModule,
+             const std::string & Filename,
+             std::string & ErrorMessage,
+             bool Verbose)
+ {
+   std::auto_ptr<Module> M(LoadObject(Filename, ErrorMessage));
+   if (M.get() == 0)
+   {
+     return true;
+   }
+ 
+   if (Verbose) std::cerr << "Linking in '" << Filename << "'\n";
+ 
+   return (LinkModules (HeadModule, M.get(), &ErrorMessage));
+ }
+ 
+ //
+ // Function: LinkFiles ()
+ //
+ // Description:
+ //  This function takes a module and a list of files and links them all
+ //  together.  It locates the file either in the current directory, as it's
+ //  absolute or relative pathname, or as a file somewhere in
+ //  LLVM_LIB_SEARCH_PATH.
+ //
+ // Inputs:
+ //  progname   - The name of the program (infamous argv[0]).
+ //  HeadModule - The module under which all files will be linked.
+ //  Files      - A vector of C++ strings indicating the LLVM bytecode filenames
+ //               to be linked.  The names can refer to a mixture of pure LLVM
+ //               bytecode files and archive (ar) formatted files.
+ //  Verbose    - Flags whether verbose output should be printed while linking.
+ //
+ // Outputs:
+ //  HeadModule - The module will have the specified LLVM bytecode files linked
+ //               in.
+ //
+ // Return value:
+ //  FALSE - No errors.
+ //  TRUE  - Some error occurred.
+ //
+ bool
+ LinkFiles (const char * progname,
+            Module * HeadModule,
+            const std::vector<std::string> & Files,
+            bool Verbose)
+ {
+   // String in which to receive error messages.
+   std::string ErrorMessage;
+ 
+   // Full pathname of the file
+   std::string Pathname;
+ 
+   // Get the library search path from the environment
+   char *SearchPath = getenv("LLVM_LIB_SEARCH_PATH");
+ 
+   for (unsigned i = 1; i < Files.size(); ++i)
+   {
+     //
+     // Determine where this file lives.
+     //
+     if (FileExists (Files[i]))
+     {
+       Pathname = Files[i];
+     }
+     else
+     {
+       if (SearchPath == NULL)
+       {
+         std::cerr << "Cannot find " << Files[i];
+         return true;
+       }
+ 
+       Pathname = std::string(SearchPath)+"/"+Files[i];
+       if (!FileExists (Pathname))
+       {
+         std::cerr << "Cannot find " << Files[i];
+         return true;
+       }
+     }
+ 
+     //
+     // A user may specify an ar archive without -l, perhaps because it
+     // is not installed as a library. Detect that and link the library.
+     //
+     if (IsArchive(Pathname))
+     {
+       if (Verbose)
+       {
+         std::cerr << "Linking archive '" << Files[i] << "'\n";
+       }
+ 
+       if (LinkInArchive (HeadModule, Pathname, ErrorMessage, Verbose))
+       {
+         PrintAndReturn(progname, ErrorMessage,
+                               ": Error linking in '" + Files[i] + "'");
+         return true;
+       }
+     }
+     else
+     {
+       if (Verbose)
+       {
+         std::cerr << "Linking file '" << Files[i] << "'\n";
+       }
+ 
+       if (LinkInFile (HeadModule, Pathname, ErrorMessage, Verbose))
+       {
+         PrintAndReturn(progname, ErrorMessage,
+                               ": error linking in '" + Files[i] + "'");
+         return true;
+       }
+     }
+   }
+ 
+   return false;
+ }
+ 
+ //
+ // Function: LinkLibraries ()
+ //
+ // Description:
+ //  This function takes the specified library files and links them into the
+ //  main bytecode object file.
+ //
+ // Inputs:
+ //  progname   - The name of the program (infamous argv[0]).
+ //  HeadModule - The module into which all necessary libraries will be linked.
+ //  Libraries  - The list of libraries to link into the module.
+ //  LibPaths   - The list of library paths in which to find libraries.
+ //  Verbose    - Flags whether verbose messages should be printed.
+ //  Native     - Flags whether native code is being generated.
+ //
+ // Outputs:
+ //  HeadModule - The module will have all necessary libraries linked in.
+ //
+ // Return value:
+ //  FALSE - No error.
+ //  TRUE  - Error.
+ //
+ bool
+ LinkLibraries (const char * progname,
+                Module * HeadModule,
+                const std::vector<std::string> & Libraries,
+                const std::vector<std::string> & LibPaths,
+                bool Verbose,
+                bool Native)
+ {
+   // String in which to receive error messages.
+   std::string ErrorMessage;
+ 
+   for (unsigned i = 1; i < Libraries.size(); ++i)
+   {
+     //
+     // Determine where this library lives.
+     //
+     std::string Pathname = FindLib (Libraries[i], LibPaths);
+     if (Pathname.empty())
+     {
+       //
+       // If the pathname does not exist, then continue to the next one if
+       // we're doing a native link and give an error if we're doing a bytecode
+       // link.
+       //
+       if (Native)
+       {
+         continue;
+       }
+       else
+       {
+         PrintAndReturn (progname, "Cannot find " + Libraries[i]);
+         return true;
+       }
+     }
+ 
+     //
+     // A user may specify an ar archive without -l, perhaps because it
+     // is not installed as a library. Detect that and link the library.
+     //
+     if (IsArchive(Pathname))
+     {
+       if (Verbose)
+       {
+         std::cerr << "Linking archive '" << Libraries[i] << "'\n";
+       }
+ 
+       if (LinkInArchive (HeadModule, Pathname, ErrorMessage, Verbose))
+       {
+         PrintAndReturn(progname, ErrorMessage,
+                               ": Error linking in '" + Libraries[i] + "'");
+         return true;
+       }
+     }
+     else
+     {
+       if (Verbose)
+       {
+         std::cerr << "Linking file '" << Libraries[i] << "'\n";
+       }
+ 
+       if (LinkInFile (HeadModule, Pathname, ErrorMessage, Verbose))
+       {
+         PrintAndReturn(progname, ErrorMessage,
+                               ": error linking in '" + Libraries[i] + "'");
+         return true;
+       }
+     }
+   }
+ 
+   return false;
+ }


Index: llvm/tools/gccld/gccld.cpp
diff -u llvm/tools/gccld/gccld.cpp:1.50 llvm/tools/gccld/gccld.cpp:1.51
--- llvm/tools/gccld/gccld.cpp:1.50	Thu Sep 18 11:22:26 2003
+++ llvm/tools/gccld/gccld.cpp	Fri Sep 19 15:24:23 2003
@@ -26,34 +26,13 @@
 #include "Support/CommandLine.h"
 #include "Support/Signals.h"
 #include "Config/unistd.h"
-#include "util.h"
+#include "gccld.h"
 
 #include <fstream>
 #include <memory>
 #include <set>
 #include <algorithm>
 
-//
-// External function prototypes
-//
-extern int
-GenerateBytecode (Module * M,
-                  bool Strip,
-                  bool Internalize,
-                  std::ofstream * Out);
-
-extern int
-generate_assembly (std::string OutputFilename,
-                   std::string InputFilename,
-                   std::string llc,
-                   char ** const envp);
-extern int
-generate_native (std::string OutputFilename,
-                 std::string InputFilename,
-                 std::vector<std::string> Libraries,
-                 std::string gcc,
-                 char ** const envp);
-
 namespace {
   cl::list<std::string> 
   InputFilenames(cl::Positional, cl::desc("<input bytecode files>"),
@@ -102,180 +81,172 @@
   CO6("r", cl::Hidden, cl::desc("Compatibility option: ignored"));
 }
 
-// FileExists - Return true if the specified string is an openable file...
-static inline bool FileExists(const std::string &FN) {
-  return access(FN.c_str(), F_OK) != -1;
+//
+// Function: PrintAndReturn ()
+//
+// Description:
+//  Prints a message (usually error message) to standard error (stderr) and
+//  returns a value usable for an exit status.
+//
+// Inputs:
+//  progname - The name of the program (i.e. argv[0]).
+//  Message  - The message to print to standard error.
+//  Extra    - Extra information to print between the program name and thei
+//             message.  It is optional.
+//
+// Outputs:
+//  None.
+//
+// Return value:
+//  Returns a value that can be used as the exit status (i.e. for exit()).
+//
+int
+PrintAndReturn (const char *progname,
+                const std::string &Message,
+                const std::string &Extra)
+{
+  std::cerr << progname << Extra << ": " << Message << "\n";
+  return 1;
 }
 
 
-// LoadObject - Read the specified "object file", which should not search the
-// library path to find it.
-static inline std::auto_ptr<Module> LoadObject(std::string FN,
-                                               std::string &OutErrorMessage) {
-  if (Verbose) std::cerr << "Loading '" << FN << "'\n";
-  if (!FileExists(FN)) {
-    // Attempt to load from the LLVM_LIB_SEARCH_PATH directory... if we would
-    // otherwise fail.  This is used to locate objects like crtend.o.
-    //
-    char *SearchPath = getenv("LLVM_LIB_SEARCH_PATH");
-    if (SearchPath && FileExists(std::string(SearchPath)+"/"+FN))
-      FN = std::string(SearchPath)+"/"+FN;
-    else {
-      OutErrorMessage = "could not find input file '" + FN + "'!";
-      return std::auto_ptr<Module>();
-    }
-  }
+//
+//
+// Function: CopyEnv()
+//
+// Description:
+//	This function takes an array of environment variables and makes a
+//	copy of it.  This copy can then be manipulated any way the caller likes
+//  without affecting the process's real environment.
+//
+// Inputs:
+//  envp - An array of C strings containing an environment.
+//
+// Outputs:
+//  None.
+//
+// Return value:
+//  NULL - An error occurred.
+//
+//  Otherwise, a pointer to a new array of C strings is returned.  Every string
+//  in the array is a duplicate of the one in the original array (i.e. we do
+//  not copy the char *'s from one array to another).
+//
+char **
+CopyEnv (char ** const envp)
+{
+  // The new environment list
+  char ** newenv;
 
-  std::string ErrorMessage;
-  Module *Result = ParseBytecodeFile(FN, &ErrorMessage);
-  if (Result) return std::auto_ptr<Module>(Result);
+  // The number of entries in the old environment list
+  int entries;
 
-  OutErrorMessage = "Bytecode file '" + FN + "' corrupt!";
-  if (ErrorMessage.size()) OutErrorMessage += ": " + ErrorMessage;
-  return std::auto_ptr<Module>();
-}
+  //
+  // Count the number of entries in the old list;
+  //
+  for (entries = 0; envp[entries] != NULL; entries++)
+  {
+    ;
+  }
 
+  //
+  // Add one more entry for the NULL pointer that ends the list.
+  //
+  ++entries;
 
-static Module *LoadSingleLibraryObject(const std::string &Filename) {
-  std::string ErrorMessage;
-  std::auto_ptr<Module> M = LoadObject(Filename, ErrorMessage);
-  if (M.get() == 0 && Verbose) {
-    std::cerr << "Error loading '" + Filename + "'";
-    if (!ErrorMessage.empty()) std::cerr << ": " << ErrorMessage;
-    std::cerr << "\n";
+  //
+  // If there are no entries at all, just return NULL.
+  //
+  if (entries == 0)
+  {
+    return NULL;
   }
-  
-  return M.release();
-}
 
-// LoadLibraryExactName - This looks for a file with a known name and tries to
-// load it, similarly to LoadLibraryFromDirectory(). 
-static inline bool LoadLibraryExactName(const std::string &FileName,
-    std::vector<Module*> &Objects, bool &isArchive) {
-  if (Verbose) std::cerr << "  Considering '" << FileName << "'\n";
-  if (FileExists(FileName)) {
-	if (IsArchive(FileName)) {
-      std::string ErrorMessage;
-      if (Verbose) std::cerr << "  Loading '" << FileName << "'\n";
-      if (!ReadArchiveFile(FileName, Objects, &ErrorMessage)) {
-        isArchive = true;
-        return false;           // Success!
-      }
-      if (Verbose) {
-        std::cerr << "  Error loading archive '" + FileName + "'";
-        if (!ErrorMessage.empty()) std::cerr << ": " << ErrorMessage;
-        std::cerr << "\n";
-      }
-    } else {
-      if (Module *M = LoadSingleLibraryObject(FileName)) {
-        isArchive = false;
-        Objects.push_back(M);
-        return false;
-      }
-    }
+  //
+  // Allocate a new environment list.
+  //
+  if ((newenv = new (char *) [entries]) == NULL)
+  {
+    return NULL;
   }
-  return true;
-}
 
-// LoadLibrary - Try to load a library named LIBNAME that contains
-// LLVM bytecode. If SEARCH is true, then search for a file named
-// libLIBNAME.{a,so,bc} in the current library search path.  Otherwise,
-// assume LIBNAME is the real name of the library file.  This method puts
-// the loaded modules into the Objects list, and sets isArchive to true if
-// a .a file was loaded. It returns true if no library is found or if an
-// error occurs; otherwise it returns false.
-//
-static inline bool LoadLibrary(const std::string &LibName,
-                               std::vector<Module*> &Objects, bool &isArchive,
-                               bool search, std::string &ErrorMessage) {
-  if (search) {
-    // First, try the current directory. Then, iterate over the
-    // directories in LibPaths, looking for a suitable match for LibName
-    // in each one.
-    for (unsigned NextLibPathIdx = 0; NextLibPathIdx != LibPaths.size();
-         ++NextLibPathIdx) {
-      std::string Directory = LibPaths[NextLibPathIdx] + "/";
-      if (!LoadLibraryExactName(Directory + "lib" + LibName + ".a",
-        Objects, isArchive))
-          return false;
-      if (!LoadLibraryExactName(Directory + "lib" + LibName + ".so",
-        Objects, isArchive))
-          return false;
-      if (!LoadLibraryExactName(Directory + "lib" + LibName + ".bc",
-        Objects, isArchive))
-          return false;
-    }
-  } else {
-    // If they said no searching, then assume LibName is the real name.
-    if (!LoadLibraryExactName(LibName, Objects, isArchive))
-      return false;
+  //
+  // Make a copy of the list.  Don't forget the NULL that ends the list.
+  //
+  entries = 0;
+  while (envp[entries] != NULL)
+  {
+    newenv[entries] = new char[strlen (envp[entries]) + 1];
+    strcpy (newenv[entries], envp[entries]);
+    ++entries;
   }
-  ErrorMessage = "error linking library '-l" + LibName+ "': library not found!";
-  return true;
+  newenv[entries] = NULL;
+
+  return newenv;
 }
 
 
-static bool LinkLibrary(Module *M, const std::string &LibName,
-                        bool search, std::string &ErrorMessage) {
-  std::set<std::string> UndefinedSymbols;
-  GetAllUndefinedSymbols(M, UndefinedSymbols);
-  if (UndefinedSymbols.empty()) {
-    if (Verbose) std::cerr << "  No symbols undefined, don't link library!\n";
-    return false;  // No need to link anything in!
-  }
+//
+// Function: RemoveEnv()
+//
+// Description:
+//	Remove the specified environment variable from the environment array.
+//
+// Inputs:
+//	name - The name of the variable to remove.  It cannot be NULL.
+//	envp - The array of environment variables.  It cannot be NULL.
+//
+// Outputs:
+//	envp - The pointer to the specified variable name is removed.
+//
+// Return value:
+//	None.
+//
+// Notes:
+//  This is mainly done because functions to remove items from the environment
+//  are not available across all platforms.  In particular, Solaris does not
+//  seem to have an unsetenv() function or a setenv() function (or they are
+//  undocumented if they do exist).
+//
+void
+RemoveEnv (const char * name, char ** const envp)
+{
+  // Pointer for scanning arrays
+  register char * p;
 
-  std::vector<Module*> Objects;
-  bool isArchive;
-  if (LoadLibrary(LibName, Objects, isArchive, search, ErrorMessage))
-    return true;
-
-  // Figure out which symbols are defined by all of the modules in the .a file
-  std::vector<std::set<std::string> > DefinedSymbols;
-  DefinedSymbols.resize(Objects.size());
-  for (unsigned i = 0; i != Objects.size(); ++i)
-    GetAllDefinedSymbols(Objects[i], DefinedSymbols[i]);
-
-  bool Linked = true;
-  while (Linked) {     // While we are linking in object files, loop.
-    Linked = false;
-
-    for (unsigned i = 0; i != Objects.size(); ++i) {
-      // Consider whether we need to link in this module...  we only need to
-      // link it in if it defines some symbol which is so far undefined.
-      //
-      const std::set<std::string> &DefSymbols = DefinedSymbols[i];
+  // Index for selecting elements of the environment array
+  register int index;
 
-      bool ObjectRequired = false;
-      for (std::set<std::string>::iterator I = UndefinedSymbols.begin(),
-             E = UndefinedSymbols.end(); I != E; ++I)
-        if (DefSymbols.count(*I)) {
-          if (Verbose)
-            std::cerr << "  Found object providing symbol '" << *I << "'...\n";
-          ObjectRequired = true;
-          break;
-        }
-      
-      // We DO need to link this object into the program...
-      if (ObjectRequired) {
-        if (LinkModules(M, Objects[i], &ErrorMessage))
-          return true;   // Couldn't link in the right object file...        
-        
-        // Since we have linked in this object, delete it from the list of
-        // objects to consider in this archive file.
-        std::swap(Objects[i], Objects.back());
-        std::swap(DefinedSymbols[i], DefinedSymbols.back());
-        Objects.pop_back();
-        DefinedSymbols.pop_back();
-        --i;   // Do not skip an entry
-        
-        // The undefined symbols set should have shrunk.
-        GetAllUndefinedSymbols(M, UndefinedSymbols);
-        Linked = true;  // We have linked something in!
-      }
+  for (index=0; envp[index] != NULL; index++)
+  {
+    //
+    // Find the first equals sign in the array and make it an EOS character.
+    //
+    p = strchr (envp[index], '=');
+    if (p == NULL)
+    {
+      continue;
+    }
+    else
+    {
+      *p = '\0';
+    }
+
+    //
+    // Compare the two strings.  If they are equal, zap this string.
+    // Otherwise, restore it.
+    //
+    if (!strcmp (name, envp[index]))
+    {
+      *envp[index] = '\0';
+    }
+    else
+    {
+      *p = '=';
     }
   }
-  
-  return false;
+
+  return;
 }
 
 
@@ -296,40 +267,15 @@
   if (char *SearchPath = getenv("LLVM_LIB_SEARCH_PATH"))
     LibPaths.push_back(SearchPath);
 
-  for (unsigned i = 1; i < InputFilenames.size(); ++i) {
-    // A user may specify an ar archive without -l, perhaps because it
-    // is not installed as a library. Detect that and link the library.
-    if (IsArchive(InputFilenames[i])) {
-      if (Verbose) std::cerr << "Linking archive '" << InputFilenames[i]
-                             << "'\n";
-      if (LinkLibrary(Composite.get(), InputFilenames[i], false, ErrorMessage))
-        return PrintAndReturn(argv[0], ErrorMessage,
-                              ": error linking in '" + InputFilenames[i] + "'");
-      continue;
-    }
-
-    std::auto_ptr<Module> M(LoadObject(InputFilenames[i], ErrorMessage));
-    if (M.get() == 0)
-      return PrintAndReturn(argv[0], ErrorMessage);
-
-    if (Verbose) std::cerr << "Linking in '" << InputFilenames[i] << "'\n";
-
-    if (LinkModules(Composite.get(), M.get(), &ErrorMessage))
-      return PrintAndReturn(argv[0], ErrorMessage,
-                            ": error linking in '" + InputFilenames[i] + "'");
-  }
-
   // Remove any consecutive duplicates of the same library...
   Libraries.erase(std::unique(Libraries.begin(), Libraries.end()),
                   Libraries.end());
 
+  // Link in all of the files
+  LinkFiles (argv[0], Composite.get(), InputFilenames, Verbose);
+  LinkLibraries (argv[0], Composite.get(), Libraries, LibPaths, Verbose, Native);
+
   // Link in all of the libraries next...
-  for (unsigned i = 0; i != Libraries.size(); ++i) {
-    if (Verbose) std::cerr << "Linking in library: -l" << Libraries[i] << "\n";
-    if (LinkLibrary(Composite.get(), Libraries[i], true, ErrorMessage))
-      if (!Native)
-        return PrintAndReturn(argv[0], ErrorMessage);
-  }
 
   //
   // Create the output file.
@@ -401,8 +347,10 @@
       //
       // Generate an assembly language file for the bytecode.
       //
-      generate_assembly (AssemblyFile, RealBytecodeOutput, llc, envp);
-      generate_native   (OutputFilename, AssemblyFile, Libraries, gcc, envp);
+      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.


Index: llvm/tools/gccld/gencode.cpp
diff -u llvm/tools/gccld/gencode.cpp:1.1 llvm/tools/gccld/gencode.cpp:1.2
--- llvm/tools/gccld/gencode.cpp:1.1	Thu Sep 18 11:22:26 2003
+++ llvm/tools/gccld/gencode.cpp	Fri Sep 19 15:24:23 2003
@@ -1,4 +1,4 @@
-//===- genexec.cpp - Functions for generating executable files  ------------===//
+//===- gencode.cpp - Functions for generating executable files  -----------===//
 //
 // This file contains functions for generating executable files once linking
 // has finished.  This includes generating a shell script to run the JIT or
@@ -14,11 +14,7 @@
 #include "llvm/PassManager.h"
 #include "llvm/Bytecode/WriteBytecodePass.h"
 #include "Support/SystemUtils.h"
-#include "util.h"
-
-#include <fstream>
-#include <string>
-#include <vector>
+#include "gccld.h"
 
 //
 // Function: GenerateBytecode ()
@@ -43,7 +39,7 @@
 GenerateBytecode (Module * M,
                   bool Strip,
                   bool Internalize,
-                  std::ofstream * Out)
+                  std::ostream * Out)
 {
   // In addition to just linking the input from GCC, we also want to spiff it up
   // a little bit.  Do this now.
@@ -106,7 +102,7 @@
 }
 
 //
-// Function: generate_assembly ()
+// Function: GenerateAssembly ()
 //
 // Description:
 //  This function generates a native assembly language source file from the
@@ -126,10 +122,10 @@
 //  1 - Failure
 //
 int
-generate_assembly (std::string OutputFilename,
-                   std::string InputFilename,
-                   std::string llc,
-                   char ** const envp)
+GenerateAssembly (const std::string & OutputFilename,
+                  const std::string & InputFilename,
+                  const std::string & llc,
+                  char ** const envp)
 {
   //
   // Run LLC to convert the bytecode file into assembly code.
@@ -142,16 +138,12 @@
   cmd[3] =  OutputFilename.c_str();
   cmd[4] =  InputFilename.c_str();
   cmd[5] =  NULL;
-  if ((ExecWait (cmd, envp)) == -1)
-  {
-    return 1;
-  }
 
-  return 0;
+  return (ExecWait (cmd, envp));
 }
 
 //
-// Function: generate_native ()
+// Function: GenerateNative ()
 //
 // Description:
 //  This function generates a native assembly language source file from the
@@ -161,6 +153,7 @@
 //  InputFilename  - The name of the output bytecode file.
 //  OutputFilename - The name of the file to generate.
 //  Libraries      - The list of libraries with which to link.
+//  LibPaths       - The list of directories in which to find libraries.
 //  gcc            - The pathname to use for GGC.
 //  envp           - A copy of the process's current environment.
 //
@@ -172,11 +165,12 @@
 //  1 - Failure
 //
 int
-generate_native (std::string OutputFilename,
-                 std::string InputFilename,
-                 std::vector<std::string> Libraries,
-                 std::string gcc,
-                 char ** const envp)
+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)
 {
   //
   // Remove these environment variables from the environment of the
@@ -187,18 +181,18 @@
   // However, when we invoke GCC below, we want it to use its  normal
   // configuration.  Hence, we must sanitize it's environment.
   //
-  char ** clean_env = copy_env (envp);
+  char ** clean_env = CopyEnv (envp);
   if (clean_env == NULL)
   {
     return 1;
   }
-  remove_env ("LIBRARY_PATH", clean_env);
-  remove_env ("COLLECT_GCC_OPTIONS", clean_env);
-  remove_env ("GCC_EXEC_PREFIX", clean_env);
-  remove_env ("COMPILER_PATH", clean_env);
-  remove_env ("COLLECT_GCC", clean_env);
+  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);
 
-  const char * cmd[8 + Libraries.size()];
+  std::vector<const char *> cmd;
 
   //
   // Run GCC to assemble and link the program into native code.
@@ -208,21 +202,44 @@
   //  and linker because we don't know where to put the _start symbol.
   //  GCC mysteriously knows how to do it.
   //
-  unsigned int index=0;
-  cmd[index++] =  gcc.c_str();
-  cmd[index++] =  "-o";
-  cmd[index++] =  OutputFilename.c_str();
-  cmd[index++] =  InputFilename.c_str();
-  for (; (index - 4) < Libraries.size(); index++)
+  cmd.push_back (gcc.c_str());
+  cmd.push_back ("-o");
+  cmd.push_back (OutputFilename.c_str());
+  cmd.push_back (InputFilename.c_str());
+
+  //
+  // JTC:
+  //  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.
+  //
+#ifdef ndef
+  //
+  // Add in the library path options.
+  //
+  for (unsigned index=0; index < LibPaths.size(); index++)
   {
-    Libraries[index - 4] = "-l" + Libraries[index - 4];
-    cmd[index] = Libraries[index-4].c_str();
+    cmd.push_back ("-L");
+    cmd.push_back (LibPaths[index].c_str());
   }
-  cmd[index++] =  NULL;
-  if ((ExecWait (cmd, clean_env)) == -1)
+#endif
+
+  //
+  // Add in the libraries to link.
+  //
+  std::vector<std::string> Libs (Libraries);
+  for (unsigned index = 0; index < Libs.size(); index++)
   {
-    return 1;
+    Libs[index] = "-l" + Libs[index];
+    cmd.push_back (Libs[index].c_str());
   }
+  cmd.push_back (NULL);
 
-  return 0;
+  //
+  // Run the compiler to assembly and link together the program.
+  //
+  return (ExecWait (&(cmd[0]), clean_env));
 }





More information about the llvm-commits mailing list