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