ยปCore Development>Code coverage>Tools/freeze/checkextensions_win32.py

Python code coverage for Tools/freeze/checkextensions_win32.py

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