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