blob: e3efe05f190160526409bbe5b22910d3d876b3e3 [file] [log] [blame]
Guido van Rossum110f3651998-05-19 20:18:37 +00001"""Extension management for Windows.
2
3Under Windows it is unlikely the .obj files are of use, as special compiler options
4are needed (primarily to toggle the behaviour of "public" symbols.
5
6I dont consider it worth parsing the MSVC makefiles for compiler options. Even if
7we get it just right, a specific freeze application may have specific compiler
8options anyway (eg, to enable or disable specific functionality)
9
10So my basic stragtegy is:
11
Guido van Rossumbaf06031998-08-25 14:06:55 +000012* Have some Windows INI files which "describe" one or more extension modules.
13 (Freeze comes with a default one for all known modules - but you can specify
14 your own).
Guido van Rossum110f3651998-05-19 20:18:37 +000015* This description can include:
16 - The MSVC .dsp file for the extension. The .c source file names
17 are extraced from there.
Guido van Rossumbaf06031998-08-25 14:06:55 +000018 - Specific compiler/linker options
Guido van Rossum110f3651998-05-19 20:18:37 +000019 - Flag to indicate if Unicode compilation is expected.
20
21At the moment the name and location of this INI file is hardcoded,
22but an obvious enhancement would be to provide command line options.
23"""
24
Guido van Rossum0f1e1fc1998-05-26 02:51:40 +000025import os, string, sys
26try:
27 import win32api
28except ImportError:
29 win32api = None # User has already been warned
Guido van Rossum110f3651998-05-19 20:18:37 +000030
31class CExtension:
32 """An abstraction of an extension implemented in C/C++
33 """
34 def __init__(self, name, sourceFiles):
35 self.name = name
36 # A list of strings defining additional compiler options.
37 self.sourceFiles = sourceFiles
38 # A list of special compiler options to be applied to
39 # all source modules in this extension.
40 self.compilerOptions = []
41 # A list of .lib files the final .EXE will need.
42 self.linkerLibs = []
43
44 def GetSourceFiles(self):
45 return self.sourceFiles
46
47 def AddCompilerOption(self, option):
48 self.compilerOptions.append(option)
49 def GetCompilerOptions(self):
50 return self.compilerOptions
51
52 def AddLinkerLib(self, lib):
53 self.linkerLibs.append(lib)
54 def GetLinkerLibs(self):
55 return self.linkerLibs
56
Guido van Rossumbaf06031998-08-25 14:06:55 +000057def checkextensions(unknown, extra_inis):
Guido van Rossum110f3651998-05-19 20:18:37 +000058 # Create a table of frozen extensions
59
Guido van Rossumbaf06031998-08-25 14:06:55 +000060 defaultMapName = os.path.join( os.path.split(sys.argv[0])[0], "extensions_win32.ini")
61 if not os.path.isfile(defaultMapName):
62 sys.stderr.write("WARNING: %s can not be found - standard extensions may not be found" % mapFileName)
63 else:
64 # must go on end, so other inis can override.
65 extra_inis.append(defaultMapName)
66
Guido van Rossum110f3651998-05-19 20:18:37 +000067 ret = []
68 for mod in unknown:
Guido van Rossumbaf06031998-08-25 14:06:55 +000069 for ini in extra_inis:
70# print "Looking for", mod, "in", win32api.GetFullPathName(ini),"...",
71 defn = get_extension_defn( mod, ini )
72 if defn is not None:
73# print "Yay - found it!"
74 ret.append( defn )
75 break
76# print "Nope!"
77 else: # For not broken!
78 sys.stderr.write("No definition of module %s in any specified map file.\n" % (mod))
79
Guido van Rossum110f3651998-05-19 20:18:37 +000080 return ret
81
82def get_extension_defn(moduleName, mapFileName):
Guido van Rossum0f1e1fc1998-05-26 02:51:40 +000083 if win32api is None: return None
Guido van Rossum110f3651998-05-19 20:18:37 +000084 dsp = win32api.GetProfileVal(moduleName, "dsp", "", mapFileName)
85 if dsp=="":
Guido van Rossum110f3651998-05-19 20:18:37 +000086 return None
87
88 # We allow environment variables in the file name
89 dsp = win32api.ExpandEnvironmentStrings(dsp)
Guido van Rossumbaf06031998-08-25 14:06:55 +000090 # If the path to the .DSP file is not absolute, assume it is relative
91 # to the description file.
92 if not os.path.isabs(dsp):
93 dsp = os.path.join( os.path.split(mapFileName)[0], dsp)
94 # Parse it to extract the source files.
Guido van Rossum110f3651998-05-19 20:18:37 +000095 sourceFiles = parse_dsp(dsp)
96 if sourceFiles is None:
97 return None
98
99 module = CExtension(moduleName, sourceFiles)
Guido van Rossumbaf06031998-08-25 14:06:55 +0000100 # Put the path to the DSP into the environment so entries can reference it.
101 os.environ['dsp_path'] = os.path.split(dsp)[0]
102 os.environ['ini_path'] = os.path.split(mapFileName)[0]
Guido van Rossum110f3651998-05-19 20:18:37 +0000103
104 cl_options = win32api.GetProfileVal(moduleName, "cl", "", mapFileName)
105 if cl_options:
106 module.AddCompilerOption(win32api.ExpandEnvironmentStrings(cl_options))
107
108 exclude = win32api.GetProfileVal(moduleName, "exclude", "", mapFileName)
109 exclude = string.split(exclude)
110
111 if win32api.GetProfileVal(moduleName, "Unicode", 0, mapFileName):
112 module.AddCompilerOption('/D UNICODE /D _UNICODE')
113
114 libs = string.split(win32api.GetProfileVal(moduleName, "libs", "", mapFileName))
115 for lib in libs:
Guido van Rossumbaf06031998-08-25 14:06:55 +0000116 module.AddLinkerLib(win32api.ExpandEnvironmentStrings(lib))
Guido van Rossum110f3651998-05-19 20:18:37 +0000117
118 for exc in exclude:
119 if exc in module.sourceFiles:
120 modules.sourceFiles.remove(exc)
121
122 return module
123
124# Given an MSVC DSP file, locate C source files it uses
125# returns a list of source files.
126def parse_dsp(dsp):
127# print "Processing", dsp
128 # For now, only support
129 ret = []
130 dsp_path, dsp_name = os.path.split(dsp)
131 try:
132 lines = open(dsp, "r").readlines()
133 except IOError, msg:
134 sys.stderr.write("%s: %s\n" % (dsp, msg))
135 return None
136 for line in lines:
137 fields = string.split(string.strip(line), "=", 2)
138 if fields[0]=="SOURCE":
139 if string.lower(os.path.splitext(fields[1])[1]) in ['.cpp', '.c']:
140 ret.append( win32api.GetFullPathName(os.path.join(dsp_path, fields[1] ) ) )
141 return ret
142
143def write_extension_table(fname, modules):
144 fp = open(fname, "w")
145 try:
146 fp.write (ext_src_header)
147 # Write fn protos
148 for module in modules:
149 # bit of a hack for .pyd's as part of packages.
150 name = string.split(module.name,'.')[-1]
151 fp.write('extern void init%s(void);\n' % (name) )
152 # Write the table
153 fp.write (ext_tab_header)
154 for module in modules:
155 name = string.split(module.name,'.')[-1]
156 fp.write('\t{"%s", init%s},\n' % (name, name) )
157
158 fp.write (ext_tab_footer)
159 fp.write(ext_src_footer)
160 finally:
161 fp.close()
162
163
164ext_src_header = """\
165#include "Python.h"
166"""
167
168ext_tab_header = """\
169
170static struct _inittab extensions[] = {
171"""
172
173ext_tab_footer = """\
174 /* Sentinel */
175 {0, 0}
176};
177"""
178
179ext_src_footer = """\
Guido van Rossumcfd76a21999-11-02 15:44:40 +0000180extern DL_IMPORT(int) PyImport_ExtendInittab(struct _inittab *newtab);
Guido van Rossum110f3651998-05-19 20:18:37 +0000181
182int PyInitFrozenExtensions()
183{
184 return PyImport_ExtendInittab(extensions);
185}
186
187"""
188
189