#!/usr/bin/python # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import os import re import sys _SHARED_RE = re.compile(r"Shared library: \[([^\]]+)\]") _RPATH_RE = re.compile(r"Library rpath: \[([^\]]+)\]") class CheckDependencies(object): """Check that dependencies for binaries can be found in the specified dir.""" def __init__(self, root, verbose=False): """Initializer. Args: root: The sysroot (e.g. "/") verbose: Print helpful messages. """ self._root = root self._libcache = set() self._verbose = verbose # Insert some default directories into our library cache. libdirs = [ "%s/lib" % root, "%s/usr/lib" % root, "%s/opt/google/o3d/lib" % root, "%s/usr/lib/opengl/xorg-x11/lib" % root, "%s/usr/local/lib/icedtea6/jre/lib/i386/client" % root, "%s/usr/local/lib/icedtea6/jre/lib/i386/headless" % root ] # Read more directories from ld.so.conf. ld_so_conf = "%s/etc/ld.so.conf" % root if os.path.exists(ld_so_conf): f = file(ld_so_conf) for line in f: if line.startswith("/"): path = root + line[:-1] if os.path.exists(path): libdirs.append(path) f.close() self._ReadLibs(libdirs, self._libcache) def _ReadLibs(self, paths, libcache): for path in paths: if os.path.exists(path): for lib in os.listdir(path): libcache.add(lib) def _ReadDependencies(self, binary): """Run readelf -d on BINARY, returning (deps, rpaths).""" deps = set() rpaths = set() # Read list of dynamic libraries, ignoring error messages that occur # when we look at files that aren't actually libraries f = os.popen("readelf -d '%s' 2>/dev/null" % binary) for line in f: # Grab dependencies m = _SHARED_RE.search(line) if m: deps.add(m.group(1)) # Add RPATHs in our search path m = _RPATH_RE.search(line) if m: for path in m.group(1).split(":"): if path.startswith("$ORIGIN"): rpaths.add(path.replace("$ORIGIN", os.path.dirname(binary))) else: rpaths.add(os.path.join(self._root, path[1:])) f.close() return (deps, rpaths) def CheckDependencies(self, binary): """Check whether the libs for BINARY can be found in our sysroot.""" good = True deps, rpaths = self._ReadDependencies(binary) if self._verbose: for lib in self._libcache & deps: print "Found %s" % lib for lib in deps - self._libcache: if lib[0] != "/": for path in rpaths: if os.path.exists(os.path.join(path, lib)): if self._verbose: print "Found %s" % lib break else: print >>sys.stderr, "Problem with %s: Can't find %s" % (binary, lib) good = False else: full_path = os.path.join(self._root, lib[1:]) if os.path.exists(full_path): if self._verbose: print "Found %s" % lib else: print >>sys.stderr, "Problem with %s: Can't find %s" % (binary, lib) good = False return good def main(): if len(sys.argv) < 3: print "Usage: %s [-v] sysroot binary [ binary ... ]" % sys.argv[0] sys.exit(1) verbose = False if sys.argv[1] == "-v": verbose = True sys.argv = sys.argv[0:1] + sys.argv[2:] checker = CheckDependencies(sys.argv[1], verbose) errors = False for binary in sys.argv[2:]: if verbose: print "Checking %s" % binary if not checker.CheckDependencies(binary): errors = True if errors: sys.exit(1) else: sys.exit(0) if __name__ == "__main__": main()