source: python/trunk/Lib/distutils/sysconfig.py@ 388

Last change on this file since 388 was 13, checked in by Yuri Dario, 15 years ago

python: allows submodules to inherit python build flags, so they build with same options. fixes highmem in mercurial.

  • Property svn:eol-style set to native
File size: 23.5 KB
Line 
1"""Provide access to Python's configuration information. The specific
2configuration variables available depend heavily on the platform and
3configuration. The values may be retrieved using
4get_config_var(name), and the list of variables is available via
5get_config_vars().keys(). Additional convenience functions are also
6available.
7
8Written by: Fred L. Drake, Jr.
9Email: <fdrake@acm.org>
10"""
11
12__revision__ = "$Id: sysconfig.py 76739 2009-12-10 10:29:05Z ronald.oussoren $"
13
14import os
15import re
16import string
17import sys
18
19from distutils.errors import DistutilsPlatformError
20
21# These are needed in a couple of spots, so just compute them once.
22PREFIX = os.path.normpath(sys.prefix)
23EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
24
25# Path to the base directory of the project. On Windows the binary may
26# live in project/PCBuild9. If we're dealing with an x64 Windows build,
27# it'll live in project/PCbuild/amd64.
28project_base = os.path.dirname(os.path.abspath(sys.executable))
29if os.name == "nt" and "pcbuild" in project_base[-8:].lower():
30 project_base = os.path.abspath(os.path.join(project_base, os.path.pardir))
31# PC/VS7.1
32if os.name == "nt" and "\\pc\\v" in project_base[-10:].lower():
33 project_base = os.path.abspath(os.path.join(project_base, os.path.pardir,
34 os.path.pardir))
35# PC/AMD64
36if os.name == "nt" and "\\pcbuild\\amd64" in project_base[-14:].lower():
37 project_base = os.path.abspath(os.path.join(project_base, os.path.pardir,
38 os.path.pardir))
39
40# python_build: (Boolean) if true, we're either building Python or
41# building an extension with an un-installed Python, so we use
42# different (hard-wired) directories.
43# Setup.local is available for Makefile builds including VPATH builds,
44# Setup.dist is available on Windows
45def _python_build():
46 for fn in ("Setup.dist", "Setup.local"):
47 if os.path.isfile(os.path.join(project_base, "Modules", fn)):
48 return True
49 return False
50python_build = _python_build()
51
52
53def get_python_version():
54 """Return a string containing the major and minor Python version,
55 leaving off the patchlevel. Sample return values could be '1.5'
56 or '2.2'.
57 """
58 return sys.version[:3]
59
60
61def get_python_inc(plat_specific=0, prefix=None):
62 """Return the directory containing installed Python header files.
63
64 If 'plat_specific' is false (the default), this is the path to the
65 non-platform-specific header files, i.e. Python.h and so on;
66 otherwise, this is the path to platform-specific header files
67 (namely pyconfig.h).
68
69 If 'prefix' is supplied, use it instead of sys.prefix or
70 sys.exec_prefix -- i.e., ignore 'plat_specific'.
71 """
72 if prefix is None:
73 prefix = plat_specific and EXEC_PREFIX or PREFIX
74 if os.name == "posix":
75 if python_build:
76 base = os.path.dirname(os.path.abspath(sys.executable))
77 if plat_specific:
78 inc_dir = base
79 else:
80 inc_dir = os.path.join(base, "Include")
81 if not os.path.exists(inc_dir):
82 inc_dir = os.path.join(os.path.dirname(base), "Include")
83 return inc_dir
84 return os.path.join(prefix, "include", "python" + get_python_version())
85 elif os.name == "nt":
86 return os.path.join(prefix, "include")
87 elif os.name == "mac":
88 if plat_specific:
89 return os.path.join(prefix, "Mac", "Include")
90 else:
91 return os.path.join(prefix, "Include")
92 elif os.name == "os2":
93 if python_build:
94 base = os.path.dirname(os.path.abspath(sys.executable))
95 if plat_specific:
96 inc_dir = base
97 else:
98 inc_dir = os.path.join(base, "Include")
99 if not os.path.exists(inc_dir):
100 inc_dir = os.path.join(os.path.dirname(base), "Include")
101 return inc_dir
102 return os.path.join(prefix, "include", "python" + get_python_version())
103 else:
104 raise DistutilsPlatformError(
105 "I don't know where Python installs its C header files "
106 "on platform '%s'" % os.name)
107
108
109def get_python_lib(plat_specific=0, standard_lib=0, prefix=None):
110 """Return the directory containing the Python library (standard or
111 site additions).
112
113 If 'plat_specific' is true, return the directory containing
114 platform-specific modules, i.e. any module from a non-pure-Python
115 module distribution; otherwise, return the platform-shared library
116 directory. If 'standard_lib' is true, return the directory
117 containing standard Python library modules; otherwise, return the
118 directory for site-specific modules.
119
120 If 'prefix' is supplied, use it instead of sys.prefix or
121 sys.exec_prefix -- i.e., ignore 'plat_specific'.
122 """
123 if prefix is None:
124 prefix = plat_specific and EXEC_PREFIX or PREFIX
125
126 if os.name == "posix":
127 libpython = os.path.join(prefix,
128 "lib", "python" + get_python_version())
129 if standard_lib:
130 return libpython
131 else:
132 return os.path.join(libpython, "site-packages")
133
134 elif os.name == "nt":
135 if standard_lib:
136 return os.path.join(prefix, "Lib")
137 else:
138 if get_python_version() < "2.2":
139 return prefix
140 else:
141 return os.path.join(prefix, "Lib", "site-packages")
142
143 elif os.name == "mac":
144 if plat_specific:
145 if standard_lib:
146 return os.path.join(prefix, "Lib", "lib-dynload")
147 else:
148 return os.path.join(prefix, "Lib", "site-packages")
149 else:
150 if standard_lib:
151 return os.path.join(prefix, "Lib")
152 else:
153 return os.path.join(prefix, "Lib", "site-packages")
154
155 elif os.name == "os2":
156 libpython = os.path.join(prefix,
157 "lib", "python" + get_python_version())
158 if standard_lib:
159 return libpython
160 else:
161 return os.path.join(libpython, "site-packages")
162
163 else:
164 raise DistutilsPlatformError(
165 "I don't know where Python installs its library "
166 "on platform '%s'" % os.name)
167
168
169def customize_compiler(compiler):
170 """Do any platform-specific customization of a CCompiler instance.
171
172 Mainly needed on Unix, so we can plug in the information that
173 varies across Unices and is stored in Python's Makefile.
174 """
175 if compiler.compiler_type == "unix" or compiler.compiler_type == "emx":
176 (cc, cxx, opt, cflags, ccshared, ldshared, so_ext) = \
177 get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS',
178 'CCSHARED', 'LDSHARED', 'SO')
179
180 if 'CC' in os.environ:
181 cc = os.environ['CC']
182 if 'CXX' in os.environ:
183 cxx = os.environ['CXX']
184 if 'LDSHARED' in os.environ:
185 ldshared = os.environ['LDSHARED']
186 if 'CPP' in os.environ:
187 cpp = os.environ['CPP']
188 else:
189 cpp = cc + " -E" # not always
190 if 'LDFLAGS' in os.environ:
191 ldshared = ldshared + ' ' + os.environ['LDFLAGS']
192 if 'CFLAGS' in os.environ:
193 cflags = opt + ' ' + os.environ['CFLAGS']
194 ldshared = ldshared + ' ' + os.environ['CFLAGS']
195 if 'CPPFLAGS' in os.environ:
196 cpp = cpp + ' ' + os.environ['CPPFLAGS']
197 cflags = cflags + ' ' + os.environ['CPPFLAGS']
198 ldshared = ldshared + ' ' + os.environ['CPPFLAGS']
199
200 cc_cmd = cc + ' ' + cflags
201 compiler.set_executables(
202 preprocessor=cpp,
203 compiler=cc_cmd,
204 compiler_so=cc_cmd + ' ' + ccshared,
205 compiler_cxx=cxx,
206 linker_so=ldshared,
207 linker_exe=cc)
208
209 compiler.shared_lib_extension = so_ext
210
211
212def get_config_h_filename():
213 """Return full pathname of installed pyconfig.h file."""
214 if python_build:
215 if os.name == "nt":
216 inc_dir = os.path.join(project_base, "PC")
217 else:
218 inc_dir = project_base
219 else:
220 inc_dir = get_python_inc(plat_specific=1)
221 if get_python_version() < '2.2':
222 config_h = 'config.h'
223 else:
224 # The name of the config.h file changed in 2.2
225 config_h = 'pyconfig.h'
226 return os.path.join(inc_dir, config_h)
227
228
229def get_makefile_filename():
230 """Return full pathname of installed Makefile from the Python build."""
231 if python_build:
232 return os.path.join(os.path.dirname(sys.executable), "Makefile")
233 lib_dir = get_python_lib(plat_specific=1, standard_lib=1)
234 return os.path.join(lib_dir, "config", "Makefile")
235
236
237def parse_config_h(fp, g=None):
238 """Parse a config.h-style file.
239
240 A dictionary containing name/value pairs is returned. If an
241 optional dictionary is passed in as the second argument, it is
242 used instead of a new dictionary.
243 """
244 if g is None:
245 g = {}
246 define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
247 undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
248 #
249 while 1:
250 line = fp.readline()
251 if not line:
252 break
253 m = define_rx.match(line)
254 if m:
255 n, v = m.group(1, 2)
256 try: v = int(v)
257 except ValueError: pass
258 g[n] = v
259 else:
260 m = undef_rx.match(line)
261 if m:
262 g[m.group(1)] = 0
263 return g
264
265
266# Regexes needed for parsing Makefile (and similar syntaxes,
267# like old-style Setup files).
268_variable_rx = re.compile("([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)")
269_findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)")
270_findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}")
271
272def parse_makefile(fn, g=None):
273 """Parse a Makefile-style file.
274
275 A dictionary containing name/value pairs is returned. If an
276 optional dictionary is passed in as the second argument, it is
277 used instead of a new dictionary.
278 """
279 from distutils.text_file import TextFile
280 fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1)
281
282 if g is None:
283 g = {}
284 done = {}
285 notdone = {}
286
287 while 1:
288 line = fp.readline()
289 if line is None: # eof
290 break
291 m = _variable_rx.match(line)
292 if m:
293 n, v = m.group(1, 2)
294 v = v.strip()
295 # `$$' is a literal `$' in make
296 tmpv = v.replace('$$', '')
297
298 if "$" in tmpv:
299 notdone[n] = v
300 else:
301 try:
302 v = int(v)
303 except ValueError:
304 # insert literal `$'
305 done[n] = v.replace('$$', '$')
306 else:
307 done[n] = v
308
309 # do variable interpolation here
310 while notdone:
311 for name in notdone.keys():
312 value = notdone[name]
313 m = _findvar1_rx.search(value) or _findvar2_rx.search(value)
314 if m:
315 n = m.group(1)
316 found = True
317 if n in done:
318 item = str(done[n])
319 elif n in notdone:
320 # get it on a subsequent round
321 found = False
322 elif n in os.environ:
323 # do it like make: fall back to environment
324 item = os.environ[n]
325 else:
326 done[n] = item = ""
327 if found:
328 after = value[m.end():]
329 value = value[:m.start()] + item + after
330 if "$" in after:
331 notdone[name] = value
332 else:
333 try: value = int(value)
334 except ValueError:
335 done[name] = value.strip()
336 else:
337 done[name] = value
338 del notdone[name]
339 else:
340 # bogus variable reference; just drop it since we can't deal
341 del notdone[name]
342
343 fp.close()
344
345 # save the results in the global dictionary
346 g.update(done)
347 return g
348
349
350def expand_makefile_vars(s, vars):
351 """Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in
352 'string' according to 'vars' (a dictionary mapping variable names to
353 values). Variables not present in 'vars' are silently expanded to the
354 empty string. The variable values in 'vars' should not contain further
355 variable expansions; if 'vars' is the output of 'parse_makefile()',
356 you're fine. Returns a variable-expanded version of 's'.
357 """
358
359 # This algorithm does multiple expansion, so if vars['foo'] contains
360 # "${bar}", it will expand ${foo} to ${bar}, and then expand
361 # ${bar}... and so forth. This is fine as long as 'vars' comes from
362 # 'parse_makefile()', which takes care of such expansions eagerly,
363 # according to make's variable expansion semantics.
364
365 while 1:
366 m = _findvar1_rx.search(s) or _findvar2_rx.search(s)
367 if m:
368 (beg, end) = m.span()
369 s = s[0:beg] + vars.get(m.group(1)) + s[end:]
370 else:
371 break
372 return s
373
374
375_config_vars = None
376
377def _init_posix():
378 """Initialize the module as appropriate for POSIX systems."""
379 g = {}
380 # load the installed Makefile:
381 try:
382 filename = get_makefile_filename()
383 parse_makefile(filename, g)
384 except IOError, msg:
385 my_msg = "invalid Python installation: unable to open %s" % filename
386 if hasattr(msg, "strerror"):
387 my_msg = my_msg + " (%s)" % msg.strerror
388
389 raise DistutilsPlatformError(my_msg)
390
391 # load the installed pyconfig.h:
392 try:
393 filename = get_config_h_filename()
394 parse_config_h(file(filename), g)
395 except IOError, msg:
396 my_msg = "invalid Python installation: unable to open %s" % filename
397 if hasattr(msg, "strerror"):
398 my_msg = my_msg + " (%s)" % msg.strerror
399
400 raise DistutilsPlatformError(my_msg)
401
402 # On MacOSX we need to check the setting of the environment variable
403 # MACOSX_DEPLOYMENT_TARGET: configure bases some choices on it so
404 # it needs to be compatible.
405 # If it isn't set we set it to the configure-time value
406 if sys.platform == 'darwin' and 'MACOSX_DEPLOYMENT_TARGET' in g:
407 cfg_target = g['MACOSX_DEPLOYMENT_TARGET']
408 cur_target = os.getenv('MACOSX_DEPLOYMENT_TARGET', '')
409 if cur_target == '':
410 cur_target = cfg_target
411 os.putenv('MACOSX_DEPLOYMENT_TARGET', cfg_target)
412 elif map(int, cfg_target.split('.')) > map(int, cur_target.split('.')):
413 my_msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: now "%s" but "%s" during configure'
414 % (cur_target, cfg_target))
415 raise DistutilsPlatformError(my_msg)
416
417 # On AIX, there are wrong paths to the linker scripts in the Makefile
418 # -- these paths are relative to the Python source, but when installed
419 # the scripts are in another directory.
420 if python_build:
421 g['LDSHARED'] = g['BLDSHARED']
422
423 elif get_python_version() < '2.1':
424 # The following two branches are for 1.5.2 compatibility.
425 if sys.platform == 'aix4': # what about AIX 3.x ?
426 # Linker script is in the config directory, not in Modules as the
427 # Makefile says.
428 python_lib = get_python_lib(standard_lib=1)
429 ld_so_aix = os.path.join(python_lib, 'config', 'ld_so_aix')
430 python_exp = os.path.join(python_lib, 'config', 'python.exp')
431
432 g['LDSHARED'] = "%s %s -bI:%s" % (ld_so_aix, g['CC'], python_exp)
433
434 elif sys.platform == 'beos':
435 # Linker script is in the config directory. In the Makefile it is
436 # relative to the srcdir, which after installation no longer makes
437 # sense.
438 python_lib = get_python_lib(standard_lib=1)
439 linkerscript_path = string.split(g['LDSHARED'])[0]
440 linkerscript_name = os.path.basename(linkerscript_path)
441 linkerscript = os.path.join(python_lib, 'config',
442 linkerscript_name)
443
444 # XXX this isn't the right place to do this: adding the Python
445 # library to the link, if needed, should be in the "build_ext"
446 # command. (It's also needed for non-MS compilers on Windows, and
447 # it's taken care of for them by the 'build_ext.get_libraries()'
448 # method.)
449 g['LDSHARED'] = ("%s -L%s/lib -lpython%s" %
450 (linkerscript, PREFIX, get_python_version()))
451
452 global _config_vars
453 _config_vars = g
454
455
456def _init_nt():
457 """Initialize the module as appropriate for NT"""
458 g = {}
459 # set basic install directories
460 g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1)
461 g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1)
462
463 # XXX hmmm.. a normal install puts include files here
464 g['INCLUDEPY'] = get_python_inc(plat_specific=0)
465
466 g['SO'] = '.pyd'
467 g['EXE'] = ".exe"
468 g['VERSION'] = get_python_version().replace(".", "")
469 g['BINDIR'] = os.path.dirname(os.path.abspath(sys.executable))
470
471 global _config_vars
472 _config_vars = g
473
474
475def _init_mac():
476 """Initialize the module as appropriate for Macintosh systems"""
477 g = {}
478 # set basic install directories
479 g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1)
480 g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1)
481
482 # XXX hmmm.. a normal install puts include files here
483 g['INCLUDEPY'] = get_python_inc(plat_specific=0)
484
485 import MacOS
486 if not hasattr(MacOS, 'runtimemodel'):
487 g['SO'] = '.ppc.slb'
488 else:
489 g['SO'] = '.%s.slb' % MacOS.runtimemodel
490
491 # XXX are these used anywhere?
492 g['install_lib'] = os.path.join(EXEC_PREFIX, "Lib")
493 g['install_platlib'] = os.path.join(EXEC_PREFIX, "Mac", "Lib")
494
495 # These are used by the extension module build
496 g['srcdir'] = ':'
497 global _config_vars
498 _config_vars = g
499
500
501def _init_os2():
502 """Initialize the module as appropriate for OS/2"""
503 g = {}
504 # load the installed Makefile:
505 try:
506 filename = get_makefile_filename()
507 parse_makefile(filename, g)
508 except IOError, msg:
509 my_msg = "invalid Python installation: unable to open %s" % filename
510 if hasattr(msg, "strerror"):
511 my_msg = my_msg + " (%s)" % msg.strerror
512
513 raise DistutilsPlatformError(my_msg)
514
515 # load the installed pyconfig.h:
516 try:
517 filename = get_config_h_filename()
518 parse_config_h(file(filename), g)
519 except IOError, msg:
520 my_msg = "invalid Python installation: unable to open %s" % filename
521 if hasattr(msg, "strerror"):
522 my_msg = my_msg + " (%s)" % msg.strerror
523
524 raise DistutilsPlatformError(my_msg)
525
526 # On AIX, there are wrong paths to the linker scripts in the Makefile
527 # -- these paths are relative to the Python source, but when installed
528 # the scripts are in another directory.
529 if python_build:
530 g['LDSHARED'] = g['BLDSHARED']
531
532 # OS/2 module
533
534 # set basic install directories
535 g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1)
536 g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1)
537
538 # XXX hmmm.. a normal install puts include files here
539 g['INCLUDEPY'] = get_python_inc(plat_specific=0)
540
541 g['SO'] = '.pyd'
542 g['EXE'] = ".exe"
543
544 global _config_vars
545 _config_vars = g
546
547
548def get_config_vars(*args):
549 """With no arguments, return a dictionary of all configuration
550 variables relevant for the current platform. Generally this includes
551 everything needed to build extensions and install both pure modules and
552 extensions. On Unix, this means every variable defined in Python's
553 installed Makefile; on Windows and Mac OS it's a much smaller set.
554
555 With arguments, return a list of values that result from looking up
556 each argument in the configuration variable dictionary.
557 """
558 global _config_vars
559 if _config_vars is None:
560 func = globals().get("_init_" + os.name)
561 if func:
562 func()
563 else:
564 _config_vars = {}
565
566 # Normalized versions of prefix and exec_prefix are handy to have;
567 # in fact, these are the standard versions used most places in the
568 # Distutils.
569 _config_vars['prefix'] = PREFIX
570 _config_vars['exec_prefix'] = EXEC_PREFIX
571
572 if sys.platform == 'darwin':
573 kernel_version = os.uname()[2] # Kernel version (8.4.3)
574 major_version = int(kernel_version.split('.')[0])
575
576 if major_version < 8:
577 # On Mac OS X before 10.4, check if -arch and -isysroot
578 # are in CFLAGS or LDFLAGS and remove them if they are.
579 # This is needed when building extensions on a 10.3 system
580 # using a universal build of python.
581 for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED',
582 # a number of derived variables. These need to be
583 # patched up as well.
584 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
585 flags = _config_vars[key]
586 flags = re.sub('-arch\s+\w+\s', ' ', flags)
587 flags = re.sub('-isysroot [^ \t]*', ' ', flags)
588 _config_vars[key] = flags
589
590 else:
591
592 # Allow the user to override the architecture flags using
593 # an environment variable.
594 # NOTE: This name was introduced by Apple in OSX 10.5 and
595 # is used by several scripting languages distributed with
596 # that OS release.
597
598 if 'ARCHFLAGS' in os.environ:
599 arch = os.environ['ARCHFLAGS']
600 for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED',
601 # a number of derived variables. These need to be
602 # patched up as well.
603 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
604
605 flags = _config_vars[key]
606 flags = re.sub('-arch\s+\w+\s', ' ', flags)
607 flags = flags + ' ' + arch
608 _config_vars[key] = flags
609
610 # If we're on OSX 10.5 or later and the user tries to
611 # compiles an extension using an SDK that is not present
612 # on the current machine it is better to not use an SDK
613 # than to fail.
614 #
615 # The major usecase for this is users using a Python.org
616 # binary installer on OSX 10.6: that installer uses
617 # the 10.4u SDK, but that SDK is not installed by default
618 # when you install Xcode.
619 #
620 m = re.search('-isysroot\s+(\S+)', _config_vars['CFLAGS'])
621 if m is not None:
622 sdk = m.group(1)
623 if not os.path.exists(sdk):
624 for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED',
625 # a number of derived variables. These need to be
626 # patched up as well.
627 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
628
629 flags = _config_vars[key]
630 flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags)
631 _config_vars[key] = flags
632
633 if args:
634 vals = []
635 for name in args:
636 vals.append(_config_vars.get(name))
637 return vals
638 else:
639 return _config_vars
640
641def get_config_var(name):
642 """Return the value of a single variable using the dictionary
643 returned by 'get_config_vars()'. Equivalent to
644 get_config_vars().get(name)
645 """
646 return get_config_vars().get(name)
Note: See TracBrowser for help on using the repository browser.