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 finalize_options(self): # have to finalize 'plat_name' before 'bdist_base' if self.plat_name is None: if self.skip_build: self.plat_name = 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", "build/bdist.<plat>/rpm", 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 DistutilsPlatformError, \ "don't know how to create built distributions " + \ "on platform %s" % os.name if self.dist_dir is None: self.dist_dir = "dist"
def run(self): from distutils2.compiler import new_compiler if not self.extensions: return # If we were asked to build any C/C++ libraries, make sure that the # directory where we put them is in the library search path for # linking extensions. if self.distribution.has_c_libraries(): build_clib = self.get_finalized_command('build_clib') self.libraries.extend(build_clib.get_library_names() or []) self.library_dirs.append(build_clib.build_clib) # Setup the CCompiler object that we'll use to do all the # compiling and linking self.compiler_obj = new_compiler(compiler=self.compiler, dry_run=self.dry_run, force=self.force) customize_compiler(self.compiler_obj) # If we are cross-compiling, init the compiler now (if we are not # cross-compiling, init would not hurt, but people may rely on # late initialization of compiler even if they shouldn't...) if os.name == 'nt' and self.plat_name != get_platform(): self.compiler_obj.initialize(self.plat_name) # And make sure that any compile/link-related options (which might # come from the command line or from the setup script) are set in # that CCompiler object -- that way, they automatically apply to # all compiling and linking done here. if self.include_dirs is not None: self.compiler_obj.set_include_dirs(self.include_dirs) if self.define is not None: # 'define' option is a list of (name,value) tuples for name, value in self.define: self.compiler_obj.define_macro(name, value) if self.undef is not None: for macro in self.undef: self.compiler_obj.undefine_macro(macro) if self.libraries is not None: self.compiler_obj.set_libraries(self.libraries) if self.library_dirs is not None: self.compiler_obj.set_library_dirs(self.library_dirs) if self.rpath is not None: self.compiler_obj.set_runtime_library_dirs(self.rpath) if self.link_objects is not None: self.compiler_obj.set_link_objects(self.link_objects) # Now actually compile and link everything. self.build_extensions()
def run(self): from distutils2.compiler import new_compiler if not self.extensions: return # If we were asked to build any C/C++ libraries, make sure that the # directory where we put them is in the library search path for # linking extensions. if self.distribution.has_c_libraries(): build_clib = self.get_finalized_command('build_clib') self.libraries.extend(build_clib.get_library_names() or []) self.library_dirs.append(build_clib.build_clib) # Setup the CCompiler object that we'll use to do all the # compiling and linking self.compiler_obj = new_compiler(compiler=self.compiler, dry_run=self.dry_run, force=self.force) customize_compiler(self.compiler_obj) # If we are cross-compiling, init the compiler now (if we are not # cross-compiling, init would not hurt, but people may rely on # late initialization of compiler even if they shouldn't...) if os.name == 'nt' and self.plat_name != get_platform(): self.compiler_obj.initialize(self.plat_name) # And make sure that any compile/link-related options (which might # come from the command line or from the setup script) are set in # that CCompiler object -- that way, they automatically apply to # all compiling and linking done here. if self.include_dirs is not None: self.compiler_obj.set_include_dirs(self.include_dirs) if self.define is not None: # 'define' option is a list of (name,value) tuples for name, value in self.define: self.compiler_obj.define_macro(name, value) if self.undef is not None: for macro in self.undef: self.compiler_obj.undefine_macro(macro) if self.libraries is not None: self.compiler_obj.set_libraries(self.libraries) if self.library_dirs is not None: self.compiler_obj.set_library_dirs(self.library_dirs) if self.rpath is not None: self.compiler_obj.set_runtime_library_dirs(self.rpath) if self.link_objects is not None: self.compiler_obj.set_link_objects(self.link_objects) # Now actually compile and link everything. self.build_extensions()
def finalize_options(self): if self.plat_name is None: self.plat_name = get_platform() else: # plat-name only supported for windows (other platforms are # supported via ./configure flags, if at all). Avoid misleading # other platforms. if os.name != 'nt': raise PackagingOptionError( "--plat-name only supported on Windows (try " "using './configure --help' on your platform)") pyversion = '%s.%s' % sys.version_info[:2] plat_specifier = ".%s-%s" % (self.plat_name, pyversion) # Make it so Python 2.x and Python 2.x with --with-pydebug don't # share the same build directories. Doing so confuses the build # process for C modules if hasattr(sys, 'gettotalrefcount'): plat_specifier += '-pydebug' # 'build_purelib' and 'build_platlib' just default to 'lib' and # 'lib.<plat>' under the base build directory. We only use one of # them for a given distribution, though -- if self.build_purelib is None: self.build_purelib = os.path.join(self.build_base, 'lib') if self.build_platlib is None: self.build_platlib = os.path.join(self.build_base, 'lib' + plat_specifier) # 'build_lib' is the actual directory that we will use for this # particular module distribution -- if user didn't supply it, pick # one of 'build_purelib' or 'build_platlib'. if self.build_lib is None: if self.distribution.ext_modules: self.build_lib = self.build_platlib else: self.build_lib = self.build_purelib # 'build_temp' -- temporary directory for compiler turds, # "build/temp.<plat>" if self.build_temp is None: self.build_temp = os.path.join(self.build_base, 'temp' + plat_specifier) if self.build_scripts is None: self.build_scripts = os.path.join(self.build_base, 'scripts-' + pyversion) if self.executable is None: self.executable = os.path.normpath(sys.executable)
def finalize_options(self): if self.plat_name is None: self.plat_name = get_platform() else: # plat-name only supported for windows (other platforms are # supported via ./configure flags, if at all). Avoid misleading # other platforms. if os.name != 'nt': raise DistutilsOptionError( "--plat-name only supported on Windows (try " "using './configure --help' on your platform)") plat_specifier = ".%s-%s" % (self.plat_name, sys.version[0:3]) # Make it so Python 2.x and Python 2.x with --with-pydebug don't # share the same build directories. Doing so confuses the build # process for C modules if hasattr(sys, 'gettotalrefcount'): plat_specifier += '-pydebug' # 'build_purelib' and 'build_platlib' just default to 'lib' and # 'lib.<plat>' under the base build directory. We only use one of # them for a given distribution, though -- if self.build_purelib is None: self.build_purelib = os.path.join(self.build_base, 'lib') if self.build_platlib is None: self.build_platlib = os.path.join(self.build_base, 'lib' + plat_specifier) # 'build_lib' is the actual directory that we will use for this # particular module distribution -- if user didn't supply it, pick # one of 'build_purelib' or 'build_platlib'. if self.build_lib is None: if self.distribution.ext_modules: self.build_lib = self.build_platlib else: self.build_lib = self.build_purelib # 'build_temp' -- temporary directory for compiler turds, # "build/temp.<plat>" if self.build_temp is None: self.build_temp = os.path.join(self.build_base, 'temp' + plat_specifier) if self.build_scripts is None: self.build_scripts = os.path.join(self.build_base, 'scripts-' + sys.version[0:3]) if self.executable is None: self.executable = os.path.normpath(sys.executable)
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 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)
class bdist_dumb(Command): description = 'create a "dumb" built distribution' user_options = [ ('bdist-dir=', 'd', "temporary directory for creating the distribution"), ('plat-name=', 'p', "platform name to embed in generated filenames " "(default: %s)" % get_platform()), ('format=', 'f', "archive format to create (tar, gztar, bztar, zip)"), ('keep-temp', 'k', "keep the pseudo-installation tree around after " + "creating the distribution archive"), ('dist-dir=', 'd', "directory to put final built distributions in"), ('skip-build', None, "skip rebuilding everything (for testing/debugging)"), ('relative', None, "build the archive using relative paths" "(default: false)"), ('owner=', 'u', "Owner name used when creating a tar file" " [default: current user]"), ('group=', 'g', "Group name used when creating a tar file" " [default: current group]"), ] boolean_options = ['keep-temp', 'skip-build', 'relative'] default_format = {'posix': 'gztar', 'nt': 'zip', 'os2': 'zip'} def initialize_options(self): self.bdist_dir = None self.plat_name = None self.format = None self.keep_temp = False self.dist_dir = None self.skip_build = None self.relative = False self.owner = None self.group = None 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 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 _ensure_relative(self, path): # copied from dir_util, deleted drive, path = os.path.splitdrive(path) if path[0:1] == os.sep: path = drive + path[1:] return path
class build_ext(Command): description = "build C/C++ extension modules (compile/link to build directory)" # XXX thoughts on how to deal with complex command-line options like # these, i.e. how to make it so fancy_getopt can suck them off the # command line and turn them into the appropriate # lists of tuples of what-have-you. # - each command needs a callback to process its command-line options # - Command.__init__() needs access to its share of the whole # command line (must ultimately come from # Distribution.parse_command_line()) # - it then calls the current command class' option-parsing # callback to deal with weird options like -D, which have to # parse the option text and churn out some custom data # structure # - that data structure (in this case, a list of 2-tuples) # will then be present in the command object by the time # we get to finalize_options() (i.e. the constructor # takes care of both command-line and client options # in between initialize_options() and finalize_options()) sep_by = " (separated by '%s')" % os.pathsep user_options = [ ('build-lib=', 'b', "directory for compiled extension modules"), ('build-temp=', 't', "directory for temporary files (build by-products)"), ('plat-name=', 'p', "platform name to cross-compile for, if supported " "(default: %s)" % get_platform()), ('inplace', 'i', "ignore build-lib and put compiled extensions into the source " + "directory alongside your pure Python modules"), ('user', None, "add user include, library and rpath"), ('include-dirs=', 'I', "list of directories to search for header files" + sep_by), ('define=', 'D', "C preprocessor macros to define"), ('undef=', 'U', "C preprocessor macros to undefine"), ('libraries=', 'l', "external C libraries to link with"), ('library-dirs=', 'L', "directories to search for external C libraries" + sep_by), ('rpath=', 'R', "directories to search for shared C libraries at runtime"), ('link-objects=', 'O', "extra explicit link objects to include in the link"), ('debug', 'g', "compile/link with debugging information"), ('force', 'f', "forcibly build everything (ignore file timestamps)"), ('compiler=', 'c', "specify the compiler type"), ('swig-opts=', None, "list of SWIG command-line options"), ('swig=', None, "path to the SWIG executable"), ] boolean_options = ['inplace', 'debug', 'force', 'user'] help_options = [ ('help-compiler', None, "list available compilers", show_compilers), ] def initialize_options(self): self.extensions = None self.build_lib = None self.plat_name = None self.build_temp = None self.inplace = False self.package = None self.include_dirs = None self.define = None self.undef = None self.libraries = None self.library_dirs = None self.rpath = None self.link_objects = None self.debug = None self.force = None self.compiler = None self.swig = None self.swig_opts = None self.user = None def finalize_options(self): self.set_undefined_options('build', 'build_lib', 'build_temp', 'compiler', 'debug', 'force', 'plat_name') if self.package is None: self.package = self.distribution.ext_package # Ensure that the list of extensions is valid, i.e. it is a list of # Extension objects. self.extensions = self.distribution.ext_modules if self.extensions: if not isinstance(self.extensions, (list, tuple)): type_name = (self.extensions is None and 'None' or type(self.extensions).__name__) raise PackagingSetupError( "'ext_modules' must be a sequence of Extension instances," " not %s" % (type_name, )) for i, ext in enumerate(self.extensions): if isinstance(ext, Extension): continue # OK! (assume type-checking done # by Extension constructor) type_name = (ext is None and 'None' or type(ext).__name__) raise PackagingSetupError( "'ext_modules' item %d must be an Extension instance," " not %s" % (i, type_name)) # Make sure Python's include directories (for Python.h, pyconfig.h, # etc.) are in the include search path. py_include = sysconfig.get_path('include') plat_py_include = sysconfig.get_path('platinclude') if self.include_dirs is None: self.include_dirs = self.distribution.include_dirs or [] if isinstance(self.include_dirs, str): self.include_dirs = self.include_dirs.split(os.pathsep) # Put the Python "system" include dir at the end, so that # any local include dirs take precedence. self.include_dirs.append(py_include) if plat_py_include != py_include: self.include_dirs.append(plat_py_include) self.ensure_string_list('libraries') # Life is easier if we're not forever checking for None, so # simplify these options to empty lists if unset if self.libraries is None: self.libraries = [] if self.library_dirs is None: self.library_dirs = [] elif isinstance(self.library_dirs, str): self.library_dirs = self.library_dirs.split(os.pathsep) if self.rpath is None: self.rpath = [] elif isinstance(self.rpath, str): self.rpath = self.rpath.split(os.pathsep) # for extensions under windows use different directories # for Release and Debug builds. # also Python's library directory must be appended to library_dirs if os.name == 'nt': # the 'libs' directory is for binary installs - we assume that # must be the *native* platform. But we don't really support # cross-compiling via a binary install anyway, so we let it go. self.library_dirs.append(os.path.join(sys.exec_prefix, 'libs')) if self.debug: self.build_temp = os.path.join(self.build_temp, "Debug") else: self.build_temp = os.path.join(self.build_temp, "Release") # Append the source distribution include and library directories, # this allows distutils on windows to work in the source tree self.include_dirs.append(os.path.join(sys.exec_prefix, 'PC')) if MSVC_VERSION == 9: # Use the .lib files for the correct architecture if self.plat_name == 'win32': suffix = '' else: # win-amd64 or win-ia64 suffix = self.plat_name[4:] new_lib = os.path.join(sys.exec_prefix, 'PCbuild') if suffix: new_lib = os.path.join(new_lib, suffix) self.library_dirs.append(new_lib) elif MSVC_VERSION == 8: self.library_dirs.append( os.path.join(sys.exec_prefix, 'PC', 'VS8.0')) elif MSVC_VERSION == 7: self.library_dirs.append( os.path.join(sys.exec_prefix, 'PC', 'VS7.1')) else: self.library_dirs.append( os.path.join(sys.exec_prefix, 'PC', 'VC6')) # OS/2 (EMX) doesn't support Debug vs Release builds, but has the # import libraries in its "Config" subdirectory if os.name == 'os2': self.library_dirs.append(os.path.join(sys.exec_prefix, 'Config')) # for extensions under Cygwin and AtheOS Python's library directory must be # appended to library_dirs if sys.platform[:6] == 'cygwin' or sys.platform[:6] == 'atheos': if sys.executable.startswith(os.path.join(sys.exec_prefix, "bin")): # building third party extensions self.library_dirs.append( os.path.join(sys.prefix, "lib", "python" + sysconfig.get_python_version(), "config")) else: # building python standard extensions self.library_dirs.append(os.curdir) # for extensions under Linux or Solaris with a shared Python library, # Python's library directory must be appended to library_dirs sysconfig.get_config_var('Py_ENABLE_SHARED') if (sys.platform.startswith(('linux', 'gnu', 'sunos')) and sysconfig.get_config_var('Py_ENABLE_SHARED')): if sys.executable.startswith(os.path.join(sys.exec_prefix, "bin")): # building third party extensions self.library_dirs.append(sysconfig.get_config_var('LIBDIR')) else: # building python standard extensions self.library_dirs.append(os.curdir) # The argument parsing will result in self.define being a string, but # it has to be a list of 2-tuples. All the preprocessor symbols # specified by the 'define' option will be set to '1'. Multiple # symbols can be separated with commas. if self.define: defines = self.define.split(',') self.define = [(symbol, '1') for symbol in defines] # The option for macros to undefine is also a string from the # option parsing, but has to be a list. Multiple symbols can also # be separated with commas here. if self.undef: self.undef = self.undef.split(',') if self.swig_opts is None: self.swig_opts = [] else: self.swig_opts = self.swig_opts.split(' ') # Finally add the user include and library directories if requested if self.user: user_include = os.path.join(site.USER_BASE, "include") user_lib = os.path.join(site.USER_BASE, "lib") if os.path.isdir(user_include): self.include_dirs.append(user_include) if os.path.isdir(user_lib): self.library_dirs.append(user_lib) self.rpath.append(user_lib) def run(self): from distutils2.compiler import new_compiler if not self.extensions: return # If we were asked to build any C/C++ libraries, make sure that the # directory where we put them is in the library search path for # linking extensions. if self.distribution.has_c_libraries(): build_clib = self.get_finalized_command('build_clib') self.libraries.extend(build_clib.get_library_names() or []) self.library_dirs.append(build_clib.build_clib) # Setup the CCompiler object that we'll use to do all the # compiling and linking self.compiler_obj = new_compiler(compiler=self.compiler, dry_run=self.dry_run, force=self.force) customize_compiler(self.compiler_obj) # If we are cross-compiling, init the compiler now (if we are not # cross-compiling, init would not hurt, but people may rely on # late initialization of compiler even if they shouldn't...) if os.name == 'nt' and self.plat_name != get_platform(): self.compiler_obj.initialize(self.plat_name) # And make sure that any compile/link-related options (which might # come from the command line or from the setup script) are set in # that CCompiler object -- that way, they automatically apply to # all compiling and linking done here. if self.include_dirs is not None: self.compiler_obj.set_include_dirs(self.include_dirs) if self.define is not None: # 'define' option is a list of (name,value) tuples for name, value in self.define: self.compiler_obj.define_macro(name, value) if self.undef is not None: for macro in self.undef: self.compiler_obj.undefine_macro(macro) if self.libraries is not None: self.compiler_obj.set_libraries(self.libraries) if self.library_dirs is not None: self.compiler_obj.set_library_dirs(self.library_dirs) if self.rpath is not None: self.compiler_obj.set_runtime_library_dirs(self.rpath) if self.link_objects is not None: self.compiler_obj.set_link_objects(self.link_objects) # Now actually compile and link everything. self.build_extensions() def get_source_files(self): filenames = [] # Wouldn't it be neat if we knew the names of header files too... for ext in self.extensions: filenames.extend(ext.sources) return filenames def get_outputs(self): # And build the list of output (built) filenames. Note that this # ignores the 'inplace' flag, and assumes everything goes in the # "build" tree. outputs = [] for ext in self.extensions: outputs.append(self.get_ext_fullpath(ext.name)) return outputs def build_extensions(self): for ext in self.extensions: try: self.build_extension(ext) except (CCompilerError, PackagingError, CompileError) as e: if not ext.optional: raise logger.warning('%s: building extension %r failed: %s', self.get_command_name(), ext.name, e) def build_extension(self, ext): sources = ext.sources if sources is None or not isinstance(sources, (list, tuple)): raise PackagingSetupError( ("in 'ext_modules' option (extension '%s'), " + "'sources' must be present and must be " + "a list of source filenames") % ext.name) sources = list(sources) ext_path = self.get_ext_fullpath(ext.name) depends = sources + ext.depends if not (self.force or newer_group(depends, ext_path, 'newer')): logger.debug("skipping '%s' extension (up-to-date)", ext.name) return else: logger.info("building '%s' extension", ext.name) # First, scan the sources for SWIG definition files (.i), run # SWIG on 'em to create .c files, and modify the sources list # accordingly. sources = self.swig_sources(sources, ext) # Next, compile the source code to object files. # XXX not honouring 'define_macros' or 'undef_macros' -- the # CCompiler API needs to change to accommodate this, and I # want to do one thing at a time! # Two possible sources for extra compiler arguments: # - 'extra_compile_args' in Extension object # - CFLAGS environment variable (not particularly # elegant, but people seem to expect it and I # guess it's useful) # The environment variable should take precedence, and # any sensible compiler will give precedence to later # command-line args. Hence we combine them in order: extra_args = ext.extra_compile_args or [] macros = ext.define_macros[:] for undef in ext.undef_macros: macros.append((undef, )) objects = self.compiler_obj.compile(sources, output_dir=self.build_temp, macros=macros, include_dirs=ext.include_dirs, debug=self.debug, extra_postargs=extra_args, depends=ext.depends) # XXX -- this is a Vile HACK! # # The setup.py script for Python on Unix needs to be able to # get this list so it can perform all the clean up needed to # avoid keeping object files around when cleaning out a failed # build of an extension module. Since Packaging does not # track dependencies, we have to get rid of intermediates to # ensure all the intermediates will be properly re-built. # self._built_objects = objects[:] # Now link the object files together into a "shared object" -- # of course, first we have to figure out all the other things # that go into the mix. if ext.extra_objects: objects.extend(ext.extra_objects) extra_args = ext.extra_link_args or [] # Detect target language, if not provided language = ext.language or self.compiler_obj.detect_language(sources) self.compiler_obj.link_shared_object( objects, ext_path, libraries=self.get_libraries(ext), library_dirs=ext.library_dirs, runtime_library_dirs=ext.runtime_library_dirs, extra_postargs=extra_args, export_symbols=self.get_export_symbols(ext), debug=self.debug, build_temp=self.build_temp, target_lang=language) def swig_sources(self, sources, extension): """Walk the list of source files in 'sources', looking for SWIG interface (.i) files. Run SWIG on all that are found, and return a modified 'sources' list with SWIG source files replaced by the generated C (or C++) files. """ new_sources = [] swig_sources = [] swig_targets = {} # XXX this drops generated C/C++ files into the source tree, which # is fine for developers who want to distribute the generated # source -- but there should be an option to put SWIG output in # the temp dir. if ('-c++' in self.swig_opts or '-c++' in extension.swig_opts): target_ext = '.cpp' else: target_ext = '.c' for source in sources: base, ext = os.path.splitext(source) if ext == ".i": # SWIG interface file new_sources.append(base + '_wrap' + target_ext) swig_sources.append(source) swig_targets[source] = new_sources[-1] else: new_sources.append(source) if not swig_sources: return new_sources swig = self.swig or self.find_swig() swig_cmd = [swig, "-python"] swig_cmd.extend(self.swig_opts) # Do not override commandline arguments if not self.swig_opts: for o in extension.swig_opts: swig_cmd.append(o) for source in swig_sources: target = swig_targets[source] logger.info("swigging %s to %s", source, target) self.spawn(swig_cmd + ["-o", target, source]) return new_sources 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) # -- Name generators ----------------------------------------------- # (extension names, filenames, whatever) def get_ext_fullpath(self, ext_name): """Returns the path of the filename for a given extension. The file is located in `build_lib` or directly in the package (inplace option). """ fullname = self.get_ext_fullname(ext_name) modpath = fullname.split('.') filename = self.get_ext_filename(modpath[-1]) if not self.inplace: # no further work needed # returning : # build_dir/package/path/filename filename = os.path.join(*modpath[:-1] + [filename]) return os.path.join(self.build_lib, filename) # the inplace option requires to find the package directory # using the build_py command for that package = '.'.join(modpath[0:-1]) build_py = self.get_finalized_command('build_py') package_dir = os.path.abspath(build_py.get_package_dir(package)) # returning # package_dir/filename return os.path.join(package_dir, filename) def get_ext_fullname(self, ext_name): """Returns the fullname of a given extension name. Adds the `package.` prefix""" if self.package is None: return ext_name else: return self.package + '.' + ext_name def get_ext_filename(self, ext_name): r"""Convert the name of an extension (eg. "foo.bar") into the name of the file from which it will be loaded (eg. "foo/bar.so", or "foo\bar.pyd"). """ ext_path = ext_name.split('.') # OS/2 has an 8 character module (extension) limit :-( if os.name == "os2": ext_path[len(ext_path) - 1] = ext_path[len(ext_path) - 1][:8] # extensions in debug_mode are named 'module_d.pyd' under windows so_ext = sysconfig.get_config_var('SO') if os.name == 'nt' and self.debug: return os.path.join(*ext_path) + '_d' + so_ext return os.path.join(*ext_path) + so_ext def get_export_symbols(self, ext): """Return the list of symbols that a shared extension has to export. This either uses 'ext.export_symbols' or, if it's not provided, "init" + module_name. Only relevant on Windows, where the .pyd file (DLL) must export the module "init" function. """ initfunc_name = "PyInit_" + ext.name.split('.')[-1] if initfunc_name not in ext.export_symbols: ext.export_symbols.append(initfunc_name) return ext.export_symbols def get_libraries(self, ext): """Return the list of libraries to link against when building a shared extension. On most platforms, this is just 'ext.libraries'; on Windows and OS/2, we add the Python library (eg. python20.dll). """ # The python library is always needed on Windows. For MSVC, this # is redundant, since the library is mentioned in a pragma in # pyconfig.h that MSVC groks. The other Windows compilers all seem # to need it mentioned explicitly, though, so that's what we do. # Append '_d' to the python import library on debug builds. if sys.platform == "win32": from distutils2.compiler.msvccompiler import MSVCCompiler if not isinstance(self.compiler_obj, MSVCCompiler): template = "python%d%d" if self.debug: template = template + '_d' pythonlib = template % sys.version_info[:2] # don't extend ext.libraries, it may be shared with other # extensions, it is a reference to the original list return ext.libraries + [pythonlib] else: return ext.libraries elif sys.platform == "os2emx": # EMX/GCC requires the python library explicitly, and I # believe VACPP does as well (though not confirmed) - AIM Apr01 template = "python%d%d" # debug versions of the main DLL aren't supported, at least # not at this time - AIM Apr01 #if self.debug: # template = template + '_d' pythonlib = template % sys.version_info[:2] # don't extend ext.libraries, it may be shared with other # extensions, it is a reference to the original list return ext.libraries + [pythonlib] elif sys.platform[:6] == "cygwin": template = "python%d.%d" pythonlib = template % sys.version_info[:2] # don't extend ext.libraries, it may be shared with other # extensions, it is a reference to the original list return ext.libraries + [pythonlib] elif sys.platform[:6] == "atheos": template = "python%d.%d" pythonlib = template % sys.version_info[:2] # Get SHLIBS from Makefile extra = [] for lib in sysconfig.get_config_var('SHLIBS').split(): if lib.startswith('-l'): extra.append(lib[2:]) else: extra.append(lib) # don't extend ext.libraries, it may be shared with other # extensions, it is a reference to the original list return ext.libraries + [pythonlib, "m"] + extra elif sys.platform == 'darwin': # Don't use the default code below return ext.libraries else: if sysconfig.get_config_var('Py_ENABLE_SHARED'): template = 'python%d.%d' + getattr(sys, 'abiflags', '') pythonlib = template % sys.version_info[:2] return ext.libraries + [pythonlib] else: return ext.libraries
class bdist_wininst(Command): description = "create an executable installer for Windows" user_options = [ ('bdist-dir=', None, "temporary directory for creating the distribution"), ('plat-name=', 'p', "platform name to embed in generated filenames " "(default: %s)" % get_platform()), ('keep-temp', 'k', "keep the pseudo-installation tree around after " + "creating the distribution archive"), ('target-version=', None, "require a specific python version" + " on the target system"), ('no-target-compile', 'c', "do not compile .py to .pyc on the target system"), ('no-target-optimize', 'o', "do not compile .py to .pyo (optimized)" "on the target system"), ('dist-dir=', 'd', "directory to put final built distributions in"), ('bitmap=', 'b', "bitmap to use for the installer instead of python-powered logo"), ('title=', 't', "title to display on the installer background instead of default"), ('skip-build', None, "skip rebuilding everything (for testing/debugging)"), ('install-script=', None, "basename of installation script to be run after" "installation or before deinstallation"), ('pre-install-script=', None, "Fully qualified filename of a script to be run before " "any files are installed. This script need not be in the " "distribution"), ('user-access-control=', None, "specify Vista's UAC handling - 'none'/default=no " "handling, 'auto'=use UAC if target Python installed for " "all users, 'force'=always use UAC"), ] boolean_options = [ 'keep-temp', 'no-target-compile', 'no-target-optimize', 'skip-build' ] def initialize_options(self): self.bdist_dir = None self.plat_name = None self.keep_temp = False self.no_target_compile = False self.no_target_optimize = False self.target_version = None self.dist_dir = None self.bitmap = None self.title = None self.skip_build = None self.install_script = None self.pre_install_script = None self.user_access_control = None def finalize_options(self): self.set_undefined_options('bdist', 'skip_build') if self.bdist_dir is None: if self.skip_build and self.plat_name: # If build is skipped and plat_name is overridden, bdist will # not see the correct 'plat_name' - so set that up manually. bdist = self.distribution.get_command_obj('bdist') bdist.plat_name = self.plat_name # next the command will be initialized using that name bdist_base = self.get_finalized_command('bdist').bdist_base self.bdist_dir = os.path.join(bdist_base, 'wininst') if not self.target_version: self.target_version = "" if not self.skip_build and self.distribution.has_ext_modules(): short_version = get_python_version() if self.target_version and self.target_version != short_version: raise PackagingOptionError("target version can only be %s, or the '--skip-build'" \ " option must be specified" % (short_version,)) self.target_version = short_version self.set_undefined_options('bdist', 'dist_dir', 'plat_name') if self.install_script: for script in self.distribution.scripts: if self.install_script == os.path.basename(script): break else: raise PackagingOptionError("install_script '%s' not found in scripts" % \ self.install_script) def run(self): if (sys.platform != "win32" and (self.distribution.has_ext_modules() or self.distribution.has_c_libraries())): raise PackagingPlatformError \ ("distribution contains extensions and/or C libraries; " "must be compiled on a Windows 32 platform") if not self.skip_build: self.run_command('build') install = self.reinitialize_command('install', reinit_subcommands=True) install.root = self.bdist_dir install.skip_build = self.skip_build install.warn_dir = False install.plat_name = self.plat_name install_lib = self.reinitialize_command('install_lib') # we do not want to include pyc or pyo files install_lib.compile = False install_lib.optimize = 0 if self.distribution.has_ext_modules(): # If we are building an installer for a Python version other # than the one we are currently running, then we need to ensure # our build_lib reflects the other Python version rather than ours. # Note that for target_version!=sys.version, we must have skipped the # build step, so there is no issue with enforcing the build of this # version. target_version = self.target_version if not target_version: assert self.skip_build, "Should have already checked this" target_version = '%s.%s' % sys.version_info[:2] plat_specifier = ".%s-%s" % (self.plat_name, target_version) build = self.get_finalized_command('build') build.build_lib = os.path.join(build.build_base, 'lib' + plat_specifier) # Use a custom scheme for the zip-file, because we have to decide # at installation time which scheme to use. for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'): value = key.upper() if key == 'headers': value = value + '/Include/$dist_name' setattr(install, 'install_' + key, value) logger.info("installing to %s", self.bdist_dir) install.ensure_finalized() # avoid warning of 'install_lib' about installing # into a directory not in sys.path sys.path.insert(0, os.path.join(self.bdist_dir, 'PURELIB')) install.run() del sys.path[0] # And make an archive relative to the root of the # pseudo-installation tree. from tempfile import NamedTemporaryFile archive_basename = NamedTemporaryFile().name fullname = self.distribution.get_fullname() arcname = self.make_archive(archive_basename, "zip", root_dir=self.bdist_dir) # create an exe containing the zip-file self.create_exe(arcname, fullname, self.bitmap) if self.distribution.has_ext_modules(): pyversion = get_python_version() else: pyversion = 'any' self.distribution.dist_files.append( ('bdist_wininst', pyversion, self.get_installer_filename(fullname))) # remove the zip-file again logger.debug("removing temporary file '%s'", arcname) os.remove(arcname) if not self.keep_temp: logger.info('removing %s', self.bdist_dir) if not self.dry_run: rmtree(self.bdist_dir) def get_inidata(self): # Return data describing the installation. lines = [] metadata = self.distribution.metadata # Write the [metadata] section. lines.append("[metadata]") # 'info' will be displayed in the installer's dialog box, # describing the items to be installed. info = (metadata.long_description or '') + '\n' # Escape newline characters def escape(s): return s.replace("\n", "\\n") for name in [ "author", "author_email", "description", "maintainer", "maintainer_email", "name", "url", "version" ]: data = getattr(metadata, name, "") if data: info = info + ("\n %s: %s" % \ (name.capitalize(), escape(data))) lines.append("%s=%s" % (name, escape(data))) # The [setup] section contains entries controlling # the installer runtime. lines.append("\n[Setup]") if self.install_script: lines.append("install_script=%s" % self.install_script) lines.append("info=%s" % escape(info)) lines.append("target_compile=%d" % (not self.no_target_compile)) lines.append("target_optimize=%d" % (not self.no_target_optimize)) if self.target_version: lines.append("target_version=%s" % self.target_version) if self.user_access_control: lines.append("user_access_control=%s" % self.user_access_control) title = self.title or self.distribution.get_fullname() lines.append("title=%s" % escape(title)) import time import distutils2 build_info = "Built %s with distutils2-%s" % \ (time.ctime(time.time()), distutils2.__version__) lines.append("build_info=%s" % build_info) return "\n".join(lines) def create_exe(self, arcname, fullname, bitmap=None): import struct self.mkpath(self.dist_dir) cfgdata = self.get_inidata() installer_name = self.get_installer_filename(fullname) logger.info("creating %s", installer_name) if bitmap: with open(bitmap, "rb") as fp: bitmapdata = fp.read() bitmaplen = len(bitmapdata) else: bitmaplen = 0 with open(installer_name, "wb") as file: file.write(self.get_exe_bytes()) if bitmap: file.write(bitmapdata) # Convert cfgdata from unicode to ascii, mbcs encoded if isinstance(cfgdata, str): cfgdata = cfgdata.encode("mbcs") # Append the pre-install script cfgdata = cfgdata + b"\0" if self.pre_install_script: # We need to normalize newlines, so we open in text mode and # convert back to bytes. "latin-1" simply avoids any possible # failures. with open(self.pre_install_script, encoding="latin-1") as fp: script_data = fp.read().encode("latin-1") cfgdata = cfgdata + script_data + b"\n\0" else: # empty pre-install script cfgdata = cfgdata + b"\0" file.write(cfgdata) # The 'magic number' 0x1234567B is used to make sure that the # binary layout of 'cfgdata' is what the wininst.exe binary # expects. If the layout changes, increment that number, make # the corresponding changes to the wininst.exe sources, and # recompile them. header = struct.pack( "<iii", 0x1234567B, # tag len(cfgdata), # length bitmaplen, # number of bytes in bitmap ) file.write(header) with open(arcname, "rb") as fp: file.write(fp.read()) def get_installer_filename(self, fullname): # Factored out to allow overriding in subclasses if self.target_version: # if we create an installer for a specific python version, # it's better to include this in the name installer_name = os.path.join( self.dist_dir, "%s.%s-py%s.exe" % (fullname, self.plat_name, self.target_version)) else: installer_name = os.path.join( self.dist_dir, "%s.%s.exe" % (fullname, self.plat_name)) return installer_name def get_exe_bytes(self): from distutils2.compiler.msvccompiler import get_build_version # If a target-version other than the current version has been # specified, then using the MSVC version from *this* build is no good. # Without actually finding and executing the target version and parsing # its sys.version, we just hard-code our knowledge of old versions. # NOTE: Possible alternative is to allow "--target-version" to # specify a Python executable rather than a simple version string. # We can then execute this program to obtain any info we need, such # as the real sys.version string for the build. cur_version = get_python_version() if self.target_version and self.target_version != cur_version: # If the target version is *later* than us, then we assume they # use what we use # string compares seem wrong, but are what sysconfig.py itself uses if self.target_version > cur_version: bv = get_build_version() else: if self.target_version < "2.4": bv = 6.0 else: bv = 7.1 else: # for current version - use authoritative check. bv = get_build_version() # wininst-x.y.exe is in the same directory as this file directory = os.path.dirname(__file__) # we must use a wininst-x.y.exe built with the same C compiler # used for python. XXX What about mingw, borland, and so on? # if plat_name starts with "win" but is not "win32" # we want to strip "win" and leave the rest (e.g. -amd64) # for all other cases, we don't want any suffix if self.plat_name != 'win32' and self.plat_name[:3] == 'win': sfix = self.plat_name[3:] else: sfix = '' filename = os.path.join(directory, "wininst-%.1f%s.exe" % (bv, sfix)) with open(filename, "rb") as fp: return fp.read()
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 DistutilsPlatformError("--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'].encode('mbcs').split(os.pathsep) os.environ['lib'] = vc_env['lib'].encode('mbcs') os.environ['include'] = vc_env['include'].encode('mbcs') if len(self.__paths) == 0: raise DistutilsPlatformError("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
def test_set_platform(self): self.addCleanup(util.set_platform, util.get_platform()) util.set_platform("fake") self.assertEqual("fake", util.get_platform())
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
def run(self): from distutils2.compiler.ccompiler import new_compiler # 'self.extensions', as supplied by setup.py, is a list of # Extension instances. See the documentation for Extension (in # distutils.extension) for details. # # For backwards compatibility with Distutils 0.8.2 and earlier, we # also allow the 'extensions' list to be a list of tuples: # (ext_name, build_info) # where build_info is a dictionary containing everything that # Extension instances do except the name, with a few things being # differently named. We convert these 2-tuples to Extension # instances as needed. if not self.extensions: return # If we were asked to build any C/C++ libraries, make sure that the # directory where we put them is in the library search path for # linking extensions. if self.distribution.has_c_libraries(): build_clib = self.get_finalized_command('build_clib') self.libraries.extend(build_clib.get_library_names() or []) self.library_dirs.append(build_clib.build_clib) # Setup the CCompiler object that we'll use to do all the # compiling and linking # used to prevent the usage of an existing compiler for the # compiler option when calling new_compiler() # this will be removed in 3.3 and 2.8 if not isinstance(self._compiler, str): self._compiler = None self.compiler_obj = new_compiler(compiler=self._compiler, verbose=self.verbose, dry_run=self.dry_run, force=self.force) # used to keep the compiler object reachable with # "self.compiler". this will be removed in 3.3 and 2.8 self._compiler = self.compiler_obj customize_compiler(self.compiler_obj) # If we are cross-compiling, init the compiler now (if we are not # cross-compiling, init would not hurt, but people may rely on # late initialization of compiler even if they shouldn't...) if os.name == 'nt' and self.plat_name != get_platform(): self.compiler_obj.initialize(self.plat_name) # And make sure that any compile/link-related options (which might # come from the command-line or from the setup script) are set in # that CCompiler object -- that way, they automatically apply to # all compiling and linking done here. if self.include_dirs is not None: self.compiler_obj.set_include_dirs(self.include_dirs) if self.define is not None: # 'define' option is a list of (name,value) tuples for (name, value) in self.define: self.compiler_obj.define_macro(name, value) if self.undef is not None: for macro in self.undef: self.compiler_obj.undefine_macro(macro) if self.libraries is not None: self.compiler_obj.set_libraries(self.libraries) if self.library_dirs is not None: self.compiler_obj.set_library_dirs(self.library_dirs) if self.rpath is not None: self.compiler_obj.set_runtime_library_dirs(self.rpath) if self.link_objects is not None: self.compiler_obj.set_link_objects(self.link_objects) # Now actually compile and link everything. self.build_extensions()
class bdist(Command): description = "create a built (binary) distribution" user_options = [('bdist-base=', 'b', "temporary directory for creating built distributions"), ('plat-name=', 'p', "platform name to embed in generated filenames " "(default: %s)" % util.get_platform()), ('formats=', None, "formats for distribution (comma-separated list)"), ('dist-dir=', 'd', "directory to put final built distributions in " "[default: dist]"), ('skip-build', None, "skip rebuilding everything (for testing/debugging)"), ('owner=', 'u', "Owner name used when creating a tar file" " [default: current user]"), ('group=', 'g', "Group name used when creating a tar file" " [default: current group]"), ] boolean_options = ['skip-build'] help_options = [ ('help-formats', None, "lists available distribution formats", show_formats), ] # This is of course very simplistic. The various UNIX family operating # systems have their specific formats, but they are out of scope for us; # bdist_dumb is, well, dumb; it's more a building block for other # packaging tools than a real end-user binary format. default_format = {'posix': 'gztar', 'nt': 'zip', 'os2': 'zip'} # Establish the preferred order (for the --help-formats option). format_commands = ['gztar', 'bztar', 'tar', 'wininst', 'zip', 'msi'] # And the real information. format_command = {'gztar': ('bdist_dumb', "gzip'ed tar file"), 'bztar': ('bdist_dumb', "bzip2'ed tar file"), 'tar': ('bdist_dumb', "tar file"), 'wininst': ('bdist_wininst', "Windows executable installer"), 'zip': ('bdist_dumb', "ZIP file"), 'msi': ('bdist_msi', "Microsoft Installer"), } def initialize_options(self): self.bdist_base = None self.plat_name = None self.formats = None self.dist_dir = None self.skip_build = False self.group = None self.owner = None 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 run(self): # Figure out which sub-commands we need to run. commands = [] for format in self.formats: try: commands.append(self.format_command[format][0]) except KeyError: raise PackagingOptionError("invalid format '%s'" % format) # Reinitialize and run each command. for i in range(len(self.formats)): cmd_name = commands[i] sub_cmd = self.reinitialize_command(cmd_name) sub_cmd.format = self.formats[i] # passing the owner and group names for tar archiving if cmd_name == 'bdist_dumb': sub_cmd.owner = self.owner sub_cmd.group = self.group # If we're going to need to run this command again, tell it to # keep its temporary files around so subsequent runs go faster. if cmd_name in commands[i+1:]: sub_cmd.keep_temp = True self.run_command(cmd_name)
class build(Command): description = "build everything needed to install" user_options = [ ('build-base=', 'b', "base directory for build library"), ('build-purelib=', None, "build directory for platform-neutral distributions"), ('build-platlib=', None, "build directory for platform-specific distributions"), ('build-lib=', None, "build directory for all distribution (defaults to either " + "build-purelib or build-platlib"), ('build-scripts=', None, "build directory for scripts"), ('build-temp=', 't', "temporary build directory"), ('plat-name=', 'p', "platform name to build for, if supported " "(default: %s)" % get_platform()), ('compiler=', 'c', "specify the compiler type"), ('debug', 'g', "compile extensions and libraries with debugging information"), ('force', 'f', "forcibly build everything (ignore file timestamps)"), ('executable=', 'e', "specify final destination interpreter path (build.py)"), ('use-2to3', None, "use 2to3 to make source python 3.x compatible"), ('convert-2to3-doctests', None, "use 2to3 to convert doctests in separate text files"), ('use-2to3-fixers', None, "list additional fixers opted for during 2to3 conversion"), ] boolean_options = ['debug', 'force'] help_options = [ ('help-compiler', None, "list available compilers", show_compilers), ] def initialize_options(self): self.build_base = 'build' # these are decided only after 'build_base' has its final value # (unless overridden by the user or client) self.build_purelib = None self.build_platlib = None self.build_lib = None self.build_temp = None self.build_scripts = None self.compiler = None self.plat_name = None self.debug = None self.force = False self.executable = None self.use_2to3 = False self.convert_2to3_doctests = None self.use_2to3_fixers = None def finalize_options(self): if self.plat_name is None: self.plat_name = get_platform() else: # plat-name only supported for windows (other platforms are # supported via ./configure flags, if at all). Avoid misleading # other platforms. if os.name != 'nt': raise PackagingOptionError( "--plat-name only supported on Windows (try " "using './configure --help' on your platform)") pyversion = '%s.%s' % sys.version_info[:2] plat_specifier = ".%s-%s" % (self.plat_name, pyversion) # Make it so Python 2.x and Python 2.x with --with-pydebug don't # share the same build directories. Doing so confuses the build # process for C modules if hasattr(sys, 'gettotalrefcount'): plat_specifier += '-pydebug' # 'build_purelib' and 'build_platlib' just default to 'lib' and # 'lib.<plat>' under the base build directory. We only use one of # them for a given distribution, though -- if self.build_purelib is None: self.build_purelib = os.path.join(self.build_base, 'lib') if self.build_platlib is None: self.build_platlib = os.path.join(self.build_base, 'lib' + plat_specifier) # 'build_lib' is the actual directory that we will use for this # particular module distribution -- if user didn't supply it, pick # one of 'build_purelib' or 'build_platlib'. if self.build_lib is None: if self.distribution.ext_modules: self.build_lib = self.build_platlib else: self.build_lib = self.build_purelib # 'build_temp' -- temporary directory for compiler turds, # "build/temp.<plat>" if self.build_temp is None: self.build_temp = os.path.join(self.build_base, 'temp' + plat_specifier) if self.build_scripts is None: self.build_scripts = os.path.join(self.build_base, 'scripts-' + pyversion) if self.executable is None: self.executable = os.path.normpath(sys.executable) def run(self): # Run all relevant sub-commands. This will be some subset of: # - build_py - pure Python modules # - build_clib - standalone C libraries # - build_ext - Python extension modules # - build_scripts - Python scripts for cmd_name in self.get_sub_commands(): self.run_command(cmd_name) # -- Predicates for the sub-command list --------------------------- def has_pure_modules(self): return self.distribution.has_pure_modules() def has_c_libraries(self): return self.distribution.has_c_libraries() def has_ext_modules(self): return self.distribution.has_ext_modules() def has_scripts(self): return self.distribution.has_scripts() sub_commands = [('build_py', has_pure_modules), ('build_clib', has_c_libraries), ('build_ext', has_ext_modules), ('build_scripts', has_scripts), ]