blob: 69643b3fa38b5788e688e9162e8ba3082c4af60b [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
12* Have a Windows INI file which "describes" an extension module.
13* This description can include:
14 - The MSVC .dsp file for the extension. The .c source file names
15 are extraced from there.
16 - Specific compiler options
17 - Flag to indicate if Unicode compilation is expected.
18
19At the moment the name and location of this INI file is hardcoded,
20but an obvious enhancement would be to provide command line options.
21"""
22
Guido van Rossum0f1e1fc1998-05-26 02:51:40 +000023import os, string, sys
24try:
25 import win32api
26except ImportError:
27 win32api = None # User has already been warned
Guido van Rossum110f3651998-05-19 20:18:37 +000028
29class CExtension:
30 """An abstraction of an extension implemented in C/C++
31 """
32 def __init__(self, name, sourceFiles):
33 self.name = name
34 # A list of strings defining additional compiler options.
35 self.sourceFiles = sourceFiles
36 # A list of special compiler options to be applied to
37 # all source modules in this extension.
38 self.compilerOptions = []
39 # A list of .lib files the final .EXE will need.
40 self.linkerLibs = []
41
42 def GetSourceFiles(self):
43 return self.sourceFiles
44
45 def AddCompilerOption(self, option):
46 self.compilerOptions.append(option)
47 def GetCompilerOptions(self):
48 return self.compilerOptions
49
50 def AddLinkerLib(self, lib):
51 self.linkerLibs.append(lib)
52 def GetLinkerLibs(self):
53 return self.linkerLibs
54
55def checkextensions(unknown, ignored):
56 # Create a table of frozen extensions
57
58 mapFileName = os.path.join( os.path.split(sys.argv[0])[0], "extensions_win32.ini")
59 ret = []
60 for mod in unknown:
61 defn = get_extension_defn( mod, mapFileName )
62 if defn is not None:
63 ret.append( defn )
64 return ret
65
66def get_extension_defn(moduleName, mapFileName):
Guido van Rossum0f1e1fc1998-05-26 02:51:40 +000067 if win32api is None: return None
Guido van Rossum110f3651998-05-19 20:18:37 +000068 dsp = win32api.GetProfileVal(moduleName, "dsp", "", mapFileName)
69 if dsp=="":
70 sys.stderr.write("No definition of module %s in map file '%s'\n" % (moduleName, mapFileName))
71 return None
72
73 # We allow environment variables in the file name
74 dsp = win32api.ExpandEnvironmentStrings(dsp)
75 sourceFiles = parse_dsp(dsp)
76 if sourceFiles is None:
77 return None
78
79 module = CExtension(moduleName, sourceFiles)
80
81 cl_options = win32api.GetProfileVal(moduleName, "cl", "", mapFileName)
82 if cl_options:
83 module.AddCompilerOption(win32api.ExpandEnvironmentStrings(cl_options))
84
85 exclude = win32api.GetProfileVal(moduleName, "exclude", "", mapFileName)
86 exclude = string.split(exclude)
87
88 if win32api.GetProfileVal(moduleName, "Unicode", 0, mapFileName):
89 module.AddCompilerOption('/D UNICODE /D _UNICODE')
90
91 libs = string.split(win32api.GetProfileVal(moduleName, "libs", "", mapFileName))
92 for lib in libs:
93 module.AddLinkerLib(lib)
94
95 for exc in exclude:
96 if exc in module.sourceFiles:
97 modules.sourceFiles.remove(exc)
98
99 return module
100
101# Given an MSVC DSP file, locate C source files it uses
102# returns a list of source files.
103def parse_dsp(dsp):
104# print "Processing", dsp
105 # For now, only support
106 ret = []
107 dsp_path, dsp_name = os.path.split(dsp)
108 try:
109 lines = open(dsp, "r").readlines()
110 except IOError, msg:
111 sys.stderr.write("%s: %s\n" % (dsp, msg))
112 return None
113 for line in lines:
114 fields = string.split(string.strip(line), "=", 2)
115 if fields[0]=="SOURCE":
116 if string.lower(os.path.splitext(fields[1])[1]) in ['.cpp', '.c']:
117 ret.append( win32api.GetFullPathName(os.path.join(dsp_path, fields[1] ) ) )
118 return ret
119
120def write_extension_table(fname, modules):
121 fp = open(fname, "w")
122 try:
123 fp.write (ext_src_header)
124 # Write fn protos
125 for module in modules:
126 # bit of a hack for .pyd's as part of packages.
127 name = string.split(module.name,'.')[-1]
128 fp.write('extern void init%s(void);\n' % (name) )
129 # Write the table
130 fp.write (ext_tab_header)
131 for module in modules:
132 name = string.split(module.name,'.')[-1]
133 fp.write('\t{"%s", init%s},\n' % (name, name) )
134
135 fp.write (ext_tab_footer)
136 fp.write(ext_src_footer)
137 finally:
138 fp.close()
139
140
141ext_src_header = """\
142#include "Python.h"
143"""
144
145ext_tab_header = """\
146
147static struct _inittab extensions[] = {
148"""
149
150ext_tab_footer = """\
151 /* Sentinel */
152 {0, 0}
153};
154"""
155
156ext_src_footer = """\
157extern int PyImport_ExtendInittab(struct _inittab *newtab);
158
159int PyInitFrozenExtensions()
160{
161 return PyImport_ExtendInittab(extensions);
162}
163
164"""
165
166