123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657 |
- """
- Support code for building Python extensions on Windows.
- # NT stuff
- # 1. Make sure libpython<version>.a exists for gcc. If not, build it.
- # 2. Force windows to use gcc (we're struggling with MSVC and g77 support)
- # 3. Force windows to use g77
- """
- from __future__ import division, absolute_import, print_function
- import os
- import sys
- import subprocess
- import re
- # Overwrite certain distutils.ccompiler functions:
- import numpy.distutils.ccompiler
- if sys.version_info[0] < 3:
- from . import log
- else:
- from numpy.distutils import log
- # NT stuff
- # 1. Make sure libpython<version>.a exists for gcc. If not, build it.
- # 2. Force windows to use gcc (we're struggling with MSVC and g77 support)
- # --> this is done in numpy/distutils/ccompiler.py
- # 3. Force windows to use g77
- import distutils.cygwinccompiler
- from distutils.version import StrictVersion
- from numpy.distutils.ccompiler import gen_preprocess_options, gen_lib_options
- from distutils.unixccompiler import UnixCCompiler
- from distutils.msvccompiler import get_build_version as get_build_msvc_version
- from distutils.errors import (DistutilsExecError, CompileError,
- UnknownFileError)
- from numpy.distutils.misc_util import (msvc_runtime_library,
- msvc_runtime_version,
- msvc_runtime_major,
- get_build_architecture)
- def get_msvcr_replacement():
- """Replacement for outdated version of get_msvcr from cygwinccompiler"""
- msvcr = msvc_runtime_library()
- return [] if msvcr is None else [msvcr]
- # monkey-patch cygwinccompiler with our updated version from misc_util
- # to avoid getting an exception raised on Python 3.5
- distutils.cygwinccompiler.get_msvcr = get_msvcr_replacement
- # Useful to generate table of symbols from a dll
- _START = re.compile(r'\[Ordinal/Name Pointer\] Table')
- _TABLE = re.compile(r'^\s+\[([\s*[0-9]*)\] ([a-zA-Z0-9_]*)')
- # the same as cygwin plus some additional parameters
- class Mingw32CCompiler(distutils.cygwinccompiler.CygwinCCompiler):
- """ A modified MingW32 compiler compatible with an MSVC built Python.
- """
- compiler_type = 'mingw32'
- def __init__ (self,
- verbose=0,
- dry_run=0,
- force=0):
- distutils.cygwinccompiler.CygwinCCompiler.__init__ (self, verbose,
- dry_run, force)
- # we need to support 3.2 which doesn't match the standard
- # get_versions methods regex
- if self.gcc_version is None:
- p = subprocess.Popen(['gcc', '-dumpversion'], shell=True,
- stdout=subprocess.PIPE)
- out_string = p.stdout.read()
- p.stdout.close()
- result = re.search(r'(\d+\.\d+)', out_string)
- if result:
- self.gcc_version = StrictVersion(result.group(1))
- # A real mingw32 doesn't need to specify a different entry point,
- # but cygwin 2.91.57 in no-cygwin-mode needs it.
- if self.gcc_version <= "2.91.57":
- entry_point = '--entry _DllMain@12'
- else:
- entry_point = ''
- if self.linker_dll == 'dllwrap':
- # Commented out '--driver-name g++' part that fixes weird
- # g++.exe: g++: No such file or directory
- # error (mingw 1.0 in Enthon24 tree, gcc-3.4.5).
- # If the --driver-name part is required for some environment
- # then make the inclusion of this part specific to that
- # environment.
- self.linker = 'dllwrap' # --driver-name g++'
- elif self.linker_dll == 'gcc':
- self.linker = 'g++'
- # **changes: eric jones 4/11/01
- # 1. Check for import library on Windows. Build if it doesn't exist.
- build_import_library()
- # Check for custom msvc runtime library on Windows. Build if it doesn't exist.
- msvcr_success = build_msvcr_library()
- msvcr_dbg_success = build_msvcr_library(debug=True)
- if msvcr_success or msvcr_dbg_success:
- # add preprocessor statement for using customized msvcr lib
- self.define_macro('NPY_MINGW_USE_CUSTOM_MSVCR')
- # Define the MSVC version as hint for MinGW
- msvcr_version = msvc_runtime_version()
- if msvcr_version:
- self.define_macro('__MSVCRT_VERSION__', '0x%04i' % msvcr_version)
- # MS_WIN64 should be defined when building for amd64 on windows,
- # but python headers define it only for MS compilers, which has all
- # kind of bad consequences, like using Py_ModuleInit4 instead of
- # Py_ModuleInit4_64, etc... So we add it here
- if get_build_architecture() == 'AMD64':
- if self.gcc_version < "4.0":
- self.set_executables(
- compiler='gcc -g -DDEBUG -DMS_WIN64 -mno-cygwin -O0 -Wall',
- compiler_so='gcc -g -DDEBUG -DMS_WIN64 -mno-cygwin -O0'
- ' -Wall -Wstrict-prototypes',
- linker_exe='gcc -g -mno-cygwin',
- linker_so='gcc -g -mno-cygwin -shared')
- else:
- # gcc-4 series releases do not support -mno-cygwin option
- self.set_executables(
- compiler='gcc -g -DDEBUG -DMS_WIN64 -O0 -Wall',
- compiler_so='gcc -g -DDEBUG -DMS_WIN64 -O0 -Wall -Wstrict-prototypes',
- linker_exe='gcc -g',
- linker_so='gcc -g -shared')
- else:
- if self.gcc_version <= "3.0.0":
- self.set_executables(
- compiler='gcc -mno-cygwin -O2 -w',
- compiler_so='gcc -mno-cygwin -mdll -O2 -w'
- ' -Wstrict-prototypes',
- linker_exe='g++ -mno-cygwin',
- linker_so='%s -mno-cygwin -mdll -static %s' %
- (self.linker, entry_point))
- elif self.gcc_version < "4.0":
- self.set_executables(
- compiler='gcc -mno-cygwin -O2 -Wall',
- compiler_so='gcc -mno-cygwin -O2 -Wall'
- ' -Wstrict-prototypes',
- linker_exe='g++ -mno-cygwin',
- linker_so='g++ -mno-cygwin -shared')
- else:
- # gcc-4 series releases do not support -mno-cygwin option
- self.set_executables(compiler='gcc -O2 -Wall',
- compiler_so='gcc -O2 -Wall -Wstrict-prototypes',
- linker_exe='g++ ',
- linker_so='g++ -shared')
- # added for python2.3 support
- # we can't pass it through set_executables because pre 2.2 would fail
- self.compiler_cxx = ['g++']
- # Maybe we should also append -mthreads, but then the finished dlls
- # need another dll (mingwm10.dll see Mingw32 docs) (-mthreads: Support
- # thread-safe exception handling on `Mingw32')
- # no additional libraries needed
- #self.dll_libraries=[]
- return
- # __init__ ()
- def link(self,
- target_desc,
- objects,
- output_filename,
- output_dir,
- libraries,
- library_dirs,
- runtime_library_dirs,
- export_symbols = None,
- debug=0,
- extra_preargs=None,
- extra_postargs=None,
- build_temp=None,
- target_lang=None):
- # Include the appropriate MSVC runtime library if Python was built
- # with MSVC >= 7.0 (MinGW standard is msvcrt)
- runtime_library = msvc_runtime_library()
- if runtime_library:
- if not libraries:
- libraries = []
- libraries.append(runtime_library)
- args = (self,
- target_desc,
- objects,
- output_filename,
- output_dir,
- libraries,
- library_dirs,
- runtime_library_dirs,
- None, #export_symbols, we do this in our def-file
- debug,
- extra_preargs,
- extra_postargs,
- build_temp,
- target_lang)
- if self.gcc_version < "3.0.0":
- func = distutils.cygwinccompiler.CygwinCCompiler.link
- else:
- func = UnixCCompiler.link
- func(*args[:func.__code__.co_argcount])
- return
- def object_filenames (self,
- source_filenames,
- strip_dir=0,
- output_dir=''):
- if output_dir is None: output_dir = ''
- obj_names = []
- for src_name in source_filenames:
- # use normcase to make sure '.rc' is really '.rc' and not '.RC'
- (base, ext) = os.path.splitext (os.path.normcase(src_name))
- # added these lines to strip off windows drive letters
- # without it, .o files are placed next to .c files
- # instead of the build directory
- drv, base = os.path.splitdrive(base)
- if drv:
- base = base[1:]
- if ext not in (self.src_extensions + ['.rc', '.res']):
- raise UnknownFileError(
- "unknown file type '%s' (from '%s')" % \
- (ext, src_name))
- if strip_dir:
- base = os.path.basename (base)
- if ext == '.res' or ext == '.rc':
- # these need to be compiled to object files
- obj_names.append (os.path.join (output_dir,
- base + ext + self.obj_extension))
- else:
- obj_names.append (os.path.join (output_dir,
- base + self.obj_extension))
- return obj_names
- # object_filenames ()
- def find_python_dll():
- # We can't do much here:
- # - find it in the virtualenv (sys.prefix)
- # - find it in python main dir (sys.base_prefix, if in a virtualenv)
- # - sys.real_prefix is main dir for virtualenvs in Python 2.7
- # - in system32,
- # - ortherwise (Sxs), I don't know how to get it.
- stems = [sys.prefix]
- if hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix:
- stems.append(sys.base_prefix)
- elif hasattr(sys, 'real_prefix') and sys.real_prefix != sys.prefix:
- stems.append(sys.real_prefix)
- sub_dirs = ['', 'lib', 'bin']
- # generate possible combinations of directory trees and sub-directories
- lib_dirs = []
- for stem in stems:
- for folder in sub_dirs:
- lib_dirs.append(os.path.join(stem, folder))
- # add system directory as well
- if 'SYSTEMROOT' in os.environ:
- lib_dirs.append(os.path.join(os.environ['SYSTEMROOT'], 'System32'))
- # search in the file system for possible candidates
- major_version, minor_version = tuple(sys.version_info[:2])
- patterns = ['python%d%d.dll']
- for pat in patterns:
- dllname = pat % (major_version, minor_version)
- print("Looking for %s" % dllname)
- for folder in lib_dirs:
- dll = os.path.join(folder, dllname)
- if os.path.exists(dll):
- return dll
- raise ValueError("%s not found in %s" % (dllname, lib_dirs))
- def dump_table(dll):
- st = subprocess.Popen(["objdump.exe", "-p", dll], stdout=subprocess.PIPE)
- return st.stdout.readlines()
- def generate_def(dll, dfile):
- """Given a dll file location, get all its exported symbols and dump them
- into the given def file.
- The .def file will be overwritten"""
- dump = dump_table(dll)
- for i in range(len(dump)):
- if _START.match(dump[i].decode()):
- break
- else:
- raise ValueError("Symbol table not found")
- syms = []
- for j in range(i+1, len(dump)):
- m = _TABLE.match(dump[j].decode())
- if m:
- syms.append((int(m.group(1).strip()), m.group(2)))
- else:
- break
- if len(syms) == 0:
- log.warn('No symbols found in %s' % dll)
- d = open(dfile, 'w')
- d.write('LIBRARY %s\n' % os.path.basename(dll))
- d.write(';CODE PRELOAD MOVEABLE DISCARDABLE\n')
- d.write(';DATA PRELOAD SINGLE\n')
- d.write('\nEXPORTS\n')
- for s in syms:
- #d.write('@%d %s\n' % (s[0], s[1]))
- d.write('%s\n' % s[1])
- d.close()
- def find_dll(dll_name):
- arch = {'AMD64' : 'amd64',
- 'Intel' : 'x86'}[get_build_architecture()]
- def _find_dll_in_winsxs(dll_name):
- # Walk through the WinSxS directory to find the dll.
- winsxs_path = os.path.join(os.environ.get('WINDIR', r'C:\WINDOWS'),
- 'winsxs')
- if not os.path.exists(winsxs_path):
- return None
- for root, dirs, files in os.walk(winsxs_path):
- if dll_name in files and arch in root:
- return os.path.join(root, dll_name)
- return None
- def _find_dll_in_path(dll_name):
- # First, look in the Python directory, then scan PATH for
- # the given dll name.
- for path in [sys.prefix] + os.environ['PATH'].split(';'):
- filepath = os.path.join(path, dll_name)
- if os.path.exists(filepath):
- return os.path.abspath(filepath)
- return _find_dll_in_winsxs(dll_name) or _find_dll_in_path(dll_name)
- def build_msvcr_library(debug=False):
- if os.name != 'nt':
- return False
- # If the version number is None, then we couldn't find the MSVC runtime at
- # all, because we are running on a Python distribution which is customed
- # compiled; trust that the compiler is the same as the one available to us
- # now, and that it is capable of linking with the correct runtime without
- # any extra options.
- msvcr_ver = msvc_runtime_major()
- if msvcr_ver is None:
- log.debug('Skip building import library: '
- 'Runtime is not compiled with MSVC')
- return False
- # Skip using a custom library for versions < MSVC 8.0
- if msvcr_ver < 80:
- log.debug('Skip building msvcr library:'
- ' custom functionality not present')
- return False
- msvcr_name = msvc_runtime_library()
- if debug:
- msvcr_name += 'd'
- # Skip if custom library already exists
- out_name = "lib%s.a" % msvcr_name
- out_file = os.path.join(sys.prefix, 'libs', out_name)
- if os.path.isfile(out_file):
- log.debug('Skip building msvcr library: "%s" exists' %
- (out_file,))
- return True
- # Find the msvcr dll
- msvcr_dll_name = msvcr_name + '.dll'
- dll_file = find_dll(msvcr_dll_name)
- if not dll_file:
- log.warn('Cannot build msvcr library: "%s" not found' %
- msvcr_dll_name)
- return False
- def_name = "lib%s.def" % msvcr_name
- def_file = os.path.join(sys.prefix, 'libs', def_name)
- log.info('Building msvcr library: "%s" (from %s)' \
- % (out_file, dll_file))
- # Generate a symbol definition file from the msvcr dll
- generate_def(dll_file, def_file)
- # Create a custom mingw library for the given symbol definitions
- cmd = ['dlltool', '-d', def_file, '-l', out_file]
- retcode = subprocess.call(cmd)
- # Clean up symbol definitions
- os.remove(def_file)
- return (not retcode)
- def build_import_library():
- if os.name != 'nt':
- return
- arch = get_build_architecture()
- if arch == 'AMD64':
- return _build_import_library_amd64()
- elif arch == 'Intel':
- return _build_import_library_x86()
- else:
- raise ValueError("Unhandled arch %s" % arch)
- def _check_for_import_lib():
- """Check if an import library for the Python runtime already exists."""
- major_version, minor_version = tuple(sys.version_info[:2])
- # patterns for the file name of the library itself
- patterns = ['libpython%d%d.a',
- 'libpython%d%d.dll.a',
- 'libpython%d.%d.dll.a']
- # directory trees that may contain the library
- stems = [sys.prefix]
- if hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix:
- stems.append(sys.base_prefix)
- elif hasattr(sys, 'real_prefix') and sys.real_prefix != sys.prefix:
- stems.append(sys.real_prefix)
- # possible subdirectories within those trees where it is placed
- sub_dirs = ['libs', 'lib']
- # generate a list of candidate locations
- candidates = []
- for pat in patterns:
- filename = pat % (major_version, minor_version)
- for stem_dir in stems:
- for folder in sub_dirs:
- candidates.append(os.path.join(stem_dir, folder, filename))
- # test the filesystem to see if we can find any of these
- for fullname in candidates:
- if os.path.isfile(fullname):
- # already exists, in location given
- return (True, fullname)
- # needs to be built, preferred location given first
- return (False, candidates[0])
- def _build_import_library_amd64():
- out_exists, out_file = _check_for_import_lib()
- if out_exists:
- log.debug('Skip building import library: "%s" exists', out_file)
- return
- # get the runtime dll for which we are building import library
- dll_file = find_python_dll()
- log.info('Building import library (arch=AMD64): "%s" (from %s)' %
- (out_file, dll_file))
- # generate symbol list from this library
- def_name = "python%d%d.def" % tuple(sys.version_info[:2])
- def_file = os.path.join(sys.prefix, 'libs', def_name)
- generate_def(dll_file, def_file)
- # generate import library from this symbol list
- cmd = ['dlltool', '-d', def_file, '-l', out_file]
- subprocess.Popen(cmd)
- def _build_import_library_x86():
- """ Build the import libraries for Mingw32-gcc on Windows
- """
- out_exists, out_file = _check_for_import_lib()
- if out_exists:
- log.debug('Skip building import library: "%s" exists', out_file)
- return
- lib_name = "python%d%d.lib" % tuple(sys.version_info[:2])
- lib_file = os.path.join(sys.prefix, 'libs', lib_name)
- if not os.path.isfile(lib_file):
- # didn't find library file in virtualenv, try base distribution, too,
- # and use that instead if found there. for Python 2.7 venvs, the base
- # directory is in attribute real_prefix instead of base_prefix.
- if hasattr(sys, 'base_prefix'):
- base_lib = os.path.join(sys.base_prefix, 'libs', lib_name)
- elif hasattr(sys, 'real_prefix'):
- base_lib = os.path.join(sys.real_prefix, 'libs', lib_name)
- else:
- base_lib = '' # os.path.isfile('') == False
- if os.path.isfile(base_lib):
- lib_file = base_lib
- else:
- log.warn('Cannot build import library: "%s" not found', lib_file)
- return
- log.info('Building import library (ARCH=x86): "%s"', out_file)
- from numpy.distutils import lib2def
- def_name = "python%d%d.def" % tuple(sys.version_info[:2])
- def_file = os.path.join(sys.prefix, 'libs', def_name)
- nm_cmd = '%s %s' % (lib2def.DEFAULT_NM, lib_file)
- nm_output = lib2def.getnm(nm_cmd)
- dlist, flist = lib2def.parse_nm(nm_output)
- lib2def.output_def(dlist, flist, lib2def.DEF_HEADER, open(def_file, 'w'))
- dll_name = find_python_dll ()
- args = (dll_name, def_file, out_file)
- cmd = 'dlltool --dllname "%s" --def "%s" --output-lib "%s"' % args
- status = os.system(cmd)
- # for now, fail silently
- if status:
- log.warn('Failed to build import library for gcc. Linking will fail.')
- return
- #=====================================
- # Dealing with Visual Studio MANIFESTS
- #=====================================
- # Functions to deal with visual studio manifests. Manifest are a mechanism to
- # enforce strong DLL versioning on windows, and has nothing to do with
- # distutils MANIFEST. manifests are XML files with version info, and used by
- # the OS loader; they are necessary when linking against a DLL not in the
- # system path; in particular, official python 2.6 binary is built against the
- # MS runtime 9 (the one from VS 2008), which is not available on most windows
- # systems; python 2.6 installer does install it in the Win SxS (Side by side)
- # directory, but this requires the manifest for this to work. This is a big
- # mess, thanks MS for a wonderful system.
- # XXX: ideally, we should use exactly the same version as used by python. I
- # submitted a patch to get this version, but it was only included for python
- # 2.6.1 and above. So for versions below, we use a "best guess".
- _MSVCRVER_TO_FULLVER = {}
- if sys.platform == 'win32':
- try:
- import msvcrt
- # I took one version in my SxS directory: no idea if it is the good
- # one, and we can't retrieve it from python
- _MSVCRVER_TO_FULLVER['80'] = "8.0.50727.42"
- _MSVCRVER_TO_FULLVER['90'] = "9.0.21022.8"
- # Value from msvcrt.CRT_ASSEMBLY_VERSION under Python 3.3.0
- # on Windows XP:
- _MSVCRVER_TO_FULLVER['100'] = "10.0.30319.460"
- if hasattr(msvcrt, "CRT_ASSEMBLY_VERSION"):
- major, minor, rest = msvcrt.CRT_ASSEMBLY_VERSION.split(".", 2)
- _MSVCRVER_TO_FULLVER[major + minor] = msvcrt.CRT_ASSEMBLY_VERSION
- del major, minor, rest
- except ImportError:
- # If we are here, means python was not built with MSVC. Not sure what
- # to do in that case: manifest building will fail, but it should not be
- # used in that case anyway
- log.warn('Cannot import msvcrt: using manifest will not be possible')
- def msvc_manifest_xml(maj, min):
- """Given a major and minor version of the MSVCR, returns the
- corresponding XML file."""
- try:
- fullver = _MSVCRVER_TO_FULLVER[str(maj * 10 + min)]
- except KeyError:
- raise ValueError("Version %d,%d of MSVCRT not supported yet" %
- (maj, min))
- # Don't be fooled, it looks like an XML, but it is not. In particular, it
- # should not have any space before starting, and its size should be
- # divisible by 4, most likely for alignment constraints when the xml is
- # embedded in the binary...
- # This template was copied directly from the python 2.6 binary (using
- # strings.exe from mingw on python.exe).
- template = """\
- <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
- <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
- <security>
- <requestedPrivileges>
- <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
- </requestedPrivileges>
- </security>
- </trustInfo>
- <dependency>
- <dependentAssembly>
- <assemblyIdentity type="win32" name="Microsoft.VC%(maj)d%(min)d.CRT" version="%(fullver)s" processorArchitecture="*" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
- </dependentAssembly>
- </dependency>
- </assembly>"""
- return template % {'fullver': fullver, 'maj': maj, 'min': min}
- def manifest_rc(name, type='dll'):
- """Return the rc file used to generate the res file which will be embedded
- as manifest for given manifest file name, of given type ('dll' or
- 'exe').
- Parameters
- ----------
- name : str
- name of the manifest file to embed
- type : str {'dll', 'exe'}
- type of the binary which will embed the manifest
- """
- if type == 'dll':
- rctype = 2
- elif type == 'exe':
- rctype = 1
- else:
- raise ValueError("Type %s not supported" % type)
- return """\
- #include "winuser.h"
- %d RT_MANIFEST %s""" % (rctype, name)
- def check_embedded_msvcr_match_linked(msver):
- """msver is the ms runtime version used for the MANIFEST."""
- # check msvcr major version are the same for linking and
- # embedding
- maj = msvc_runtime_major()
- if maj:
- if not maj == int(msver):
- raise ValueError(
- "Discrepancy between linked msvcr " \
- "(%d) and the one about to be embedded " \
- "(%d)" % (int(msver), maj))
- def configtest_name(config):
- base = os.path.basename(config._gen_temp_sourcefile("yo", [], "c"))
- return os.path.splitext(base)[0]
- def manifest_name(config):
- # Get configest name (including suffix)
- root = configtest_name(config)
- exext = config.compiler.exe_extension
- return root + exext + ".manifest"
- def rc_name(config):
- # Get configtest name (including suffix)
- root = configtest_name(config)
- return root + ".rc"
- def generate_manifest(config):
- msver = get_build_msvc_version()
- if msver is not None:
- if msver >= 8:
- check_embedded_msvcr_match_linked(msver)
- ma = int(msver)
- mi = int((msver - ma) * 10)
- # Write the manifest file
- manxml = msvc_manifest_xml(ma, mi)
- man = open(manifest_name(config), "w")
- config.temp_files.append(manifest_name(config))
- man.write(manxml)
- man.close()
|