import os, sys, re import ConfigParser from distutils.ccompiler import show_compilers from distutils.core import Command, DEBUG from distutils.errors import DistutilsOptionError, DistutilsPlatformError from distutils import util, sysconfig def get_python_lib(prefix): libdir = sysconfig.get_python_lib(prefix=prefix) if libdir not in sys.path: libdir = sysconfig.get_python_lib() return libdir CONFIG_SCHEMES = { 'fhs_local' : { 'pythonlibdir' : get_python_lib('/usr/local'), 'includedir' : '/usr/local/include/$name', 'bindir' : '/usr/local/bin', 'datadir' : '/usr/local/share/$name', 'sysconfdir' : '/usr/local/etc/$name', 'localstatedir' : '/var/local/lib/$name', 'libdir' : '/usr/local/lib/$name', 'docdir' : '/usr/local/share/doc/$name', 'localedir' : '/usr/local/share/locale', 'mandir' : '/usr/local/share/man', }, 'fhs_system' : { 'pythonlibdir' : get_python_lib('/usr'), 'includedir' : '/usr/include/$name', 'bindir' : '/usr/bin', 'datadir' : '/usr/share/$name', 'sysconfdir' : '/etc/$name', 'localstatedir' : '/var/lib/$name', 'libdir' : '/usr/lib/$name', 'docdir' : '/usr/share/doc/$name', 'localedir' : '/usr/share/locale', 'mandir' : '/usr/share/man', }, 'posix_autoconf' : { 'pythonlibdir' : sysconfig.get_python_lib(), 'includedir' : '$prefix/include/$name', 'bindir' : '$exec_prefix/bin', 'datadir' : '$prefix/share/$name', 'sysconfdir' : '$prefix/etc/$name', 'localstatedir' : '$exec_prefix/var/$name', 'libdir' : '$exec_prefix/lib/$name', 'docdir' : '$prefix/share/doc/$name', 'localedir' : '$datadir/locale', 'mandir' : '$prefix/man', }, 'posix_home' : { 'pythonlibdir' : '$prefix/lib/python$python_version', 'includedir' : '$prefix/include/python$python_version/$name', 'bindir' : '$prefix/bin', 'datadir' : '$prefix/share/$name', 'sysconfdir' : '$prefix/share/etc/$name', 'localstatedir' : '$prefix/share/var/$name', 'libdir' : '$prefix/lib/$name', 'docdir' : '$prefix/share/doc/$name', 'localedir' : '$prefix/share/locale', 'mandir' : '$prefix/share/man', }, 'nt' : { 'pythonlibdir' : '$prefix/Lib/site-packages', 'includedir' : '$prefix/Include/$name', 'bindir' : '$prefix/Scripts', 'datadir' : '$prefix/Share/$name', 'sysconfdir' : '$prefix/Share/Settings/$name', 'localstatedir' : '$prefix/Share/$name', 'libdir' : '$prefix/Share/$name', 'docdir' : '$prefix/Share/Doc/$name', 'localedir' : '$prefix/Share/Locale', 'mandir' : '$prefix/Share/Help', }, 'other' : { 'pythonlibdir' : '$prefix/Lib/site-packages', 'includedir' : '$prefix/Include/$name', 'bindir' : '$prefix/Scripts', 'datadir' : '$prefix/Share/$name', 'sysconfdir' : '$prefix/Share/Settings/$name', 'localstatedir' : '$prefix/Share/$name', 'libdir' : '$prefix/Share/$name', 'docdir' : '$prefix/Share/Doc/$name', 'localedir' : '$prefix/Share/Locale', 'mandir' : '$prefix/Share/Help', }, } CACHE_FILENAME = 'config.cache' CONFIG_KEYS = ('prefix', 'exec_prefix', 'pythonlibdir', 'includedir', 'bindir', 'datadir', 'sysconfdir', 'localstatedir', 'libdir', 'docdir', 'localedir', 'mandir', 'compiler', 'debug') class Config(Command): command_name = 'config' description = 'select installation scheme and base directories' user_options = [ # All platforms support the 'prefix' installation scheme. ('prefix=', None, 'Use POSIX autoconf-style or Windows installation scheme with this prefix'), ] # POSIX systems have additional scheme selectors. if os.name == 'posix': user_options.extend([ ('exec-prefix=', None, 'Prefix for platform-specific files (for use with --prefix)'), ('local', None, 'Use FHS /usr/local installation scheme [default]'), ('system', None, 'Use FHS /usr installation scheme (e.g. for RPM builds)'), ]) user_options.extend([ # All platforms also support the 'home' installation scheme. ('home=', None, 'Use home directory installation scheme with this prefix'), # Fine-tuning of directories ('pythonlibdir=', None, 'Directory for 3rd-party Python libraries (site-packages)'), ('includedir=', None, 'Directory for C header files'), ('bindir=', None, 'Directory for user executables'), ('datadir=', None, 'Directory for read-only platform-independent data'), ('sysconfdir=', None, 'Directory for read-only host-specific data'), ('localstatedir=', None, 'Directory for modifiable host-specific data'), ('libdir=',None, 'Directory for program & package libraries'), ('docdir=', None, 'Directory for documentation files'), ('localedir=', None, 'Directory for message catalogs'), ('mandir=', None, 'Directory for man documentation'), # Compilation options ('compiler=', 'c', "specify the compiler type"), ('debug', 'g', "compile extensions and libraries with debugging information"), ('plat-name=', 'p', "target platform for compiling extensions and libraries" " (default: %s)" % util.get_platform()), ]) boolean_options = ['local', 'system', 'debug'] help_options = [ ('help-compiler', None, "list available compilers", show_compilers), ] def initialize_options(self): self.cache_filename = CACHE_FILENAME self.scheme = None # User selectable Options self.local = None self.system = None self.home = None self.prefix = None self.exec_prefix = None self.pythonlibdir = None self.includedir = None self.bindir = None self.datadir = None self.sysconfdir = None self.localstatedir = None self.libdir = None self.docdir = None self.localedir = None self.mandir = None self.compiler = None self.debug = None self.plat_name = None return def finalize_options(self): if DEBUG: print "Config.finalize_options():" if self.debug is None: # sys.getobjects() is only defined in a debug build of Python self.debug = hasattr(sys, 'getobjects') if self.plat_name is None: self.plat_name = util.get_platform() cache_section = self.plat_name + '-' + sys.version[:3] if self.debug: cache_section += '-debug' if os.name == 'posix': self.finalize_posix() else: self.finalize_other() # Read the configuration cache to fill in values not already set. parser = ConfigParser.ConfigParser() if self.cache_filename and os.path.exists(self.cache_filename): if DEBUG: print " reading", self.cache_filename fp = open(self.cache_filename, 'rb') parser.readfp(fp) fp.close() # Use the cached configuration only if the platform specific section # already exists in the cache (duh!) and no options have been # specified by the user. changed = False if not (parser.has_section(cache_section) and not (self.local or self.system or self.home or filter(self.__dict__.get, CONFIG_KEYS))): # Fill in the cache with values from the scheme and options. if not parser.has_section(cache_section): parser.add_section(cache_section) # string values for key in ('prefix', 'exec_prefix', 'compiler'): value = getattr(self, key) or '' parser.set(cache_section, key, value) # boolean values for key in ('debug',): value = str(getattr(self, key)) parser.set(cache_section, key, value) # Set the scheme directories from the options, or the default # value if not specified. scheme = CONFIG_SCHEMES[self.scheme] for key in scheme.keys(): value = getattr(self, key) if value is None: value = scheme[key] parser.set(cache_section, key, value) changed = True elif DEBUG: print ' using cached options' # string values for key in ('prefix', 'exec_prefix', 'compiler'): if parser.has_option(cache_section, key): value = parser.get(cache_section, key) or None setattr(self, key, value) else: value = getattr(self, key) or '' parser.set(cache_section, key, value) changed = True # boolean values for key in ('debug',): if parser.has_option(cache_section, key): value = eval(parser.get(cache_section, key)) setattr(self, key, value) else: value = str(getattr(self, key)) parser.set(cache_section, key, value) changed = True # directory scheme scheme = CONFIG_SCHEMES[self.scheme] for key in scheme.keys(): if parser.has_option(cache_section, key): value = parser.get(cache_section, key) or None if value and key == 'docdir' and value.find('$fullname') >= 0: value = value.replace('$fullname', '$name') changed = True setattr(self, key, value) else: value = CONFIG_SCHEMES[self.scheme][key] parser.set(cache_section, key, value) changed = True # Save this configuration for next run if self.cache_filename and changed: if DEBUG: print ' writing', self.cache_filename print ' [%s]' % cache_section for name in CONFIG_KEYS: value = parser.get(cache_section, name) print ' %s = %s' % (name, value) fp = open(self.cache_filename, 'wb') parser.write(fp) fp.close() if self.prefix is None: self.prefix = sys.prefix self.finalize_config_vars() return def finalize_posix(self): # Only one of local/system/home/[prefix|exec-prefix] may be given # The easiest determine this is to just count the Nones specified_count = ((self.local is not None) + (self.system is not None) + (self.home is not None) + ((self.prefix or self.exec_prefix) is not None)) if specified_count > 1: raise DistutilsOptionError("only one of --local, --system, --home" " or --prefix/exec-prefix allowed") if self.local or not specified_count: self.scheme = 'fhs_local' elif self.system: self.scheme = 'fhs_system' elif self.home: self.prefix = self.exec_prefix = os.path.expanduser(self.home) self.scheme = 'posix_home' else: # Either self.prefix or self.exec_prefix is specified if self.exec_prefix is None: self.exec_prefix = self.prefix elif self.prefix is None: raise DistutilsOptionError, \ "must not supply exec-prefix without prefix" self.prefix = os.path.expanduser(self.prefix) self.exec_prefix = os.path.expanduser(self.exec_prefix) self.scheme = 'posix_autoconf' return def finalize_other(self): if self.local: self.warn("'--local' option ignored on this platform") self.local = None if self.system: self.warn("'--system' option ignored on this platform") self.system = None if self.exec_prefix: self.warn("'--exec-prefix' option ignored on this platform") self.exec_prefix = None if self.home: self.warn("'--home' option ignored on this platform") self.home = None if os.name == 'nt': self.scheme = 'nt' else: self.scheme = 'other' return def finalize_config_vars(self): # Expand configuration variables, tilde, etc. main_distribution = self.distribution.main_distribution if main_distribution is None: main_distribution = self.distribution self.config_vars = { 'name' : main_distribution.get_name(), 'version' : main_distribution.get_version(), 'fullname' : main_distribution.get_fullname(), 'python_version' : sys.version[:3], } for key in CONFIG_KEYS: value = getattr(self, key) # Distutils prior to Python 2.3 cannot handle empty strings # in the util.* functions. if isinstance(value, str) and value: if os.name == 'posix': value = os.path.expanduser(value) value = util.convert_path(value) value = util.subst_vars(value, self.config_vars) self.config_vars[key] = value return self.config_vars def run(self): if DEBUG: print "Config.run():" for name in CONFIG_KEYS: print ' ', name, '=', getattr(self, name) return