Spaces:
Sleeping
Sleeping
| 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 <kernr@mail.ncifcrf.gov> | |
| 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) | |