4 # //===----------------------------------------------------------------------===//
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-exception
10 # //===----------------------------------------------------------------------===//
18 from libomputils
import (
27 def get_deps_readelf(filename
):
28 """Get list of dependencies from readelf"""
30 # Force readelf call to be in English
31 os
.environ
["LANG"] = "C"
32 r
= execute_command(["readelf", "-d", filename
])
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
)
39 deps
.append(match
.group(1))
43 def get_deps_otool(filename
):
44 """Get list of dependencies from otool"""
46 r
= execute_command(["otool", "-L", filename
])
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
)
54 # Don't include the library itself as a needed dependency
56 match
= libRegex
.search(line
)
58 deps
.append(match
.group(1))
63 def get_deps_link(filename
):
64 """Get list of dependecies from link (Windows OS)"""
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")
73 error("unrecognized file extension: {}".format(filename
))
75 r
= execute_command(args
)
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
):
82 match
= regex
.search(line
)
84 depsSet
.add(match
.group(1))
87 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
):
92 if markerStart
.search(line
):
95 else: # Started parsing the libs
99 if markerEnd
.search(line
) or markerEnd2
.search(line
):
101 depsSet
.add(line
.lower())
106 parser
= argparse
.ArgumentParser(description
="Check library dependencies")
110 help="Produce plain, bare output: just a list"
111 " of libraries, a library per line",
116 help="CSV_LIST is a comma-separated list of expected"
117 ' dependencies (or "none"). checks the specified'
118 " library has only expected dependencies.",
121 parser
.add_argument("library", help="The library file to check")
122 commandArgs
= parser
.parse_args()
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
)
132 deps
= get_deps_readelf(commandArgs
.library
)
135 # If bare output specified, then just print the dependencies one per line
137 print(os
.linesep
.join(deps
))
140 # Calculate unexpected dependencies if expected list specified
142 if commandArgs
.expected
:
143 # none => any dependency is unexpected
144 if commandArgs
.expected
== "none":
145 unexpected
= list(deps
)
147 expected
= [d
.strip() for d
in commandArgs
.expected
.split(",")]
148 unexpected
= [d
for d
in deps
if d
not in expected
]
151 print_info_line("Dependencies:")
153 print_info_line(" {}".format(dep
))
155 print_error_line("Unexpected Dependencies:")
156 for dep
in unexpected
:
157 print_error_line(" {}".format(dep
))
158 error("found unexpected dependencies")
161 if __name__
== "__main__":
164 except ScriptError
as e
:
165 print_error_line(str(e
))