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