flatcar-scripts/build_library/check_deps
Michael Marineau 1e8f44e3fc fix(check_deps): Depend exclusively on ld.so.conf for lib list
The list in ld.so.conf needs to be complete so don't bother with
including other hard-coded paths or the path to ld-linux-x86-64.so.2.
2013-11-26 16:41:42 -08:00

165 lines
4.2 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 r(?:un)?path: \[([^\]]+)\]")
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 = set()
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.add(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):
rel_p = "/%s" % os.path.relpath(p, self._root)
libdirs.update(self._ReadLdSoConf(rel_p))
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 = self._ReadLdSoConf("/etc/ld.so.conf")
if self._verbose:
print "Library search path: %s" % " ".join(sorted(libdirs))
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()