def query_vcvarsall(version, arch="x86"): """Launch vcvarsall.bat and read the settings from its environment """ vcvarsall = find_vcvarsall(version) interesting = set(("include", "lib", "libpath", "path")) result = {} if vcvarsall is None: raise PackagingPlatformError("Unable to find vcvarsall.bat") logger.debug("calling 'vcvarsall.bat %s' (version=%s)", arch, version) popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch), stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = popen.communicate() if popen.wait() != 0: raise PackagingPlatformError(stderr.decode("mbcs")) stdout = stdout.decode("mbcs") for line in stdout.split("\n"): line = Reg.convert_mbcs(line) if '=' not in line: continue line = line.strip() key, value = line.split('=', 1) key = key.lower() if key in interesting: if value.endswith(os.pathsep): value = value[:-1] result[key] = removeDuplicates(value) if len(result) != len(interesting): raise ValueError(str(list(result))) return result
def find_swig(self): """Return the name of the SWIG executable. On Unix, this is just "swig" -- it should be in the PATH. Tries a bit harder on Windows. """ if os.name == "posix": return "swig" elif os.name == "nt": # Look for SWIG in its standard installation directory on # Windows (or so I presume!). If we find it there, great; # if not, act like Unix and assume it's in the PATH. for vers in ("1.3", "1.2", "1.1"): fn = os.path.join("c:\\swig%s" % vers, "swig.exe") if os.path.isfile(fn): return fn else: return "swig.exe" elif os.name == "os2": # assume swig available in the PATH. return "swig.exe" else: raise PackagingPlatformError( ("I don't know how to find (much less run) SWIG " "on platform '%s'") % os.name)
def finalize_options(self): # have to finalize 'plat_name' before 'bdist_base' if self.plat_name is None: if self.skip_build: self.plat_name = util.get_platform() else: self.plat_name = self.get_finalized_command('build').plat_name # 'bdist_base' -- parent of per-built-distribution-format # temporary directories (eg. we'll probably have # "build/bdist.<plat>/dumb", etc.) if self.bdist_base is None: build_base = self.get_finalized_command('build').build_base self.bdist_base = os.path.join(build_base, 'bdist.' + self.plat_name) self.ensure_string_list('formats') if self.formats is None: try: self.formats = [self.default_format[os.name]] except KeyError: raise PackagingPlatformError( "don't know how to create built distributions " "on platform %s" % os.name) if self.dist_dir is None: self.dist_dir = "dist"
def new_compiler(plat=None, compiler=None, dry_run=False, force=False): """Generate an instance of some CCompiler subclass for the supplied platform/compiler combination. 'plat' defaults to 'os.name' (eg. 'posix', 'nt'), and 'compiler' defaults to the default compiler for that platform. Currently only 'posix' and 'nt' are supported, and the default compilers are "traditional Unix interface" (UnixCCompiler class) and Visual C++ (MSVCCompiler class). Note that it's perfectly possible to ask for a Unix compiler object under Windows, and a Microsoft compiler object under Unix -- if you supply a value for 'compiler', 'plat' is ignored. """ if plat is None: plat = os.name try: if compiler is None: compiler = get_default_compiler(plat) cls = _COMPILERS[compiler] except KeyError: msg = "don't know how to compile C/C++ code on platform '%s'" % plat if compiler is not None: msg = msg + " with '%s' compiler" % compiler raise PackagingPlatformError(msg) if isinstance(cls, str): cls = resolve_name(cls) _COMPILERS[compiler] = cls return cls(dry_run, force)
def load_macros(self, version): self.set_macro("VCInstallDir", self.vsbase + r"\Setup\VC", "productdir") self.set_macro("VSInstallDir", self.vsbase + r"\Setup\VS", "productdir") self.set_macro("FrameworkDir", NET_BASE, "installroot") try: if version >= 8.0: self.set_macro("FrameworkSDKDir", NET_BASE, "sdkinstallrootv2.0") else: raise KeyError("sdkinstallrootv2.0") except KeyError: raise PackagingPlatformError( """Python was built with Visual Studio 2008; extensions must be built with a compiler than can generate compatible binaries. Visual Studio 2008 was not found on this system. If you have Cygwin installed, you can try compiling with MingW32, by passing "-c mingw32" to pysetup.""") if version >= 9.0: self.set_macro("FrameworkVersion", self.vsbase, "clr version") self.set_macro("WindowsSdkDir", WINSDK_BASE, "currentinstallfolder") else: p = r"Software\Microsoft\NET Framework Setup\Product" for base in HKEYS: try: h = RegOpenKeyEx(base, p) except RegError: continue key = RegEnumKey(h, 0) d = Reg.get_value(base, r"%s\%s" % (p, key)) self.macros["$(FrameworkVersion)"] = d["version"]
def run(self): if not self.skip_build: self.run_command('build') install = self.reinitialize_command('install_dist', reinit_subcommands=True) install.root = self.bdist_dir install.skip_build = self.skip_build install.warn_dir = False logger.info("installing to %s", self.bdist_dir) self.run_command('install_dist') # And make an archive relative to the root of the # pseudo-installation tree. archive_basename = "%s.%s" % (self.distribution.get_fullname(), self.plat_name) # OS/2 objects to any ":" characters in a filename (such as when # a timestamp is used in a version) so change them to hyphens. if os.name == "os2": archive_basename = archive_basename.replace(":", "-") pseudoinstall_root = os.path.join(self.dist_dir, archive_basename) if not self.relative: archive_root = self.bdist_dir else: if (self.distribution.has_ext_modules() and (install.install_base != install.install_platbase)): raise PackagingPlatformError( "can't make a dumb built distribution where base and " "platbase are different (%r, %r)" % (install.install_base, install.install_platbase)) else: archive_root = os.path.join( self.bdist_dir, self._ensure_relative(install.install_base)) # Make the archive filename = self.make_archive(pseudoinstall_root, self.format, root_dir=archive_root, owner=self.owner, group=self.group) if self.distribution.has_ext_modules(): pyversion = get_python_version() else: pyversion = 'any' self.distribution.dist_files.append( ('bdist_dumb', pyversion, filename)) if not self.keep_temp: if self.dry_run: logger.info('removing %s', self.bdist_dir) else: rmtree(self.bdist_dir)
def finalize_other(self): """Finalize options for non-posix platforms""" if self.user: if self.install_userbase is None: raise PackagingPlatformError( "user base directory is not specified") self.install_base = self.install_platbase = self.install_userbase self.select_scheme(os.name + "_user") elif self.home is not None: self.install_base = self.install_platbase = self.home self.select_scheme("posix_home") else: if self.prefix is None: self.prefix = os.path.normpath(sys.prefix) self.install_base = self.install_platbase = self.prefix try: self.select_scheme(os.name) except KeyError: raise PackagingPlatformError( "no support for installation on '%s'" % os.name)
def finalize_options(self): if self.bdist_dir is None: bdist_base = self.get_finalized_command('bdist').bdist_base self.bdist_dir = os.path.join(bdist_base, 'dumb') if self.format is None: try: self.format = self.default_format[os.name] except KeyError: raise PackagingPlatformError( "don't know how to create dumb built distributions " "on platform %s" % os.name) self.set_undefined_options('bdist', 'dist_dir', 'plat_name', 'skip_build')
def finalize_options(self): if self.manifest is None: self.manifest = "MANIFEST" self.ensure_string_list('formats') if self.formats is None: try: self.formats = [self.default_format[os.name]] except KeyError: raise PackagingPlatformError("don't know how to create source " "distributions on platform %s" % os.name) bad_format = self._check_archive_formats(self.formats) if bad_format: raise PackagingOptionError("unknown archive format '%s'" \ % bad_format) if self.dist_dir is None: self.dist_dir = "dist" if self.filelist is None: self.filelist = Manifest() if self.manifest_builders is None: self.manifest_builders = [] else: if isinstance(self.manifest_builders, str): self.manifest_builders = self.manifest_builders.split(',') builders = [] for builder in self.manifest_builders: builder = builder.strip() if builder == '': continue try: builder = resolve_name(builder) except ImportError as e: raise PackagingModuleError(e) builders.append(builder) self.manifest_builders = builders
def run(self): """Runs the command.""" # Obviously have to build before we can install if not self.skip_build: self.run_command('build') # If we built for any other platform, we can't install. build_plat = self.distribution.get_command_obj('build').plat_name # check warn_dir - it is a clue that the 'install_dist' is happening # internally, and not to sys.path, so we don't check the platform # matches what we are running. if self.warn_dir and build_plat != get_platform(): raise PackagingPlatformError("Can't install when " "cross-compiling") # Run all sub-commands (at least those that need to be run) for cmd_name in self.get_sub_commands(): self.run_command(cmd_name) if self.path_file: self.create_path_file() # write list of installed files, if requested. if self.record: outputs = self.get_outputs() if self.root: # strip any package prefix root_len = len(self.root) for counter in range(len(outputs)): outputs[counter] = outputs[counter][root_len:] self.execute( write_file, (self.record, outputs), "writing list of installed files to '%s'" % self.record) normpath, normcase = os.path.normpath, os.path.normcase sys_path = [normcase(normpath(p)) for p in sys.path] install_lib = normcase(normpath(self.install_lib)) if (self.warn_dir and not (self.path_file and self.install_path_file) and install_lib not in sys_path): logger.debug(("modules installed to '%s', which is not in " "Python's module search path (sys.path) -- " "you'll have to change the search path yourself"), self.install_lib)
def finalize_unix(self): """Finalize options for posix platforms.""" if self.install_base is not None or self.install_platbase is not None: if ((self.install_lib is None and self.install_purelib is None and self.install_platlib is None) or self.install_headers is None or self.install_scripts is None or self.install_data is None): raise PackagingOptionError( "install-base or install-platbase supplied, but " "installation scheme is incomplete") return if self.user: if self.install_userbase is None: raise PackagingPlatformError( "user base directory is not specified") self.install_base = self.install_platbase = self.install_userbase self.select_scheme("posix_user") elif self.home is not None: self.install_base = self.install_platbase = self.home self.select_scheme("posix_home") else: if self.prefix is None: if self.exec_prefix is not None: raise PackagingOptionError( "must not supply exec-prefix without prefix") self.prefix = os.path.normpath(sys.prefix) self.exec_prefix = os.path.normpath(sys.exec_prefix) else: if self.exec_prefix is None: self.exec_prefix = self.prefix self.install_base = self.prefix self.install_platbase = self.exec_prefix self.select_scheme("posix_prefix")
def runtime_library_dir_option(self, dir): raise PackagingPlatformError( "don't know how to set runtime library search path for MSVC++")
def initialize(self, plat_name=None): # multi-init means we would need to check platform same each time... assert not self.initialized, "don't init multiple times" if plat_name is None: plat_name = get_platform() # sanity check for platforms to prevent obscure errors later. ok_plats = 'win32', 'win-amd64', 'win-ia64' if plat_name not in ok_plats: raise PackagingPlatformError("--plat-name must be one of %s" % (ok_plats, )) if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe( "cl.exe"): # Assume that the SDK set up everything alright; don't try to be # smarter self.cc = "cl.exe" self.linker = "link.exe" self.lib = "lib.exe" self.rc = "rc.exe" self.mc = "mc.exe" else: # On x86, 'vcvars32.bat amd64' creates an env that doesn't work; # to cross compile, you use 'x86_amd64'. # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross # compile use 'x86' (ie, it runs the x86 compiler directly) # No idea how itanium handles this, if at all. if plat_name == get_platform() or plat_name == 'win32': # native build or cross-compile to win32 plat_spec = PLAT_TO_VCVARS[plat_name] else: # cross compile from win32 -> some 64bit plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \ PLAT_TO_VCVARS[plat_name] vc_env = query_vcvarsall(VERSION, plat_spec) # take care to only use strings in the environment. self.__paths = vc_env['path'].split(os.pathsep) os.environ['lib'] = vc_env['lib'] os.environ['include'] = vc_env['include'] if len(self.__paths) == 0: raise PackagingPlatformError( "Python was built with %s, " "and extensions need to be built with the same " "version of the compiler, but it isn't installed." % self.__product) self.cc = self.find_exe("cl.exe") self.linker = self.find_exe("link.exe") self.lib = self.find_exe("lib.exe") self.rc = self.find_exe("rc.exe") # resource compiler self.mc = self.find_exe("mc.exe") # message compiler #self.set_path_env_var('lib') #self.set_path_env_var('include') # extend the MSVC path with the current path try: for p in os.environ['path'].split(';'): self.__paths.append(p) except KeyError: pass self.__paths = normalize_and_reduce_paths(self.__paths) os.environ['path'] = ";".join(self.__paths) self.preprocess_options = None if self.__arch == "x86": self.compile_options = ['/nologo', '/Ox', '/MD', '/W3', '/DNDEBUG'] self.compile_options_debug = [ '/nologo', '/Od', '/MDd', '/W3', '/Z7', '/D_DEBUG' ] else: # Win64 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-', '/DNDEBUG' ] self.compile_options_debug = [ '/nologo', '/Od', '/MDd', '/W3', '/GS-', '/Z7', '/D_DEBUG' ] self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO'] if self.__version >= 7: self.ldflags_shared_debug = [ '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG', '/pdb:None' ] self.ldflags_static = ['/nologo'] self.initialized = True
key = key.lower() if key in interesting: if value.endswith(os.pathsep): value = value[:-1] result[key] = removeDuplicates(value) if len(result) != len(interesting): raise ValueError(str(list(result))) return result # More globals VERSION = get_build_version() if VERSION < 8.0: raise PackagingPlatformError("VC %0.1f is not supported by this module" % VERSION) # MACROS = MacroExpander(VERSION) class MSVCCompiler(CCompiler): """Concrete class that implements an interface to Microsoft Visual C++, as defined by the CCompiler abstract class.""" name = 'msvc' description = 'Microsoft Visual C++' # Just set this so CCompiler's constructor doesn't barf. We currently # don't use the 'set_executables()' bureaucracy provided by CCompiler, # as it really isn't necessary for this sort of single-compiler class. # Would be nice to have a consistent interface with UnixCCompiler, # though, so it's worth thinking about.