Chris@87
|
1 from __future__ import division, absolute_import, print_function
|
Chris@87
|
2
|
Chris@87
|
3 import re
|
Chris@87
|
4 import sys
|
Chris@87
|
5 import os
|
Chris@87
|
6 import subprocess
|
Chris@87
|
7
|
Chris@87
|
8 __doc__ = """This module generates a DEF file from the symbols in
|
Chris@87
|
9 an MSVC-compiled DLL import library. It correctly discriminates between
|
Chris@87
|
10 data and functions. The data is collected from the output of the program
|
Chris@87
|
11 nm(1).
|
Chris@87
|
12
|
Chris@87
|
13 Usage:
|
Chris@87
|
14 python lib2def.py [libname.lib] [output.def]
|
Chris@87
|
15 or
|
Chris@87
|
16 python lib2def.py [libname.lib] > output.def
|
Chris@87
|
17
|
Chris@87
|
18 libname.lib defaults to python<py_ver>.lib and output.def defaults to stdout
|
Chris@87
|
19
|
Chris@87
|
20 Author: Robert Kern <kernr@mail.ncifcrf.gov>
|
Chris@87
|
21 Last Update: April 30, 1999
|
Chris@87
|
22 """
|
Chris@87
|
23
|
Chris@87
|
24 __version__ = '0.1a'
|
Chris@87
|
25
|
Chris@87
|
26 py_ver = "%d%d" % tuple(sys.version_info[:2])
|
Chris@87
|
27
|
Chris@87
|
28 DEFAULT_NM = 'nm -Cs'
|
Chris@87
|
29
|
Chris@87
|
30 DEF_HEADER = """LIBRARY python%s.dll
|
Chris@87
|
31 ;CODE PRELOAD MOVEABLE DISCARDABLE
|
Chris@87
|
32 ;DATA PRELOAD SINGLE
|
Chris@87
|
33
|
Chris@87
|
34 EXPORTS
|
Chris@87
|
35 """ % py_ver
|
Chris@87
|
36 # the header of the DEF file
|
Chris@87
|
37
|
Chris@87
|
38 FUNC_RE = re.compile(r"^(.*) in python%s\.dll" % py_ver, re.MULTILINE)
|
Chris@87
|
39 DATA_RE = re.compile(r"^_imp__(.*) in python%s\.dll" % py_ver, re.MULTILINE)
|
Chris@87
|
40
|
Chris@87
|
41 def parse_cmd():
|
Chris@87
|
42 """Parses the command-line arguments.
|
Chris@87
|
43
|
Chris@87
|
44 libfile, deffile = parse_cmd()"""
|
Chris@87
|
45 if len(sys.argv) == 3:
|
Chris@87
|
46 if sys.argv[1][-4:] == '.lib' and sys.argv[2][-4:] == '.def':
|
Chris@87
|
47 libfile, deffile = sys.argv[1:]
|
Chris@87
|
48 elif sys.argv[1][-4:] == '.def' and sys.argv[2][-4:] == '.lib':
|
Chris@87
|
49 deffile, libfile = sys.argv[1:]
|
Chris@87
|
50 else:
|
Chris@87
|
51 print("I'm assuming that your first argument is the library")
|
Chris@87
|
52 print("and the second is the DEF file.")
|
Chris@87
|
53 elif len(sys.argv) == 2:
|
Chris@87
|
54 if sys.argv[1][-4:] == '.def':
|
Chris@87
|
55 deffile = sys.argv[1]
|
Chris@87
|
56 libfile = 'python%s.lib' % py_ver
|
Chris@87
|
57 elif sys.argv[1][-4:] == '.lib':
|
Chris@87
|
58 deffile = None
|
Chris@87
|
59 libfile = sys.argv[1]
|
Chris@87
|
60 else:
|
Chris@87
|
61 libfile = 'python%s.lib' % py_ver
|
Chris@87
|
62 deffile = None
|
Chris@87
|
63 return libfile, deffile
|
Chris@87
|
64
|
Chris@87
|
65 def getnm(nm_cmd = ['nm', '-Cs', 'python%s.lib' % py_ver]):
|
Chris@87
|
66 """Returns the output of nm_cmd via a pipe.
|
Chris@87
|
67
|
Chris@87
|
68 nm_output = getnam(nm_cmd = 'nm -Cs py_lib')"""
|
Chris@87
|
69 f = subprocess.Popen(nm_cmd, shell=True, stdout=subprocess.PIPE)
|
Chris@87
|
70 nm_output = f.stdout.read()
|
Chris@87
|
71 f.stdout.close()
|
Chris@87
|
72 return nm_output
|
Chris@87
|
73
|
Chris@87
|
74 def parse_nm(nm_output):
|
Chris@87
|
75 """Returns a tuple of lists: dlist for the list of data
|
Chris@87
|
76 symbols and flist for the list of function symbols.
|
Chris@87
|
77
|
Chris@87
|
78 dlist, flist = parse_nm(nm_output)"""
|
Chris@87
|
79 data = DATA_RE.findall(nm_output)
|
Chris@87
|
80 func = FUNC_RE.findall(nm_output)
|
Chris@87
|
81
|
Chris@87
|
82 flist = []
|
Chris@87
|
83 for sym in data:
|
Chris@87
|
84 if sym in func and (sym[:2] == 'Py' or sym[:3] == '_Py' or sym[:4] == 'init'):
|
Chris@87
|
85 flist.append(sym)
|
Chris@87
|
86
|
Chris@87
|
87 dlist = []
|
Chris@87
|
88 for sym in data:
|
Chris@87
|
89 if sym not in flist and (sym[:2] == 'Py' or sym[:3] == '_Py'):
|
Chris@87
|
90 dlist.append(sym)
|
Chris@87
|
91
|
Chris@87
|
92 dlist.sort()
|
Chris@87
|
93 flist.sort()
|
Chris@87
|
94 return dlist, flist
|
Chris@87
|
95
|
Chris@87
|
96 def output_def(dlist, flist, header, file = sys.stdout):
|
Chris@87
|
97 """Outputs the final DEF file to a file defaulting to stdout.
|
Chris@87
|
98
|
Chris@87
|
99 output_def(dlist, flist, header, file = sys.stdout)"""
|
Chris@87
|
100 for data_sym in dlist:
|
Chris@87
|
101 header = header + '\t%s DATA\n' % data_sym
|
Chris@87
|
102 header = header + '\n' # blank line
|
Chris@87
|
103 for func_sym in flist:
|
Chris@87
|
104 header = header + '\t%s\n' % func_sym
|
Chris@87
|
105 file.write(header)
|
Chris@87
|
106
|
Chris@87
|
107 if __name__ == '__main__':
|
Chris@87
|
108 libfile, deffile = parse_cmd()
|
Chris@87
|
109 if deffile is None:
|
Chris@87
|
110 deffile = sys.stdout
|
Chris@87
|
111 else:
|
Chris@87
|
112 deffile = open(deffile, 'w')
|
Chris@87
|
113 nm_cmd = [str(DEFAULT_NM), str(libfile)]
|
Chris@87
|
114 nm_output = getnm(nm_cmd)
|
Chris@87
|
115 dlist, flist = parse_nm(nm_output)
|
Chris@87
|
116 output_def(dlist, flist, DEF_HEADER, deffile)
|