1#!/usr/bin/env python 2# Copyright 2017 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6"""Given a binary, uses dpkg-shlibdeps to check that its package dependencies 7are satisfiable on all supported debian-based distros. 8""" 9 10import argparse 11import json 12import os 13import re 14import subprocess 15import sys 16 17import deb_version 18import package_version_interval 19 20parser = argparse.ArgumentParser() 21parser.add_argument('binary') 22parser.add_argument('sysroot') 23parser.add_argument('arch') 24parser.add_argument('dep_filename') 25parser.add_argument('--distro-check', action='store_true') 26args = parser.parse_args() 27 28binary = os.path.abspath(args.binary) 29sysroot = os.path.abspath(args.sysroot) 30arch = args.arch 31dep_filename = os.path.abspath(args.dep_filename) 32distro_check = args.distro_check 33 34script_dir = os.path.dirname(os.path.realpath(__file__)) 35dpkg_shlibdeps = os.path.join(script_dir, '..', '..', '..', '..', 'third_party', 36 'dpkg-shlibdeps', 'dpkg-shlibdeps.pl') 37 38cmd = [dpkg_shlibdeps, '--ignore-weak-undefined'] 39if arch == 'x64': 40 cmd.extend(['-l%s/usr/lib/x86_64-linux-gnu' % sysroot, 41 '-l%s/lib/x86_64-linux-gnu' % sysroot]) 42elif arch == 'x86': 43 cmd.extend(['-l%s/usr/lib/i386-linux-gnu' % sysroot, 44 '-l%s/lib/i386-linux-gnu' % sysroot]) 45elif arch == 'arm': 46 cmd.extend(['-l%s/usr/lib/arm-linux-gnueabihf' % sysroot, 47 '-l%s/lib/arm-linux-gnueabihf' % sysroot]) 48elif arch == 'arm64': 49 cmd.extend(['-l%s/usr/lib/aarch64-linux-gnu' % sysroot, 50 '-l%s/lib/aarch64-linux-gnu' % sysroot]) 51elif arch == 'mipsel': 52 cmd.extend(['-l%s/usr/lib/mipsel-linux-gnu' % sysroot, 53 '-l%s/lib/mipsel-linux-gnu' % sysroot]) 54elif arch == 'mips64el': 55 cmd.extend(['-l%s/usr/lib/mips64el-linux-gnuabi64' % sysroot, 56 '-l%s/lib/mips64el-linux-gnuabi64' % sysroot]) 57else: 58 print 'Unsupported architecture ' + arch 59 sys.exit(1) 60cmd.extend(['-l%s/usr/lib' % sysroot, '-O', '-e', binary]) 61 62proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, 63 cwd=sysroot) 64(stdout, stderr) = proc.communicate() 65exit_code = proc.wait() 66if exit_code != 0: 67 print 'dpkg-shlibdeps failed with exit code ' + str(exit_code) 68 print 'stderr was ' + stderr 69 sys.exit(1) 70 71SHLIBS_DEPENDS_PREFIX = 'shlibs:Depends=' 72deps_str = '' 73for line in stdout.split('\n'): 74 if line.startswith(SHLIBS_DEPENDS_PREFIX): 75 deps_str = line[len(SHLIBS_DEPENDS_PREFIX):] 76deps = deps_str.split(', ') 77interval_sets = [] 78if deps_str != '': 79 for dep in deps: 80 interval_sets.append(package_version_interval.parse_interval_set(dep)) 81 82script_dir = os.path.dirname(os.path.abspath(__file__)) 83deps_file = os.path.join(script_dir, 'dist_package_versions.json') 84distro_package_versions = json.load(open(deps_file)) 85 86ret_code = 0 87if distro_check: 88 for distro in distro_package_versions: 89 for interval_set in interval_sets: 90 dep_satisfiable = False 91 for interval in interval_set.intervals: 92 package = interval.package 93 if package not in distro_package_versions[distro]: 94 continue 95 distro_version = deb_version.DebVersion( 96 distro_package_versions[distro][package]) 97 if interval.contains(distro_version): 98 dep_satisfiable = True 99 break 100 if not dep_satisfiable: 101 print >> sys.stderr, ( 102 'Dependency %s not satisfiable on distro %s caused by binary %s' % ( 103 interval_set.formatted(), distro, os.path.basename(binary))) 104 ret_code = 1 105if ret_code == 0: 106 with open(dep_filename, 'w') as dep_file: 107 lines = [interval_set.formatted() + '\n' 108 for interval_set in interval_sets] 109 dep_file.write(''.join(sorted(lines))) 110sys.exit(ret_code) 111