def check_package(self, package, package_dir): # Empty dir name means current directory, which we can probably # assume exists. Also, os.path.exists and isdir don't know about # my "empty string means current dir" convention, so we have to # circumvent them. if package_dir != "": if not os.path.exists(package_dir): raise DistutilsFileError( "package directory '%s' does not exist" % package_dir) if not os.path.isdir(package_dir): raise DistutilsFileError( "supposed package directory '%s' exists, " "but is not a directory" % package_dir) # Require __init__.py for all but the "root package" if package: init_py = os.path.join(package_dir, "__init__.py") if os.path.isfile(init_py): return init_py else: log.warn(("package init file '%s' not found " + "(or not a regular file)"), init_py) # Either not in a package at all (__init__.py not expected), or # __init__.py doesn't exist -- so don't return the filename. return None
def run(self): # remove the build/temp.<plat> directory (unless it's already # gone) if os.path.exists(self.build_temp): if self.dry_run: log.info('Removing %s' % self.build_temp) else: rmtree(self.build_temp) else: log.debug("'%s' does not exist -- can't clean it", self.build_temp) if self.all: # remove build directories for directory in (self.build_lib, self.bdist_base, self.build_scripts): if os.path.exists(directory): if self.dry_run: log.info('Removing %s' % directory) else: rmtree(directory) else: log.warn("'%s' does not exist -- can't clean it", directory) # just for the heck of it, try to remove the base build directory: # we might have emptied it right now, but if not we don't care if not self.dry_run: try: os.rmdir(self.build_base) log.info("removing '%s'", self.build_base) except OSError: pass
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 self.swig_cpp: log.warn("--swig-cpp is deprecated - use --swig-opts=-c++") if self.swig_cpp or ('-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) if self.swig_cpp: swig_cmd.append("-c++") # 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] log.info("swigging %s to %s", source, target) self.spawn(swig_cmd + ["-o", target, source]) return new_sources
def make_release_tree(self, base_dir, files): """Create the directory tree that will become the source distribution archive. All directories implied by the filenames in 'files' are created under 'base_dir', and then we hard link or copy (if hard linking is unavailable) those files into place. Essentially, this duplicates the developer's source tree, but in a directory named after the distribution, containing only the files to be distributed. """ # Create all the directories under 'base_dir' necessary to # put 'files' there; the 'mkpath()' is just so we don't die # if the manifest happens to be empty. self.mkpath(base_dir) self.create_tree(base_dir, files, dry_run=self.dry_run) # And walk over the list of files, either making a hard link (if # os.link exists) to each one that doesn't already exist in its # corresponding location under 'base_dir', or copying each file # that's out-of-date in 'base_dir'. (Usually, all files will be # out-of-date, because by default we blow away 'base_dir' when # we're done making the distribution archives.) if hasattr(os, "link"): # can make hard links on this system link = "hard" msg = "making hard links in %s..." % base_dir else: # nope, have to copy link = None msg = "copying files to %s..." % base_dir if not files: log.warn("no files to distribute -- empty manifest?") else: log.info(msg) for file in files: if not os.path.isfile(file): log.warn("'%s' not a regular file -- skipping" % file) else: dest = os.path.join(base_dir, file) self.copy_file(file, dest, link=link) self.distribution.metadata.write(os.path.join(base_dir, "PKG-INFO"))
def set(self, name, value): """Control then set a metadata field.""" name = self._convert_name(name) if ((name in _ELEMENTSFIELD or name == 'Platform') and not isinstance(value, (list, tuple))): if isinstance(value, str): value = [v.strip() for v in value.split(',')] else: value = [] elif (name in _LISTFIELDS and not isinstance(value, (list, tuple))): if isinstance(value, str): value = [value] else: value = [] if name in _PREDICATE_FIELDS and value is not None: for v in value: # check that the values are valid predicates if not is_valid_predicate(v.split(';')[0]): warn('"%s" is not a valid predicate (field "%s")' % (v, name)) # FIXME this rejects UNKNOWN, is that right? elif name in _VERSIONS_FIELDS and value is not None: if not is_valid_versions(value): warn('"%s" is not a valid version (field "%s")' % (value, name)) elif name in _VERSION_FIELDS and value is not None: if not is_valid_version(value): warn('"%s" is not a valid version (field "%s")' % (value, name)) if name in _UNICODEFIELDS: value = self._encode_field(value) if name == 'Description': value = self._remove_line_prefix(value) self._fields[name] = value self._set_best_version()
def set(self, name, value): """Controls then sets a metadata field""" name = self._convert_name(name) if (name in _ELEMENTSFIELD + ('Platform',) and not isinstance(value, (list, tuple))): if isinstance(value, str): value = value.split(',') else: value = [] elif (name in _LISTFIELDS and not isinstance(value, (list, tuple))): if isinstance(value, str): value = [value] else: value = None if name in _PREDICATE_FIELDS and value is not None: for v in value: # check that the values are valid predicates if not is_valid_predicate(v.split(';')[0]): warn('"%s" is not a valid predicate' % v) elif name in _VERSIONS_FIELDS and value is not None: if not is_valid_versions(value): warn('"%s" is not a valid predicate' % value) elif name in _VERSION_FIELDS and value is not None: if not is_valid_version(value): warn('"%s" is not a valid version' % value) if name in _UNICODEFIELDS: value = self._encode_field(value) if name == 'Description': value = self._remove_line_prefix(value) self._fields[name] = value self._set_best_version()
def check_extensions_list(self, extensions): """Ensure that the list of extensions (presumably provided as a command option 'extensions') is valid, i.e. it is a list of Extension objects. We also support the old-style list of 2-tuples, where the tuples are (ext_name, build_info), which are converted to Extension instances here. Raise DistutilsSetupError if the structure is invalid anywhere; just returns otherwise. """ if not isinstance(extensions, list): raise DistutilsSetupError, \ "'ext_modules' option must be a list of Extension instances" for i, ext in enumerate(extensions): if isinstance(ext, Extension): continue # OK! (assume type-checking done # by Extension constructor) if not isinstance(ext, tuple) or len(ext) != 2: raise DistutilsSetupError, \ ("each element of 'ext_modules' option must be an " "Extension instance or 2-tuple") ext_name, build_info = ext log.warn(("old-style (ext_name, build_info) tuple found in " "ext_modules for extension '%s'" "-- please convert to Extension instance" % ext_name)) if not (isinstance(ext_name, str) and extension_name_re.match(ext_name)): raise DistutilsSetupError, \ ("first element of each tuple in 'ext_modules' " "must be the extension name (a string)") if not isinstance(build_info, dict): raise DistutilsSetupError, \ ("second element of each tuple in 'ext_modules' " "must be a dictionary (build info)") # OK, the (ext_name, build_info) dict is type-safe: convert it # to an Extension instance. ext = Extension(ext_name, build_info['sources']) # Easy stuff: one-to-one mapping from dict elements to # instance attributes. for key in ('include_dirs', 'library_dirs', 'libraries', 'extra_objects', 'extra_compile_args', 'extra_link_args'): val = build_info.get(key) if val is not None: setattr(ext, key, val) # Medium-easy stuff: same syntax/semantics, different names. ext.runtime_library_dirs = build_info.get('rpath') if 'def_file' in build_info: log.warn("'def_file' element of build info dict " "no longer supported") # Non-trivial stuff: 'macros' split into 'define_macros' # and 'undef_macros'. macros = build_info.get('macros') if macros: ext.define_macros = [] ext.undef_macros = [] for macro in macros: if not (isinstance(macro, tuple) and len(macro) in (1, 2)): raise DistutilsSetupError, \ ("'macros' element of build info dict " "must be 1- or 2-tuple") if len(macro) == 1: ext.undef_macros.append(macro[0]) elif len(macro) == 2: ext.define_macros.append(macro) extensions[i] = ext
def link (self, target_desc, objects, output_filename, output_dir=None, libraries=None, library_dirs=None, runtime_library_dirs=None, export_symbols=None, debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, target_lang=None): # XXX this ignores 'build_temp'! should follow the lead of # msvccompiler.py (objects, output_dir) = self._fix_object_args (objects, output_dir) (libraries, library_dirs, runtime_library_dirs) = \ self._fix_lib_args (libraries, library_dirs, runtime_library_dirs) if runtime_library_dirs: log.warn("I don't know what to do with 'runtime_library_dirs': %s", str(runtime_library_dirs)) if output_dir is not None: output_filename = os.path.join (output_dir, output_filename) if self._need_link (objects, output_filename): # Figure out linker args based on type of target. if target_desc == CCompiler.EXECUTABLE: startup_obj = 'c0w32' if debug: ld_args = self.ldflags_exe_debug[:] else: ld_args = self.ldflags_exe[:] else: startup_obj = 'c0d32' if debug: ld_args = self.ldflags_shared_debug[:] else: ld_args = self.ldflags_shared[:] # Create a temporary exports file for use by the linker if export_symbols is None: def_file = '' else: head, tail = os.path.split (output_filename) modname, ext = os.path.splitext (tail) temp_dir = os.path.dirname(objects[0]) # preserve tree structure def_file = os.path.join (temp_dir, '%s.def' % modname) contents = ['EXPORTS'] for sym in (export_symbols or []): contents.append(' %s=_%s' % (sym, sym)) self.execute(write_file, (def_file, contents), "writing %s" % def_file) # Borland C++ has problems with '/' in paths objects2 = map(os.path.normpath, objects) # split objects in .obj and .res files # Borland C++ needs them at different positions in the command line objects = [startup_obj] resources = [] for file in objects2: (base, ext) = os.path.splitext(os.path.normcase(file)) if ext == '.res': resources.append(file) else: objects.append(file) for l in library_dirs: ld_args.append("/L%s" % os.path.normpath(l)) ld_args.append("/L.") # we sometimes use relative paths # list of object files ld_args.extend(objects) # XXX the command-line syntax for Borland C++ is a bit wonky; # certain filenames are jammed together in one big string, but # comma-delimited. This doesn't mesh too well with the # Unix-centric attitude (with a DOS/Windows quoting hack) of # 'spawn()', so constructing the argument list is a bit # awkward. Note that doing the obvious thing and jamming all # the filenames and commas into one argument would be wrong, # because 'spawn()' would quote any filenames with spaces in # them. Arghghh!. Apparently it works fine as coded... # name of dll/exe file ld_args.extend([',',output_filename]) # no map file and start libraries ld_args.append(',,') for lib in libraries: # see if we find it and if there is a bcpp specific lib # (xxx_bcpp.lib) libfile = self.find_library_file(library_dirs, lib, debug) if libfile is None: ld_args.append(lib) # probably a BCPP internal library -- don't warn else: # full name which prefers bcpp_xxx.lib over xxx.lib ld_args.append(libfile) # some default libraries ld_args.append ('import32') ld_args.append ('cw32mt') # def file for export symbols ld_args.extend([',',def_file]) # add resource files ld_args.append(',') ld_args.extend(resources) if extra_preargs: ld_args[:0] = extra_preargs if extra_postargs: ld_args.extend(extra_postargs) self.mkpath (os.path.dirname (output_filename)) try: self.spawn ([self.linker] + ld_args) except DistutilsExecError, msg: raise LinkError, msg
def warn(self, msg): log.warn("warning: %s: %s\n" % (self.get_command_name(), msg))
def process_template_line(self, line): # Parse the line: split it up, make sure the right number of words # is there, and return the relevant words. 'action' is always # defined: it's the first word of the line. Which of the other # three are defined depends on the action; it'll be either # patterns, (dir and patterns), or (dir_pattern). action, patterns, dir, dir_pattern = self._parse_template_line(line) # OK, now we know that the action is valid and we have the # right number of words on the line for that action -- so we # can proceed with minimal error-checking. if action == 'include': for pattern in patterns: if not self.include_pattern(pattern, anchor=1): log.warn("warning: no files found matching '%s'", pattern) elif action == 'exclude': for pattern in patterns: if not self.exclude_pattern(pattern, anchor=1): log.warn(("warning: no previously-included files " "found matching '%s'"), pattern) elif action == 'global-include': for pattern in patterns: if not self.include_pattern(pattern, anchor=0): log.warn(("warning: no files found matching '%s' " + "anywhere in distribution"), pattern) elif action == 'global-exclude': for pattern in patterns: if not self.exclude_pattern(pattern, anchor=0): log.warn(("warning: no previously-included files matching " "'%s' found anywhere in distribution"), pattern) elif action == 'recursive-include': for pattern in patterns: if not self.include_pattern(pattern, prefix=dir): log.warn(("warning: no files found matching '%s' " + "under directory '%s'"), pattern, dir) elif action == 'recursive-exclude': for pattern in patterns: if not self.exclude_pattern(pattern, prefix=dir): log.warn(("warning: no previously-included files matching " "'%s' found under directory '%s'"), pattern, dir) elif action == 'graft': if not self.include_pattern(None, prefix=dir_pattern): log.warn("warning: no directories found matching '%s'", dir_pattern) elif action == 'prune': if not self.exclude_pattern(None, prefix=dir_pattern): log.warn(("no previously-included directories found " + "matching '%s'"), dir_pattern) else: raise DistutilsInternalError, \ "this cannot happen: invalid action '%s'" % action
def check_module(self, module, module_file): if not os.path.isfile(module_file): log.warn("file %s (for module %s) not found", module_file, module) return False else: return True
def _darwin_compiler_fixup(compiler_so, cc_args): """ This function will strip '-isysroot PATH' and '-arch ARCH' from the compile flags if the user has specified one them in extra_compile_flags. This is needed because '-arch ARCH' adds another architecture to the build, without a way to remove an architecture. Furthermore GCC will barf if multiple '-isysroot' arguments are present. """ stripArch = stripSysroot = 0 compiler_so = list(compiler_so) kernel_version = os.uname()[2] # 8.4.3 major_version = int(kernel_version.split('.')[0]) if major_version < 8: # OSX before 10.4.0, these don't support -arch and -isysroot at # all. stripArch = stripSysroot = True else: stripArch = '-arch' in cc_args stripSysroot = '-isysroot' in cc_args if stripArch or 'ARCHFLAGS' in os.environ: while 1: try: index = compiler_so.index('-arch') # Strip this argument and the next one: del compiler_so[index:index+2] except ValueError: break if 'ARCHFLAGS' in os.environ and not stripArch: # User specified different -arch flags in the environ, # see also the sysconfig compiler_so = compiler_so + os.environ['ARCHFLAGS'].split() if stripSysroot: try: index = compiler_so.index('-isysroot') # Strip this argument and the next one: del compiler_so[index:index+2] except ValueError: pass # Check if the SDK that is used during compilation actually exists, # the universal build requires the usage of a universal SDK and not all # users have that installed by default. sysroot = None if '-isysroot' in cc_args: idx = cc_args.index('-isysroot') sysroot = cc_args[idx+1] elif '-isysroot' in compiler_so: idx = compiler_so.index('-isysroot') sysroot = compiler_so[idx+1] if sysroot and not os.path.isdir(sysroot): log.warn("Compiling with an SDK that doesn't seem to exist: %s", sysroot) log.warn("Please check your Xcode installation") return compiler_so