Spaces:
Running
Running
import re | |
import sys | |
import subprocess | |
__doc__ = """This module generates a DEF file from the symbols in | |
an MSVC-compiled DLL import library. It correctly discriminates between | |
data and functions. The data is collected from the output of the program | |
nm(1). | |
Usage: | |
python lib2def.py [libname.lib] [output.def] | |
or | |
python lib2def.py [libname.lib] > output.def | |
libname.lib defaults to python<py_ver>.lib and output.def defaults to stdout | |
Author: Robert Kern <[email protected]> | |
Last Update: April 30, 1999 | |
""" | |
__version__ = '0.1a' | |
py_ver = "%d%d" % tuple(sys.version_info[:2]) | |
DEFAULT_NM = ['nm', '-Cs'] | |
DEF_HEADER = """LIBRARY python%s.dll | |
;CODE PRELOAD MOVEABLE DISCARDABLE | |
;DATA PRELOAD SINGLE | |
EXPORTS | |
""" % py_ver | |
# the header of the DEF file | |
FUNC_RE = re.compile(r"^(.*) in python%s\.dll" % py_ver, re.MULTILINE) | |
DATA_RE = re.compile(r"^_imp__(.*) in python%s\.dll" % py_ver, re.MULTILINE) | |
def parse_cmd(): | |
"""Parses the command-line arguments. | |
libfile, deffile = parse_cmd()""" | |
if len(sys.argv) == 3: | |
if sys.argv[1][-4:] == '.lib' and sys.argv[2][-4:] == '.def': | |
libfile, deffile = sys.argv[1:] | |
elif sys.argv[1][-4:] == '.def' and sys.argv[2][-4:] == '.lib': | |
deffile, libfile = sys.argv[1:] | |
else: | |
print("I'm assuming that your first argument is the library") | |
print("and the second is the DEF file.") | |
elif len(sys.argv) == 2: | |
if sys.argv[1][-4:] == '.def': | |
deffile = sys.argv[1] | |
libfile = 'python%s.lib' % py_ver | |
elif sys.argv[1][-4:] == '.lib': | |
deffile = None | |
libfile = sys.argv[1] | |
else: | |
libfile = 'python%s.lib' % py_ver | |
deffile = None | |
return libfile, deffile | |
def getnm(nm_cmd=['nm', '-Cs', 'python%s.lib' % py_ver], shell=True): | |
"""Returns the output of nm_cmd via a pipe. | |
nm_output = getnm(nm_cmd = 'nm -Cs py_lib')""" | |
p = subprocess.Popen(nm_cmd, shell=shell, stdout=subprocess.PIPE, | |
stderr=subprocess.PIPE, universal_newlines=True) | |
nm_output, nm_err = p.communicate() | |
if p.returncode != 0: | |
raise RuntimeError('failed to run "%s": "%s"' % ( | |
' '.join(nm_cmd), nm_err)) | |
return nm_output | |
def parse_nm(nm_output): | |
"""Returns a tuple of lists: dlist for the list of data | |
symbols and flist for the list of function symbols. | |
dlist, flist = parse_nm(nm_output)""" | |
data = DATA_RE.findall(nm_output) | |
func = FUNC_RE.findall(nm_output) | |
flist = [] | |
for sym in data: | |
if sym in func and (sym[:2] == 'Py' or sym[:3] == '_Py' or sym[:4] == 'init'): | |
flist.append(sym) | |
dlist = [] | |
for sym in data: | |
if sym not in flist and (sym[:2] == 'Py' or sym[:3] == '_Py'): | |
dlist.append(sym) | |
dlist.sort() | |
flist.sort() | |
return dlist, flist | |
def output_def(dlist, flist, header, file = sys.stdout): | |
"""Outputs the final DEF file to a file defaulting to stdout. | |
output_def(dlist, flist, header, file = sys.stdout)""" | |
for data_sym in dlist: | |
header = header + '\t%s DATA\n' % data_sym | |
header = header + '\n' # blank line | |
for func_sym in flist: | |
header = header + '\t%s\n' % func_sym | |
file.write(header) | |
if __name__ == '__main__': | |
libfile, deffile = parse_cmd() | |
if deffile is None: | |
deffile = sys.stdout | |
else: | |
deffile = open(deffile, 'w') | |
nm_cmd = DEFAULT_NM + [str(libfile)] | |
nm_output = getnm(nm_cmd, shell=False) | |
dlist, flist = parse_nm(nm_output) | |
output_def(dlist, flist, DEF_HEADER, deffile) | |