| 
									
										
										
										
											1998-05-19 20:18:37 +00:00
										 |  |  | """Extension management for Windows.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Under Windows it is unlikely the .obj files are of use, as special compiler options | 
					
						
							| 
									
										
										
										
											2000-07-16 12:04:32 +00:00
										 |  |  | are needed (primarily to toggle the behavior of "public" symbols. | 
					
						
							| 
									
										
										
										
											1998-05-19 20:18:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-26 01:32:56 +03:00
										 |  |  | I don't consider it worth parsing the MSVC makefiles for compiler options.  Even if | 
					
						
							| 
									
										
										
										
											1998-05-19 20:18:37 +00:00
										 |  |  | we get it just right, a specific freeze application may have specific compiler | 
					
						
							|  |  |  | options anyway (eg, to enable or disable specific functionality) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-16 11:05:33 +02:00
										 |  |  | So my basic strategy is: | 
					
						
							| 
									
										
										
										
											1998-05-19 20:18:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-08-25 14:06:55 +00:00
										 |  |  | * 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). | 
					
						
							| 
									
										
										
										
											1998-05-19 20:18:37 +00:00
										 |  |  | * This description can include: | 
					
						
							|  |  |  |   - The MSVC .dsp file for the extension.  The .c source file names | 
					
						
							| 
									
										
										
										
											2013-08-26 01:32:56 +03:00
										 |  |  |     are extracted from there. | 
					
						
							| 
									
										
										
										
											1998-08-25 14:06:55 +00:00
										 |  |  |   - Specific compiler/linker options | 
					
						
							| 
									
										
										
										
											1998-05-19 20:18:37 +00:00
										 |  |  |   - 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. | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-09-11 20:36:02 +00:00
										 |  |  | import os, sys | 
					
						
							| 
									
										
										
										
											1998-05-26 02:51:40 +00:00
										 |  |  | try: | 
					
						
							| 
									
										
										
										
											2004-07-18 06:16:08 +00:00
										 |  |  |     import win32api | 
					
						
							| 
									
										
										
										
											1998-05-26 02:51:40 +00:00
										 |  |  | except ImportError: | 
					
						
							| 
									
										
										
										
											2004-07-18 06:16:08 +00:00
										 |  |  |     win32api = None # User has already been warned | 
					
						
							| 
									
										
										
										
											1998-05-19 20:18:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class CExtension: | 
					
						
							| 
									
										
										
										
											2004-07-18 06:16:08 +00:00
										 |  |  |     """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 | 
					
						
							| 
									
										
										
										
											1998-05-19 20:18:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-13 15:45:17 +00:00
										 |  |  | def checkextensions(unknown, extra_inis, prefix): | 
					
						
							| 
									
										
										
										
											2004-07-18 06:16:08 +00:00
										 |  |  |     # 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 | 
					
						
							| 
									
										
										
										
											1998-05-19 20:18:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-13 15:45:17 +00:00
										 |  |  | def get_extension_defn(moduleName, mapFileName, prefix): | 
					
						
							| 
									
										
										
										
											2004-07-18 06:16:08 +00:00
										 |  |  |     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: | 
					
						
							| 
									
										
										
										
											2015-10-29 21:10:57 -07:00
										 |  |  |             module.sourceFiles.remove(exc) | 
					
						
							| 
									
										
										
										
											2004-07-18 06:16:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return module | 
					
						
							| 
									
										
										
										
											1998-05-19 20:18:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Given an MSVC DSP file, locate C source files it uses | 
					
						
							|  |  |  | # returns a list of source files. | 
					
						
							|  |  |  | def parse_dsp(dsp): | 
					
						
							| 
									
										
										
										
											2004-07-18 06:16:08 +00:00
										 |  |  | #       print "Processing", dsp | 
					
						
							|  |  |  |     # For now, only support | 
					
						
							|  |  |  |     ret = [] | 
					
						
							|  |  |  |     dsp_path, dsp_name = os.path.split(dsp) | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         lines = open(dsp, "r").readlines() | 
					
						
							| 
									
										
										
										
											2007-01-10 16:19:56 +00:00
										 |  |  |     except IOError as msg: | 
					
						
							| 
									
										
										
										
											2004-07-18 06:16:08 +00:00
										 |  |  |         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 | 
					
						
							| 
									
										
										
										
											1998-05-19 20:18:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def write_extension_table(fname, modules): | 
					
						
							| 
									
										
										
										
											2004-07-18 06:16:08 +00:00
										 |  |  |     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() | 
					
						
							| 
									
										
										
										
											1998-05-19 20:18:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ext_src_header = """\
 | 
					
						
							|  |  |  | #include "Python.h" | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ext_tab_header = """\
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct _inittab extensions[] = { | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ext_tab_footer = """\
 | 
					
						
							|  |  |  |         /* Sentinel */ | 
					
						
							|  |  |  |         {0, 0} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ext_src_footer = """\
 | 
					
						
							| 
									
										
										
										
											1999-11-02 15:44:40 +00:00
										 |  |  | extern DL_IMPORT(int) PyImport_ExtendInittab(struct _inittab *newtab); | 
					
						
							| 
									
										
										
										
											1998-05-19 20:18:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | int PyInitFrozenExtensions() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2004-07-18 06:16:08 +00:00
										 |  |  |         return PyImport_ExtendInittab(extensions); | 
					
						
							| 
									
										
										
										
											1998-05-19 20:18:37 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """
 |