Blame numpy/distutils/lib2def.py

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