[LLVMdev] allow gcc .... /full/path/to/libfoo.a

Brian R. Gaeke gaeke at uiuc.edu
Thu May 22 23:03:02 PDT 2003


gccld would barf if you tried to specify the full pathname of an archive
on the command line to gcc, (e.g., instead of gcc ... -L/full/path/to -lFOO
you say gcc ... /full/path/to/libFOO.a) which many GNU Makefiles try to do. 
This patch fixes that.

Ok to commit?

-- 
gaeke at uiuc.edu

gccld.cpp:
 Fix typo in header.
 Add IsArchive static method.
 Roll LoadLibraryFromDirectory() into LoadLibrary(), and factor
  LoadLibraryExactName() out of the result. Instead of treating the current
  directory specially, just insert it into LibPaths in the beginning of
  main().
 Make LoadLibrary() take a "search" flag that says whether to search for the 
  correct library, or just trust that LibName is right.
 Make LinkLibrary() take a "search" flag, and pass it to LoadLibrary().
 Change the for-loop over InputFilenames to detect ar archives and link them
  in as libraries without searching.
 Change the for-loop over Libraries to explicitly turn on the "search" flag
  to LinkLibrary() that makes LoadLibrary() search for the correct library
  (i.e., when processing -lNAME options.)

cvs diff: Diffing .
Index: gccld.cpp
===================================================================
RCS file: /home/vadve/vadve/Research/DynOpt/CVSRepository/llvm/tools/gccld/gccld.cpp,v
retrieving revision 1.30
diff -u -a -d -p -r1.30 gccld.cpp
--- gccld.cpp	13 May 2003 22:14:13 -0000	1.30
+++ gccld.cpp	23 May 2003 03:43:48 -0000
@@ -9,7 +9,7 @@
 //
 // 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.
+// I'm not too worried about this.
 //
 //===----------------------------------------------------------------------===//
 
@@ -117,70 +117,80 @@ static Module *LoadSingleLibraryObject(c
   return M.release();
 }
 
+// IsArchive -  Returns true iff FILENAME appears to be the name of an ar
+// archive file. It determines this by checking the magic string at the
+// beginning of the file.
+static bool IsArchive (const std::string &filename) {
+  static const 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);
+}
 
-// LoadLibraryFromDirectory - This looks for a .a, .so, or .bc file in a
-// particular directory.  It returns true if no library is found, otherwise it
-// puts the loaded modules into the Objects list, and sets isArchive to true if
-// a .a file was loaded.
-//
-static inline bool LoadLibraryFromDirectory(const std::string &LibName,
-                                            const std::string &Directory,
-                                            std::vector<Module*> &Objects,
-                                            bool &isArchive) {
-  if (FileExists(Directory + "lib" + LibName + ".a")) {
-    std::string ErrorMessage;
-    if (Verbose) std::cerr << "  Loading '" << Directory << "lib"
-                           << LibName << ".a'\n";
-    if (!ReadArchiveFile(Directory + "lib" + LibName + ".a", Objects,
-                         &ErrorMessage)) {   // Read the archive file
-      isArchive = true;
-      return false;           // Success!
-    }
-
-    if (Verbose) {
-      std::cerr << "  Error loading archive '" + Directory +"lib"+LibName+".a'";
-      if (!ErrorMessage.empty()) std::cerr << ": " << ErrorMessage;
-      std::cerr << "\n";
+// 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;
+      }
     }
   }
-
-  if (FileExists(Directory + "lib" + LibName + ".so"))
-    if (Module *M = LoadSingleLibraryObject(Directory + "lib" + LibName+".so")){
-      isArchive = false;
-      Objects.push_back(M);
-      return false;
-    }
-
-  if (FileExists(Directory + "lib" + LibName + ".bc"))
-    if (Module *M = LoadSingleLibraryObject(Directory + "lib" + LibName+".bc")){
-      isArchive = false;
-      Objects.push_back(M);
-      return false;
-    }
   return true;
 }
 
-// LoadLibrary - This searches for a .a, .so, or .bc file which provides the
-// LLVM bytecode for the library.  It returns true if no library is found,
-// otherwise it puts the loaded modules into the Objects list, and sets
-// isArchive to true if a .a file was loaded.
+// 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,
-                               std::string &ErrorMessage) {
-  std::string Directory;
-  unsigned NextLibPathIdx = 0;
-
-  while (1) {
-    // Try loading from the current directory...
-    if (Verbose) std::cerr << "  Looking in directory '" << Directory << "'\n";
-    if (!LoadLibraryFromDirectory(LibName, Directory, Objects, 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;
-
-    if (NextLibPathIdx == LibPaths.size()) break;
-    Directory = LibPaths[NextLibPathIdx++]+"/";
   }
-
   ErrorMessage = "error linking library '-l" + LibName+ "': library not found!";
   return true;
 }
@@ -231,7 +241,7 @@ static void GetAllUndefinedSymbols(Modul
 
 
 static bool LinkLibrary(Module *M, const std::string &LibName,
-                        std::string &ErrorMessage) {
+                        bool search, std::string &ErrorMessage) {
   std::set<std::string> UndefinedSymbols;
   GetAllUndefinedSymbols(M, UndefinedSymbols);
   if (UndefinedSymbols.empty()) {
@@ -241,7 +251,8 @@ static bool LinkLibrary(Module *M, const
 
   std::vector<Module*> Objects;
   bool isArchive;
-  if (LoadLibrary(LibName, Objects, isArchive, ErrorMessage)) return true;
+  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;
@@ -307,11 +318,25 @@ int main(int argc, char **argv) {
   if (Composite.get() == 0)
     return PrintAndReturn(argv[0], ErrorMessage);
 
+  // We always look first in the current directory when searching for libraries.
+  LibPaths.insert(LibPaths.begin(), ".");
+
   // If the user specied an extra search path in their environment, respect it.
   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);
@@ -330,7 +355,7 @@ int main(int argc, char **argv) {
   // 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], ErrorMessage))
+    if (LinkLibrary(Composite.get(), Libraries[i], true, ErrorMessage))
       return PrintAndReturn(argv[0], ErrorMessage);
   }
 



More information about the llvm-dev mailing list