brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.2 KiB · f185900 Raw
169 lines · python
1#!/usr/bin/env python32 3#4# //===----------------------------------------------------------------------===//5# //6# // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.7# // See https://llvm.org/LICENSE.txt for license information.8# // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception9# //10# //===----------------------------------------------------------------------===//11#12 13import argparse14import os15import platform16import re17import sys18from libomputils import (19    ScriptError,20    error,21    execute_command,22    print_info_line,23    print_error_line,24)25 26 27def get_deps_readelf(filename):28    """Get list of dependencies from readelf"""29    deps = []30    # Force readelf call to be in English31    os.environ["LANG"] = "C"32    r = execute_command(["readelf", "-d", filename])33    if r.returncode != 0:34        error("readelf -d {} failed".format(filename))35    neededRegex = re.compile(r"\(NEEDED\)\s+Shared library: \[([a-zA-Z0-9_.-]+)\]")36    for line in r.stdout.split(os.linesep):37        match = neededRegex.search(line)38        if match:39            deps.append(match.group(1))40    return deps41 42 43def get_deps_otool(filename):44    """Get list of dependencies from otool"""45    deps = []46    r = execute_command(["otool", "-L", filename])47    if r.returncode != 0:48        error("otool -L {} failed".format(filename))49    libRegex = re.compile(r"([^ \t]+)\s+\(compatibility version ")50    thisLibRegex = re.compile(r"@rpath/{}".format(os.path.basename(filename)))51    for line in r.stdout.split(os.linesep):52        match = thisLibRegex.search(line)53        if match:54            # Don't include the library itself as a needed dependency55            continue56        match = libRegex.search(line)57        if match:58            deps.append(match.group(1))59            continue60    return deps61 62 63def get_deps_link(filename):64    """Get list of dependecies from link (Windows OS)"""65    depsSet = set([])66    f = filename.lower()67    args = ["link", "/DUMP"]68    if f.endswith(".lib"):69        args.append("/DIRECTIVES")70    elif f.endswith(".dll") or f.endswith(".exe"):71        args.append("/DEPENDENTS")72    else:73        error("unrecognized file extension: {}".format(filename))74    args.append(filename)75    r = execute_command(args)76    if r.returncode != 0:77        error("{} failed".format(args.command))78    if f.endswith(".lib"):79        regex = re.compile(r"\s*[-/]defaultlib:(.*)\s*$")80        for line in r.stdout.split(os.linesep):81            line = line.lower()82            match = regex.search(line)83            if match:84                depsSet.add(match.group(1))85    else:86        started = False87        markerStart = re.compile(r"Image has the following depend")88        markerEnd = re.compile(r"Summary")89        markerEnd2 = re.compile(r"Image has the following delay load depend")90        for line in r.stdout.split(os.linesep):91            if not started:92                if markerStart.search(line):93                    started = True94                    continue95            else:  # Started parsing the libs96                line = line.strip()97                if not line:98                    continue99                if markerEnd.search(line) or markerEnd2.search(line):100                    break101                depsSet.add(line.lower())102    return list(depsSet)103 104 105def main():106    parser = argparse.ArgumentParser(description="Check library dependencies")107    parser.add_argument(108        "--bare",109        action="store_true",110        help="Produce plain, bare output: just a list"111        " of libraries, a library per line",112    )113    parser.add_argument(114        "--expected",115        metavar="CSV_LIST",116        help="CSV_LIST is a comma-separated list of expected"117        ' dependencies (or "none"). checks the specified'118        " library has only expected dependencies.",119    )120 121    parser.add_argument("library", help="The library file to check")122    commandArgs = parser.parse_args()123    # Get dependencies124    deps = []125 126    system = platform.system()127    if system == "Windows":128        deps = get_deps_link(commandArgs.library)129    elif system == "Darwin":130        deps = get_deps_otool(commandArgs.library)131    else:132        deps = get_deps_readelf(commandArgs.library)133    deps = sorted(deps)134 135    # If bare output specified, then just print the dependencies one per line136    if commandArgs.bare:137        print(os.linesep.join(deps))138        return139 140    # Calculate unexpected dependencies if expected list specified141    unexpected = []142    if commandArgs.expected:143        # none => any dependency is unexpected144        if commandArgs.expected == "none":145            unexpected = list(deps)146        else:147            expected = [d.strip() for d in commandArgs.expected.split(",")]148            unexpected = [d for d in deps if d not in expected]149 150    # Regular output151    print_info_line("Dependencies:")152    for dep in deps:153        print_info_line("    {}".format(dep))154    if unexpected:155        print_error_line("Unexpected Dependencies:")156        for dep in unexpected:157            print_error_line("    {}".format(dep))158        error("found unexpected dependencies")159 160 161if __name__ == "__main__":162    try:163        main()164    except ScriptError as e:165        print_error_line(str(e))166        sys.exit(1)167 168# end of file169