Commit | Line | Data |
---|---|---|
920dae64 AT |
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: sysconfig.py,v 1.61.2.1 2005/01/06 23:16:03 jackjansen Exp $" | |
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('LDSHARED'): | |
157 | ldshared = os.environ['LDSHARED'] | |
158 | if os.environ.has_key('CPP'): | |
159 | cpp = os.environ['CPP'] | |
160 | else: | |
161 | cpp = cc + " -E" # not always | |
162 | if os.environ.has_key('LDFLAGS'): | |
163 | ldshared = ldshared + ' ' + os.environ['LDFLAGS'] | |
164 | if basecflags: | |
165 | opt = basecflags + ' ' + opt | |
166 | if os.environ.has_key('CFLAGS'): | |
167 | opt = opt + ' ' + os.environ['CFLAGS'] | |
168 | ldshared = ldshared + ' ' + os.environ['CFLAGS'] | |
169 | if os.environ.has_key('CPPFLAGS'): | |
170 | cpp = cpp + ' ' + os.environ['CPPFLAGS'] | |
171 | opt = opt + ' ' + os.environ['CPPFLAGS'] | |
172 | ldshared = ldshared + ' ' + os.environ['CPPFLAGS'] | |
173 | ||
174 | cc_cmd = cc + ' ' + opt | |
175 | compiler.set_executables( | |
176 | preprocessor=cpp, | |
177 | compiler=cc_cmd, | |
178 | compiler_so=cc_cmd + ' ' + ccshared, | |
179 | compiler_cxx=cxx, | |
180 | linker_so=ldshared, | |
181 | linker_exe=cc) | |
182 | ||
183 | compiler.shared_lib_extension = so_ext | |
184 | ||
185 | ||
186 | def get_config_h_filename(): | |
187 | """Return full pathname of installed pyconfig.h file.""" | |
188 | if python_build: | |
189 | inc_dir = os.curdir | |
190 | else: | |
191 | inc_dir = get_python_inc(plat_specific=1) | |
192 | if sys.version < '2.2': | |
193 | config_h = 'config.h' | |
194 | else: | |
195 | # The name of the config.h file changed in 2.2 | |
196 | config_h = 'pyconfig.h' | |
197 | return os.path.join(inc_dir, config_h) | |
198 | ||
199 | ||
200 | def get_makefile_filename(): | |
201 | """Return full pathname of installed Makefile from the Python build.""" | |
202 | if python_build: | |
203 | return os.path.join(os.path.dirname(sys.executable), "Makefile") | |
204 | lib_dir = get_python_lib(plat_specific=1, standard_lib=1) | |
205 | return os.path.join(lib_dir, "config", "Makefile") | |
206 | ||
207 | ||
208 | def parse_config_h(fp, g=None): | |
209 | """Parse a config.h-style file. | |
210 | ||
211 | A dictionary containing name/value pairs is returned. If an | |
212 | optional dictionary is passed in as the second argument, it is | |
213 | used instead of a new dictionary. | |
214 | """ | |
215 | if g is None: | |
216 | g = {} | |
217 | define_rx = re.compile("#define ([A-Z][A-Z0-9_]+) (.*)\n") | |
218 | undef_rx = re.compile("/[*] #undef ([A-Z][A-Z0-9_]+) [*]/\n") | |
219 | # | |
220 | while 1: | |
221 | line = fp.readline() | |
222 | if not line: | |
223 | break | |
224 | m = define_rx.match(line) | |
225 | if m: | |
226 | n, v = m.group(1, 2) | |
227 | try: v = int(v) | |
228 | except ValueError: pass | |
229 | g[n] = v | |
230 | else: | |
231 | m = undef_rx.match(line) | |
232 | if m: | |
233 | g[m.group(1)] = 0 | |
234 | return g | |
235 | ||
236 | ||
237 | # Regexes needed for parsing Makefile (and similar syntaxes, | |
238 | # like old-style Setup files). | |
239 | _variable_rx = re.compile("([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") | |
240 | _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") | |
241 | _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") | |
242 | ||
243 | def parse_makefile(fn, g=None): | |
244 | """Parse a Makefile-style file. | |
245 | ||
246 | A dictionary containing name/value pairs is returned. If an | |
247 | optional dictionary is passed in as the second argument, it is | |
248 | used instead of a new dictionary. | |
249 | """ | |
250 | from distutils.text_file import TextFile | |
251 | fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1) | |
252 | ||
253 | if g is None: | |
254 | g = {} | |
255 | done = {} | |
256 | notdone = {} | |
257 | ||
258 | while 1: | |
259 | line = fp.readline() | |
260 | if line is None: # eof | |
261 | break | |
262 | m = _variable_rx.match(line) | |
263 | if m: | |
264 | n, v = m.group(1, 2) | |
265 | v = string.strip(v) | |
266 | if "$" in v: | |
267 | notdone[n] = v | |
268 | else: | |
269 | try: v = int(v) | |
270 | except ValueError: pass | |
271 | done[n] = v | |
272 | ||
273 | # do variable interpolation here | |
274 | while notdone: | |
275 | for name in notdone.keys(): | |
276 | value = notdone[name] | |
277 | m = _findvar1_rx.search(value) or _findvar2_rx.search(value) | |
278 | if m: | |
279 | n = m.group(1) | |
280 | if done.has_key(n): | |
281 | after = value[m.end():] | |
282 | value = value[:m.start()] + str(done[n]) + after | |
283 | if "$" in after: | |
284 | notdone[name] = value | |
285 | else: | |
286 | try: value = int(value) | |
287 | except ValueError: | |
288 | done[name] = string.strip(value) | |
289 | else: | |
290 | done[name] = value | |
291 | del notdone[name] | |
292 | elif notdone.has_key(n): | |
293 | # get it on a subsequent round | |
294 | pass | |
295 | else: | |
296 | done[n] = "" | |
297 | after = value[m.end():] | |
298 | value = value[:m.start()] + after | |
299 | if "$" in after: | |
300 | notdone[name] = value | |
301 | else: | |
302 | try: value = int(value) | |
303 | except ValueError: | |
304 | done[name] = string.strip(value) | |
305 | else: | |
306 | done[name] = value | |
307 | del notdone[name] | |
308 | else: | |
309 | # bogus variable reference; just drop it since we can't deal | |
310 | del notdone[name] | |
311 | ||
312 | fp.close() | |
313 | ||
314 | # save the results in the global dictionary | |
315 | g.update(done) | |
316 | return g | |
317 | ||
318 | ||
319 | def expand_makefile_vars(s, vars): | |
320 | """Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in | |
321 | 'string' according to 'vars' (a dictionary mapping variable names to | |
322 | values). Variables not present in 'vars' are silently expanded to the | |
323 | empty string. The variable values in 'vars' should not contain further | |
324 | variable expansions; if 'vars' is the output of 'parse_makefile()', | |
325 | you're fine. Returns a variable-expanded version of 's'. | |
326 | """ | |
327 | ||
328 | # This algorithm does multiple expansion, so if vars['foo'] contains | |
329 | # "${bar}", it will expand ${foo} to ${bar}, and then expand | |
330 | # ${bar}... and so forth. This is fine as long as 'vars' comes from | |
331 | # 'parse_makefile()', which takes care of such expansions eagerly, | |
332 | # according to make's variable expansion semantics. | |
333 | ||
334 | while 1: | |
335 | m = _findvar1_rx.search(s) or _findvar2_rx.search(s) | |
336 | if m: | |
337 | (beg, end) = m.span() | |
338 | s = s[0:beg] + vars.get(m.group(1)) + s[end:] | |
339 | else: | |
340 | break | |
341 | return s | |
342 | ||
343 | ||
344 | _config_vars = None | |
345 | ||
346 | def _init_posix(): | |
347 | """Initialize the module as appropriate for POSIX systems.""" | |
348 | g = {} | |
349 | # load the installed Makefile: | |
350 | try: | |
351 | filename = get_makefile_filename() | |
352 | parse_makefile(filename, g) | |
353 | except IOError, msg: | |
354 | my_msg = "invalid Python installation: unable to open %s" % filename | |
355 | if hasattr(msg, "strerror"): | |
356 | my_msg = my_msg + " (%s)" % msg.strerror | |
357 | ||
358 | raise DistutilsPlatformError(my_msg) | |
359 | ||
360 | # On MacOSX we need to check the setting of the environment variable | |
361 | # MACOSX_DEPLOYMENT_TARGET: configure bases some choices on it so | |
362 | # it needs to be compatible. | |
363 | # If it isn't set we set it to the configure-time value | |
364 | if sys.platform == 'darwin' and g.has_key('CONFIGURE_MACOSX_DEPLOYMENT_TARGET'): | |
365 | cfg_target = g['CONFIGURE_MACOSX_DEPLOYMENT_TARGET'] | |
366 | cur_target = os.getenv('MACOSX_DEPLOYMENT_TARGET', '') | |
367 | if cur_target == '': | |
368 | cur_target = cfg_target | |
369 | os.putenv('MACOSX_DEPLOYMENT_TARGET', cfg_target) | |
370 | if cfg_target != cur_target: | |
371 | my_msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: now "%s" but "%s" during configure' | |
372 | % (cur_target, cfg_target)) | |
373 | raise DistutilsPlatformError(my_msg) | |
374 | ||
375 | # On AIX, there are wrong paths to the linker scripts in the Makefile | |
376 | # -- these paths are relative to the Python source, but when installed | |
377 | # the scripts are in another directory. | |
378 | if python_build: | |
379 | g['LDSHARED'] = g['BLDSHARED'] | |
380 | ||
381 | elif sys.version < '2.1': | |
382 | # The following two branches are for 1.5.2 compatibility. | |
383 | if sys.platform == 'aix4': # what about AIX 3.x ? | |
384 | # Linker script is in the config directory, not in Modules as the | |
385 | # Makefile says. | |
386 | python_lib = get_python_lib(standard_lib=1) | |
387 | ld_so_aix = os.path.join(python_lib, 'config', 'ld_so_aix') | |
388 | python_exp = os.path.join(python_lib, 'config', 'python.exp') | |
389 | ||
390 | g['LDSHARED'] = "%s %s -bI:%s" % (ld_so_aix, g['CC'], python_exp) | |
391 | ||
392 | elif sys.platform == 'beos': | |
393 | # Linker script is in the config directory. In the Makefile it is | |
394 | # relative to the srcdir, which after installation no longer makes | |
395 | # sense. | |
396 | python_lib = get_python_lib(standard_lib=1) | |
397 | linkerscript_path = string.split(g['LDSHARED'])[0] | |
398 | linkerscript_name = os.path.basename(linkerscript_path) | |
399 | linkerscript = os.path.join(python_lib, 'config', | |
400 | linkerscript_name) | |
401 | ||
402 | # XXX this isn't the right place to do this: adding the Python | |
403 | # library to the link, if needed, should be in the "build_ext" | |
404 | # command. (It's also needed for non-MS compilers on Windows, and | |
405 | # it's taken care of for them by the 'build_ext.get_libraries()' | |
406 | # method.) | |
407 | g['LDSHARED'] = ("%s -L%s/lib -lpython%s" % | |
408 | (linkerscript, PREFIX, sys.version[0:3])) | |
409 | ||
410 | global _config_vars | |
411 | _config_vars = g | |
412 | ||
413 | ||
414 | def _init_nt(): | |
415 | """Initialize the module as appropriate for NT""" | |
416 | g = {} | |
417 | # set basic install directories | |
418 | g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1) | |
419 | g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1) | |
420 | ||
421 | # XXX hmmm.. a normal install puts include files here | |
422 | g['INCLUDEPY'] = get_python_inc(plat_specific=0) | |
423 | ||
424 | g['SO'] = '.pyd' | |
425 | g['EXE'] = ".exe" | |
426 | ||
427 | global _config_vars | |
428 | _config_vars = g | |
429 | ||
430 | ||
431 | def _init_mac(): | |
432 | """Initialize the module as appropriate for Macintosh systems""" | |
433 | g = {} | |
434 | # set basic install directories | |
435 | g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1) | |
436 | g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1) | |
437 | ||
438 | # XXX hmmm.. a normal install puts include files here | |
439 | g['INCLUDEPY'] = get_python_inc(plat_specific=0) | |
440 | ||
441 | import MacOS | |
442 | if not hasattr(MacOS, 'runtimemodel'): | |
443 | g['SO'] = '.ppc.slb' | |
444 | else: | |
445 | g['SO'] = '.%s.slb' % MacOS.runtimemodel | |
446 | ||
447 | # XXX are these used anywhere? | |
448 | g['install_lib'] = os.path.join(EXEC_PREFIX, "Lib") | |
449 | g['install_platlib'] = os.path.join(EXEC_PREFIX, "Mac", "Lib") | |
450 | ||
451 | # These are used by the extension module build | |
452 | g['srcdir'] = ':' | |
453 | global _config_vars | |
454 | _config_vars = g | |
455 | ||
456 | ||
457 | def _init_os2(): | |
458 | """Initialize the module as appropriate for OS/2""" | |
459 | g = {} | |
460 | # set basic install directories | |
461 | g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1) | |
462 | g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1) | |
463 | ||
464 | # XXX hmmm.. a normal install puts include files here | |
465 | g['INCLUDEPY'] = get_python_inc(plat_specific=0) | |
466 | ||
467 | g['SO'] = '.pyd' | |
468 | g['EXE'] = ".exe" | |
469 | ||
470 | global _config_vars | |
471 | _config_vars = g | |
472 | ||
473 | ||
474 | def get_config_vars(*args): | |
475 | """With no arguments, return a dictionary of all configuration | |
476 | variables relevant for the current platform. Generally this includes | |
477 | everything needed to build extensions and install both pure modules and | |
478 | extensions. On Unix, this means every variable defined in Python's | |
479 | installed Makefile; on Windows and Mac OS it's a much smaller set. | |
480 | ||
481 | With arguments, return a list of values that result from looking up | |
482 | each argument in the configuration variable dictionary. | |
483 | """ | |
484 | global _config_vars | |
485 | if _config_vars is None: | |
486 | func = globals().get("_init_" + os.name) | |
487 | if func: | |
488 | func() | |
489 | else: | |
490 | _config_vars = {} | |
491 | ||
492 | # Normalized versions of prefix and exec_prefix are handy to have; | |
493 | # in fact, these are the standard versions used most places in the | |
494 | # Distutils. | |
495 | _config_vars['prefix'] = PREFIX | |
496 | _config_vars['exec_prefix'] = EXEC_PREFIX | |
497 | ||
498 | if args: | |
499 | vals = [] | |
500 | for name in args: | |
501 | vals.append(_config_vars.get(name)) | |
502 | return vals | |
503 | else: | |
504 | return _config_vars | |
505 | ||
506 | def get_config_var(name): | |
507 | """Return the value of a single variable using the dictionary | |
508 | returned by 'get_config_vars()'. Equivalent to | |
509 | get_config_vars().get(name) | |
510 | """ | |
511 | return get_config_vars().get(name) |