]>
Commit | Line | Data |
---|---|---|
1e4a197e RD |
1 | """Provide access to Python's configuration information. The specific |
2 | configuration variables available depend heavily on the platform and | |
3 | configuration. The values may be retrieved using | |
4 | get_config_var(name), and the list of variables is available via | |
5 | get_config_vars().keys(). Additional convenience functions are also | |
6 | available. | |
7 | ||
8 | Written by: Fred L. Drake, Jr. | |
9 | Email: <fdrake@acm.org> | |
10 | """ | |
11 | ||
12 | __revision__ = "$Id$" | |
13 | ||
14 | import os | |
15 | import re | |
16 | import string | |
17 | import sys | |
18 | ||
19 | from errors import DistutilsPlatformError | |
20 | ||
21 | # These are needed in a couple of spots, so just compute them once. | |
22 | PREFIX = os.path.normpath(sys.prefix) | |
23 | EXEC_PREFIX = os.path.normpath(sys.exec_prefix) | |
24 | ||
25 | # python_build: (Boolean) if true, we're either building Python or | |
26 | # building an extension with an un-installed Python, so we use | |
27 | # different (hard-wired) directories. | |
28 | ||
29 | argv0_path = os.path.dirname(os.path.abspath(sys.executable)) | |
30 | landmark = os.path.join(argv0_path, "Modules", "Setup") | |
31 | ||
32 | python_build = os.path.isfile(landmark) | |
33 | ||
34 | del argv0_path, landmark | |
35 | ||
36 | ||
37 | def get_python_version (): | |
38 | """Return a string containing the major and minor Python version, | |
39 | leaving off the patchlevel. Sample return values could be '1.5' | |
40 | or '2.2'. | |
41 | """ | |
42 | return sys.version[:3] | |
43 | ||
44 | ||
45 | def get_python_inc(plat_specific=0, prefix=None): | |
46 | """Return the directory containing installed Python header files. | |
47 | ||
48 | If 'plat_specific' is false (the default), this is the path to the | |
49 | non-platform-specific header files, i.e. Python.h and so on; | |
50 | otherwise, this is the path to platform-specific header files | |
51 | (namely pyconfig.h). | |
52 | ||
53 | If 'prefix' is supplied, use it instead of sys.prefix or | |
54 | sys.exec_prefix -- i.e., ignore 'plat_specific'. | |
55 | """ | |
56 | if prefix is None: | |
57 | prefix = plat_specific and EXEC_PREFIX or PREFIX | |
58 | if os.name == "posix": | |
59 | if python_build: | |
60 | base = os.path.dirname(os.path.abspath(sys.executable)) | |
61 | if plat_specific: | |
62 | inc_dir = base | |
63 | else: | |
64 | inc_dir = os.path.join(base, "Include") | |
65 | if not os.path.exists(inc_dir): | |
66 | inc_dir = os.path.join(os.path.dirname(base), "Include") | |
67 | return inc_dir | |
68 | return os.path.join(prefix, "include", "python" + sys.version[:3]) | |
69 | elif os.name == "nt": | |
70 | return os.path.join(prefix, "include") | |
71 | elif os.name == "mac": | |
72 | if plat_specific: | |
73 | return os.path.join(prefix, "Mac", "Include") | |
74 | else: | |
75 | return os.path.join(prefix, "Include") | |
76 | elif os.name == "os2": | |
77 | return os.path.join(prefix, "Include") | |
78 | else: | |
79 | raise DistutilsPlatformError( | |
80 | "I don't know where Python installs its C header files " | |
81 | "on platform '%s'" % os.name) | |
82 | ||
83 | ||
84 | def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): | |
85 | """Return the directory containing the Python library (standard or | |
86 | site additions). | |
87 | ||
88 | If 'plat_specific' is true, return the directory containing | |
89 | platform-specific modules, i.e. any module from a non-pure-Python | |
90 | module distribution; otherwise, return the platform-shared library | |
91 | directory. If 'standard_lib' is true, return the directory | |
92 | containing standard Python library modules; otherwise, return the | |
93 | directory for site-specific modules. | |
94 | ||
95 | If 'prefix' is supplied, use it instead of sys.prefix or | |
96 | sys.exec_prefix -- i.e., ignore 'plat_specific'. | |
97 | """ | |
98 | if prefix is None: | |
99 | prefix = plat_specific and EXEC_PREFIX or PREFIX | |
100 | ||
101 | if os.name == "posix": | |
102 | libpython = os.path.join(prefix, | |
103 | "lib", "python" + get_python_version()) | |
104 | if standard_lib: | |
105 | return libpython | |
106 | else: | |
107 | return os.path.join(libpython, "site-packages") | |
108 | ||
109 | elif os.name == "nt": | |
110 | if standard_lib: | |
111 | return os.path.join(prefix, "Lib") | |
112 | else: | |
113 | if sys.version < "2.2": | |
114 | return prefix | |
115 | else: | |
116 | return os.path.join(PREFIX, "Lib", "site-packages") | |
117 | ||
118 | elif os.name == "mac": | |
119 | if plat_specific: | |
120 | if standard_lib: | |
121 | return os.path.join(prefix, "Lib", "lib-dynload") | |
122 | else: | |
123 | return os.path.join(prefix, "Lib", "site-packages") | |
124 | else: | |
125 | if standard_lib: | |
126 | return os.path.join(prefix, "Lib") | |
127 | else: | |
128 | return os.path.join(prefix, "Lib", "site-packages") | |
129 | ||
130 | elif os.name == "os2": | |
131 | if standard_lib: | |
132 | return os.path.join(PREFIX, "Lib") | |
133 | else: | |
134 | return os.path.join(PREFIX, "Lib", "site-packages") | |
135 | ||
136 | else: | |
137 | raise DistutilsPlatformError( | |
138 | "I don't know where Python installs its library " | |
139 | "on platform '%s'" % os.name) | |
140 | ||
141 | ||
142 | def customize_compiler(compiler): | |
143 | """Do any platform-specific customization of a CCompiler instance. | |
144 | ||
145 | Mainly needed on Unix, so we can plug in the information that | |
146 | varies across Unices and is stored in Python's Makefile. | |
147 | """ | |
148 | if compiler.compiler_type == "unix": | |
149 | (cc, cxx, opt, basecflags, ccshared, ldshared, so_ext) = \ | |
150 | get_config_vars('CC', 'CXX', 'OPT', 'BASECFLAGS', 'CCSHARED', 'LDSHARED', 'SO') | |
151 | ||
152 | if os.environ.has_key('CC'): | |
153 | cc = os.environ['CC'] | |
154 | if os.environ.has_key('CXX'): | |
155 | cxx = os.environ['CXX'] | |
156 | if os.environ.has_key('CPP'): | |
157 | cpp = os.environ['CPP'] | |
158 | else: | |
159 | cpp = cc + " -E" # not always | |
160 | if os.environ.has_key('LDFLAGS'): | |
161 | ldshared = ldshared + ' ' + os.environ['LDFLAGS'] | |
162 | if basecflags: | |
163 | opt = basecflags + ' ' + opt | |
164 | if os.environ.has_key('CFLAGS'): | |
165 | opt = opt + ' ' + os.environ['CFLAGS'] | |
166 | ldshared = ldshared + ' ' + os.environ['CFLAGS'] | |
167 | if os.environ.has_key('CPPFLAGS'): | |
168 | cpp = cpp + ' ' + os.environ['CPPFLAGS'] | |
169 | opt = opt + ' ' + os.environ['CPPFLAGS'] | |
170 | ldshared = ldshared + ' ' + os.environ['CPPFLAGS'] | |
171 | ||
172 | cc_cmd = cc + ' ' + opt | |
173 | compiler.set_executables( | |
174 | preprocessor=cpp, | |
175 | compiler=cc_cmd, | |
176 | compiler_so=cc_cmd + ' ' + ccshared, | |
177 | compiler_cxx=cxx, | |
178 | linker_so=ldshared, | |
179 | linker_exe=cc) | |
180 | ||
181 | compiler.shared_lib_extension = so_ext | |
182 | ||
183 | ||
184 | def get_config_h_filename(): | |
185 | """Return full pathname of installed pyconfig.h file.""" | |
186 | if python_build: | |
187 | inc_dir = os.curdir | |
188 | else: | |
189 | inc_dir = get_python_inc(plat_specific=1) | |
190 | if sys.version < '2.2': | |
191 | config_h = 'config.h' | |
192 | else: | |
193 | # The name of the config.h file changed in 2.2 | |
194 | config_h = 'pyconfig.h' | |
195 | return os.path.join(inc_dir, config_h) | |
196 | ||
197 | ||
198 | def get_makefile_filename(): | |
199 | """Return full pathname of installed Makefile from the Python build.""" | |
200 | if python_build: | |
201 | return os.path.join(os.path.dirname(sys.executable), "Makefile") | |
202 | lib_dir = get_python_lib(plat_specific=1, standard_lib=1) | |
203 | return os.path.join(lib_dir, "config", "Makefile") | |
204 | ||
205 | ||
206 | def parse_config_h(fp, g=None): | |
207 | """Parse a config.h-style file. | |
208 | ||
209 | A dictionary containing name/value pairs is returned. If an | |
210 | optional dictionary is passed in as the second argument, it is | |
211 | used instead of a new dictionary. | |
212 | """ | |
213 | if g is None: | |
214 | g = {} | |
215 | define_rx = re.compile("#define ([A-Z][A-Z0-9_]+) (.*)\n") | |
216 | undef_rx = re.compile("/[*] #undef ([A-Z][A-Z0-9_]+) [*]/\n") | |
217 | # | |
218 | while 1: | |
219 | line = fp.readline() | |
220 | if not line: | |
221 | break | |
222 | m = define_rx.match(line) | |
223 | if m: | |
224 | n, v = m.group(1, 2) | |
225 | try: v = int(v) | |
226 | except ValueError: pass | |
227 | g[n] = v | |
228 | else: | |
229 | m = undef_rx.match(line) | |
230 | if m: | |
231 | g[m.group(1)] = 0 | |
232 | return g | |
233 | ||
234 | ||
235 | # Regexes needed for parsing Makefile (and similar syntaxes, | |
236 | # like old-style Setup files). | |
237 | _variable_rx = re.compile("([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") | |
238 | _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") | |
239 | _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") | |
240 | ||
241 | def parse_makefile(fn, g=None): | |
242 | """Parse a Makefile-style file. | |
243 | ||
244 | A dictionary containing name/value pairs is returned. If an | |
245 | optional dictionary is passed in as the second argument, it is | |
246 | used instead of a new dictionary. | |
247 | """ | |
248 | from distutils.text_file import TextFile | |
249 | fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1) | |
250 | ||
251 | if g is None: | |
252 | g = {} | |
253 | done = {} | |
254 | notdone = {} | |
255 | ||
256 | while 1: | |
257 | line = fp.readline() | |
258 | if line is None: # eof | |
259 | break | |
260 | m = _variable_rx.match(line) | |
261 | if m: | |
262 | n, v = m.group(1, 2) | |
263 | v = string.strip(v) | |
264 | if "$" in v: | |
265 | notdone[n] = v | |
266 | else: | |
267 | try: v = int(v) | |
268 | except ValueError: pass | |
269 | done[n] = v | |
270 | ||
271 | # do variable interpolation here | |
272 | while notdone: | |
273 | for name in notdone.keys(): | |
274 | value = notdone[name] | |
275 | m = _findvar1_rx.search(value) or _findvar2_rx.search(value) | |
276 | if m: | |
277 | n = m.group(1) | |
278 | if done.has_key(n): | |
279 | after = value[m.end():] | |
280 | value = value[:m.start()] + str(done[n]) + after | |
281 | if "$" in after: | |
282 | notdone[name] = value | |
283 | else: | |
284 | try: value = int(value) | |
285 | except ValueError: | |
286 | done[name] = string.strip(value) | |
287 | else: | |
288 | done[name] = value | |
289 | del notdone[name] | |
290 | elif notdone.has_key(n): | |
291 | # get it on a subsequent round | |
292 | pass | |
293 | else: | |
294 | done[n] = "" | |
295 | after = value[m.end():] | |
296 | value = value[:m.start()] + after | |
297 | if "$" in after: | |
298 | notdone[name] = value | |
299 | else: | |
300 | try: value = int(value) | |
301 | except ValueError: | |
302 | done[name] = string.strip(value) | |
303 | else: | |
304 | done[name] = value | |
305 | del notdone[name] | |
306 | else: | |
307 | # bogus variable reference; just drop it since we can't deal | |
308 | del notdone[name] | |
309 | ||
310 | fp.close() | |
311 | ||
312 | # save the results in the global dictionary | |
313 | g.update(done) | |
314 | return g | |
315 | ||
316 | ||
317 | def expand_makefile_vars(s, vars): | |
318 | """Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in | |
319 | 'string' according to 'vars' (a dictionary mapping variable names to | |
320 | values). Variables not present in 'vars' are silently expanded to the | |
321 | empty string. The variable values in 'vars' should not contain further | |
322 | variable expansions; if 'vars' is the output of 'parse_makefile()', | |
323 | you're fine. Returns a variable-expanded version of 's'. | |
324 | """ | |
325 | ||
326 | # This algorithm does multiple expansion, so if vars['foo'] contains | |
327 | # "${bar}", it will expand ${foo} to ${bar}, and then expand | |
328 | # ${bar}... and so forth. This is fine as long as 'vars' comes from | |
329 | # 'parse_makefile()', which takes care of such expansions eagerly, | |
330 | # according to make's variable expansion semantics. | |
331 | ||
332 | while 1: | |
333 | m = _findvar1_rx.search(s) or _findvar2_rx.search(s) | |
334 | if m: | |
335 | (beg, end) = m.span() | |
336 | s = s[0:beg] + vars.get(m.group(1)) + s[end:] | |
337 | else: | |
338 | break | |
339 | return s | |
340 | ||
341 | ||
342 | _config_vars = None | |
343 | ||
344 | def _init_posix(): | |
345 | """Initialize the module as appropriate for POSIX systems.""" | |
346 | g = {} | |
347 | # load the installed Makefile: | |
348 | try: | |
349 | filename = get_makefile_filename() | |
350 | parse_makefile(filename, g) | |
351 | except IOError, msg: | |
352 | my_msg = "invalid Python installation: unable to open %s" % filename | |
353 | if hasattr(msg, "strerror"): | |
354 | my_msg = my_msg + " (%s)" % msg.strerror | |
355 | ||
356 | raise DistutilsPlatformError(my_msg) | |
357 | ||
358 | ||
359 | # On AIX, there are wrong paths to the linker scripts in the Makefile | |
360 | # -- these paths are relative to the Python source, but when installed | |
361 | # the scripts are in another directory. | |
362 | if python_build: | |
363 | g['LDSHARED'] = g['BLDSHARED'] | |
364 | ||
365 | elif sys.version < '2.1': | |
366 | # The following two branches are for 1.5.2 compatibility. | |
367 | if sys.platform == 'aix4': # what about AIX 3.x ? | |
368 | # Linker script is in the config directory, not in Modules as the | |
369 | # Makefile says. | |
370 | python_lib = get_python_lib(standard_lib=1) | |
371 | ld_so_aix = os.path.join(python_lib, 'config', 'ld_so_aix') | |
372 | python_exp = os.path.join(python_lib, 'config', 'python.exp') | |
373 | ||
374 | g['LDSHARED'] = "%s %s -bI:%s" % (ld_so_aix, g['CC'], python_exp) | |
375 | ||
376 | elif sys.platform == 'beos': | |
377 | # Linker script is in the config directory. In the Makefile it is | |
378 | # relative to the srcdir, which after installation no longer makes | |
379 | # sense. | |
380 | python_lib = get_python_lib(standard_lib=1) | |
381 | linkerscript_path = string.split(g['LDSHARED'])[0] | |
382 | linkerscript_name = os.path.basename(linkerscript_path) | |
383 | linkerscript = os.path.join(python_lib, 'config', | |
384 | linkerscript_name) | |
385 | ||
386 | # XXX this isn't the right place to do this: adding the Python | |
387 | # library to the link, if needed, should be in the "build_ext" | |
388 | # command. (It's also needed for non-MS compilers on Windows, and | |
389 | # it's taken care of for them by the 'build_ext.get_libraries()' | |
390 | # method.) | |
391 | g['LDSHARED'] = ("%s -L%s/lib -lpython%s" % | |
392 | (linkerscript, PREFIX, sys.version[0:3])) | |
393 | ||
394 | global _config_vars | |
395 | _config_vars = g | |
396 | ||
397 | ||
398 | def _init_nt(): | |
399 | """Initialize the module as appropriate for NT""" | |
400 | g = {} | |
401 | # set basic install directories | |
402 | g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1) | |
403 | g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1) | |
404 | ||
405 | # XXX hmmm.. a normal install puts include files here | |
406 | g['INCLUDEPY'] = get_python_inc(plat_specific=0) | |
407 | ||
408 | g['SO'] = '.pyd' | |
409 | g['EXE'] = ".exe" | |
410 | ||
411 | global _config_vars | |
412 | _config_vars = g | |
413 | ||
414 | ||
415 | def _init_mac(): | |
416 | """Initialize the module as appropriate for Macintosh systems""" | |
417 | g = {} | |
418 | # set basic install directories | |
419 | g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1) | |
420 | g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1) | |
421 | ||
422 | # XXX hmmm.. a normal install puts include files here | |
423 | g['INCLUDEPY'] = get_python_inc(plat_specific=0) | |
424 | ||
425 | import MacOS | |
426 | if not hasattr(MacOS, 'runtimemodel'): | |
427 | g['SO'] = '.ppc.slb' | |
428 | else: | |
429 | g['SO'] = '.%s.slb' % MacOS.runtimemodel | |
430 | ||
431 | # XXX are these used anywhere? | |
432 | g['install_lib'] = os.path.join(EXEC_PREFIX, "Lib") | |
433 | g['install_platlib'] = os.path.join(EXEC_PREFIX, "Mac", "Lib") | |
434 | ||
435 | # These are used by the extension module build | |
436 | g['srcdir'] = ':' | |
437 | global _config_vars | |
438 | _config_vars = g | |
439 | ||
440 | ||
441 | def _init_os2(): | |
442 | """Initialize the module as appropriate for OS/2""" | |
443 | g = {} | |
444 | # set basic install directories | |
445 | g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1) | |
446 | g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1) | |
447 | ||
448 | # XXX hmmm.. a normal install puts include files here | |
449 | g['INCLUDEPY'] = get_python_inc(plat_specific=0) | |
450 | ||
451 | g['SO'] = '.pyd' | |
452 | g['EXE'] = ".exe" | |
453 | ||
454 | global _config_vars | |
455 | _config_vars = g | |
456 | ||
457 | ||
458 | def get_config_vars(*args): | |
459 | """With no arguments, return a dictionary of all configuration | |
460 | variables relevant for the current platform. Generally this includes | |
461 | everything needed to build extensions and install both pure modules and | |
462 | extensions. On Unix, this means every variable defined in Python's | |
463 | installed Makefile; on Windows and Mac OS it's a much smaller set. | |
464 | ||
465 | With arguments, return a list of values that result from looking up | |
466 | each argument in the configuration variable dictionary. | |
467 | """ | |
468 | global _config_vars | |
469 | if _config_vars is None: | |
470 | func = globals().get("_init_" + os.name) | |
471 | if func: | |
472 | func() | |
473 | else: | |
474 | _config_vars = {} | |
475 | ||
476 | # Normalized versions of prefix and exec_prefix are handy to have; | |
477 | # in fact, these are the standard versions used most places in the | |
478 | # Distutils. | |
479 | _config_vars['prefix'] = PREFIX | |
480 | _config_vars['exec_prefix'] = EXEC_PREFIX | |
481 | ||
482 | if args: | |
483 | vals = [] | |
484 | for name in args: | |
485 | vals.append(_config_vars.get(name)) | |
486 | return vals | |
487 | else: | |
488 | return _config_vars | |
489 | ||
490 | def get_config_var(name): | |
491 | """Return the value of a single variable using the dictionary | |
492 | returned by 'get_config_vars()'. Equivalent to | |
493 | get_config_vars().get(name) | |
494 | """ | |
495 | return get_config_vars().get(name) |