mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 19:34:08 +00:00 
			
		
		
		
	(a) "except E, V" -> "except E as V" (b) V is now limited to a simple name (local variable) (c) V is now deleted at the end of the except block
		
			
				
	
	
		
			188 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""Extension management for Windows.
 | 
						|
 | 
						|
Under Windows it is unlikely the .obj files are of use, as special compiler options
 | 
						|
are needed (primarily to toggle the behavior of "public" symbols.
 | 
						|
 | 
						|
I dont consider it worth parsing the MSVC makefiles for compiler options.  Even if
 | 
						|
we get it just right, a specific freeze application may have specific compiler
 | 
						|
options anyway (eg, to enable or disable specific functionality)
 | 
						|
 | 
						|
So my basic stragtegy is:
 | 
						|
 | 
						|
* Have some Windows INI files which "describe" one or more extension modules.
 | 
						|
  (Freeze comes with a default one for all known modules - but you can specify
 | 
						|
  your own).
 | 
						|
* This description can include:
 | 
						|
  - The MSVC .dsp file for the extension.  The .c source file names
 | 
						|
    are extraced from there.
 | 
						|
  - Specific compiler/linker options
 | 
						|
  - Flag to indicate if Unicode compilation is expected.
 | 
						|
 | 
						|
At the moment the name and location of this INI file is hardcoded,
 | 
						|
but an obvious enhancement would be to provide command line options.
 | 
						|
"""
 | 
						|
 | 
						|
import os, sys
 | 
						|
try:
 | 
						|
    import win32api
 | 
						|
except ImportError:
 | 
						|
    win32api = None # User has already been warned
 | 
						|
 | 
						|
class CExtension:
 | 
						|
    """An abstraction of an extension implemented in C/C++
 | 
						|
    """
 | 
						|
    def __init__(self, name, sourceFiles):
 | 
						|
        self.name = name
 | 
						|
        # A list of strings defining additional compiler options.
 | 
						|
        self.sourceFiles = sourceFiles
 | 
						|
        # A list of special compiler options to be applied to
 | 
						|
        # all source modules in this extension.
 | 
						|
        self.compilerOptions = []
 | 
						|
        # A list of .lib files the final .EXE will need.
 | 
						|
        self.linkerLibs = []
 | 
						|
 | 
						|
    def GetSourceFiles(self):
 | 
						|
        return self.sourceFiles
 | 
						|
 | 
						|
    def AddCompilerOption(self, option):
 | 
						|
        self.compilerOptions.append(option)
 | 
						|
    def GetCompilerOptions(self):
 | 
						|
        return self.compilerOptions
 | 
						|
 | 
						|
    def AddLinkerLib(self, lib):
 | 
						|
        self.linkerLibs.append(lib)
 | 
						|
    def GetLinkerLibs(self):
 | 
						|
        return self.linkerLibs
 | 
						|
 | 
						|
def checkextensions(unknown, extra_inis, prefix):
 | 
						|
    # Create a table of frozen extensions
 | 
						|
 | 
						|
    defaultMapName = os.path.join( os.path.split(sys.argv[0])[0], "extensions_win32.ini")
 | 
						|
    if not os.path.isfile(defaultMapName):
 | 
						|
        sys.stderr.write("WARNING: %s can not be found - standard extensions may not be found\n" % defaultMapName)
 | 
						|
    else:
 | 
						|
        # must go on end, so other inis can override.
 | 
						|
        extra_inis.append(defaultMapName)
 | 
						|
 | 
						|
    ret = []
 | 
						|
    for mod in unknown:
 | 
						|
        for ini in extra_inis:
 | 
						|
#                       print "Looking for", mod, "in", win32api.GetFullPathName(ini),"...",
 | 
						|
            defn = get_extension_defn( mod, ini, prefix )
 | 
						|
            if defn is not None:
 | 
						|
#                               print "Yay - found it!"
 | 
						|
                ret.append( defn )
 | 
						|
                break
 | 
						|
#                       print "Nope!"
 | 
						|
        else: # For not broken!
 | 
						|
            sys.stderr.write("No definition of module %s in any specified map file.\n" % (mod))
 | 
						|
 | 
						|
    return ret
 | 
						|
 | 
						|
def get_extension_defn(moduleName, mapFileName, prefix):
 | 
						|
    if win32api is None: return None
 | 
						|
    os.environ['PYTHONPREFIX'] = prefix
 | 
						|
    dsp = win32api.GetProfileVal(moduleName, "dsp", "", mapFileName)
 | 
						|
    if dsp=="":
 | 
						|
        return None
 | 
						|
 | 
						|
    # We allow environment variables in the file name
 | 
						|
    dsp = win32api.ExpandEnvironmentStrings(dsp)
 | 
						|
    # If the path to the .DSP file is not absolute, assume it is relative
 | 
						|
    # to the description file.
 | 
						|
    if not os.path.isabs(dsp):
 | 
						|
        dsp = os.path.join( os.path.split(mapFileName)[0], dsp)
 | 
						|
    # Parse it to extract the source files.
 | 
						|
    sourceFiles = parse_dsp(dsp)
 | 
						|
    if sourceFiles is None:
 | 
						|
        return None
 | 
						|
 | 
						|
    module = CExtension(moduleName, sourceFiles)
 | 
						|
    # Put the path to the DSP into the environment so entries can reference it.
 | 
						|
    os.environ['dsp_path'] = os.path.split(dsp)[0]
 | 
						|
    os.environ['ini_path'] = os.path.split(mapFileName)[0]
 | 
						|
 | 
						|
    cl_options = win32api.GetProfileVal(moduleName, "cl", "", mapFileName)
 | 
						|
    if cl_options:
 | 
						|
        module.AddCompilerOption(win32api.ExpandEnvironmentStrings(cl_options))
 | 
						|
 | 
						|
    exclude = win32api.GetProfileVal(moduleName, "exclude", "", mapFileName)
 | 
						|
    exclude = exclude.split()
 | 
						|
 | 
						|
    if win32api.GetProfileVal(moduleName, "Unicode", 0, mapFileName):
 | 
						|
        module.AddCompilerOption('/D UNICODE /D _UNICODE')
 | 
						|
 | 
						|
    libs = win32api.GetProfileVal(moduleName, "libs", "", mapFileName).split()
 | 
						|
    for lib in libs:
 | 
						|
        module.AddLinkerLib(win32api.ExpandEnvironmentStrings(lib))
 | 
						|
 | 
						|
    for exc in exclude:
 | 
						|
        if exc in module.sourceFiles:
 | 
						|
            modules.sourceFiles.remove(exc)
 | 
						|
 | 
						|
    return module
 | 
						|
 | 
						|
# Given an MSVC DSP file, locate C source files it uses
 | 
						|
# returns a list of source files.
 | 
						|
def parse_dsp(dsp):
 | 
						|
#       print "Processing", dsp
 | 
						|
    # For now, only support
 | 
						|
    ret = []
 | 
						|
    dsp_path, dsp_name = os.path.split(dsp)
 | 
						|
    try:
 | 
						|
        lines = open(dsp, "r").readlines()
 | 
						|
    except IOError as msg:
 | 
						|
        sys.stderr.write("%s: %s\n" % (dsp, msg))
 | 
						|
        return None
 | 
						|
    for line in lines:
 | 
						|
        fields = line.strip().split("=", 2)
 | 
						|
        if fields[0]=="SOURCE":
 | 
						|
            if os.path.splitext(fields[1])[1].lower() in ['.cpp', '.c']:
 | 
						|
                ret.append( win32api.GetFullPathName(os.path.join(dsp_path, fields[1] ) ) )
 | 
						|
    return ret
 | 
						|
 | 
						|
def write_extension_table(fname, modules):
 | 
						|
    fp = open(fname, "w")
 | 
						|
    try:
 | 
						|
        fp.write (ext_src_header)
 | 
						|
        # Write fn protos
 | 
						|
        for module in modules:
 | 
						|
            # bit of a hack for .pyd's as part of packages.
 | 
						|
            name = module.name.split('.')[-1]
 | 
						|
            fp.write('extern void init%s(void);\n' % (name) )
 | 
						|
        # Write the table
 | 
						|
        fp.write (ext_tab_header)
 | 
						|
        for module in modules:
 | 
						|
            name = module.name.split('.')[-1]
 | 
						|
            fp.write('\t{"%s", init%s},\n' % (name, name) )
 | 
						|
 | 
						|
        fp.write (ext_tab_footer)
 | 
						|
        fp.write(ext_src_footer)
 | 
						|
    finally:
 | 
						|
        fp.close()
 | 
						|
 | 
						|
 | 
						|
ext_src_header = """\
 | 
						|
#include "Python.h"
 | 
						|
"""
 | 
						|
 | 
						|
ext_tab_header = """\
 | 
						|
 | 
						|
static struct _inittab extensions[] = {
 | 
						|
"""
 | 
						|
 | 
						|
ext_tab_footer = """\
 | 
						|
        /* Sentinel */
 | 
						|
        {0, 0}
 | 
						|
};
 | 
						|
"""
 | 
						|
 | 
						|
ext_src_footer = """\
 | 
						|
extern DL_IMPORT(int) PyImport_ExtendInittab(struct _inittab *newtab);
 | 
						|
 | 
						|
int PyInitFrozenExtensions()
 | 
						|
{
 | 
						|
        return PyImport_ExtendInittab(extensions);
 | 
						|
}
 | 
						|
 | 
						|
"""
 |