mirror of
https://github.com/flatcar/scripts.git
synced 2025-08-08 05:26:58 +02:00
Rather than hardcoding every possible multilib path that we might come across, look up the native multilib path that the target system is using by finding the native ELF interpreter. We use /bin/sh as a known good file since you can't really have a system without this. BUG=chromium-os:20636 TEST=`./check_deps /build/amd64-generic /bin/bash` now finds libs without explicit ld.so.conf TEST=`./build_image --board=x86-alex` still works Change-Id: Ib80824312a5e5a0f9e17e8ae18a2d42248771eb7 Reviewed-on: http://gerrit.chromium.org/gerrit/8564 Commit-Ready: Mike Frysinger <vapier@chromium.org> Reviewed-by: Mike Frysinger <vapier@chromium.org> Tested-by: Mike Frysinger <vapier@chromium.org>
191 lines
5.1 KiB
Python
Executable File
191 lines
5.1 KiB
Python
Executable File
#!/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
|
|
import glob
|
|
|
|
_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 _ReadLdSoConf(self, path):
|
|
"""Parse ld.so.conf files.
|
|
|
|
Starting with the file at PATH (searched relative to self._root), return
|
|
all the valid libdirs found. Include directives are handled recursively.
|
|
|
|
Args:
|
|
path: the path to the ld.so.conf file (inside of the root).
|
|
|
|
Returns:
|
|
A list of valid libdirs.
|
|
"""
|
|
|
|
libdirs = []
|
|
|
|
ld_so_conf = self._root + path
|
|
if os.path.exists(ld_so_conf):
|
|
f = file(ld_so_conf)
|
|
|
|
for line in f:
|
|
line = line.rstrip()
|
|
|
|
if line.startswith("/"):
|
|
libpath = self._root + line
|
|
if os.path.exists(libpath):
|
|
libdirs.append(libpath)
|
|
|
|
elif line.startswith("include "):
|
|
# Includes are absolute or relative to the file itself.
|
|
line = os.path.join(os.path.dirname(path), line[8:])
|
|
for p in glob.glob(self._root + line):
|
|
libdirs.extend(self._ReadLdSoConf(os.path.relpath(p, self._root)))
|
|
|
|
f.close()
|
|
|
|
return libdirs
|
|
|
|
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
|
|
|
|
libdirs = []
|
|
|
|
# Add the native paths. Get the ELF interpreter from a known file
|
|
# and assume that the path it is in is our native libdir. So here
|
|
# we would get something like "/lib64/ld-linux-x86-64.so.2".
|
|
elf = "/bin/sh"
|
|
f = os.popen("scanelf -qF'%%i#p' %s/%s" % (root, elf))
|
|
native_libdir = os.path.dirname(f.readline().rstrip())
|
|
f.close()
|
|
if len(native_libdir) == 0:
|
|
print >>sys.stderr, "Problem with %s: can't find ELF interp" % elf
|
|
sys.exit(1)
|
|
elif native_libdir != "/lib":
|
|
libdirs.extend([
|
|
"%s/%s" % (root, native_libdir),
|
|
"%s/usr%s" % (root, native_libdir)
|
|
])
|
|
|
|
# Insert some default directories into our library cache.
|
|
libdirs.extend([
|
|
"%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.
|
|
libdirs.extend(self._ReadLdSoConf("/etc/ld.so.conf"))
|
|
|
|
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()
|