Exemple #1
0
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)
Exemple #3
0
    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"
Exemple #4
0
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)
Exemple #5
0
    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')
Exemple #9
0
    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")
Exemple #12
0
 def runtime_library_dir_option(self, dir):
     raise PackagingPlatformError(
         "don't know how to set runtime library search path for MSVC++")
Exemple #13
0
    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
Exemple #14
0
        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.