1 # vi:filetype=python:expandtab:tabstop=4:shiftwidth=4
5 # This file is part of LyX, the document processor.
6 # Licence details can be found in the file COPYING.
9 # Full author contact details are available in file CREDITS.
11 # This file defines all the utility functions for the
12 # scons-based build system of lyx
15 import os, sys, re, shutil, glob
16 from SCons.Util import *
19 def getVerFromConfigure(path):
20 " get lyx version from the AC_INIT line of configure.ac "
22 config = open(os.path.join(path, 'configure.ac'))
24 print "Can not open configure.ac. "
26 # find a line like follows
27 # AC_INIT(LyX,1.4.4svn,[lyx-devel@lists.lyx.org],[lyx])
28 pat = re.compile('AC_INIT\([^,]+,([^,]+),')
29 for line in config.readlines():
31 (version,) = pat.match(line).groups()
32 return version.strip()
37 def writeToFile(filename, lines, append = False):
38 " utility function: write or append lines to filename "
39 # create directory if needed
40 dir = os.path.split(filename)[0]
41 if dir != '' and not os.path.isdir(dir):
44 file = open(filename, 'a')
46 file = open(filename, 'w')
51 def env_subst(target, source, env):
52 ''' subst variables in source by those in env, and output to target
53 source and target are scons File() objects
55 %key% (not key itself) is an indication of substitution
57 assert len(target) == 1
58 assert len(source) == 1
59 target_file = file(str(target[0]), "w")
60 source_file = file(str(source[0]), "r")
62 contents = source_file.read()
63 for k, v in env.items():
65 val = env.subst('$'+k)
66 # temporary fix for the \Resource backslash problem
67 val = val.replace('\\', '/')
68 # multi-line replacement
69 val = val.replace('\n',r'\\n\\\n')
70 contents = re.sub('@'+k+'@', val, contents)
73 target_file.write(contents + "\n")
75 #st = os.stat(str(source[0]))
76 #os.chmod(str(target[0]), stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
79 def env_nsis(source, target, env, for_signature):
80 ''' Get nsis command line '''
81 def quoteIfSpaced(str):
83 return '"' + str + '"'
86 ret = env['NSIS'] + " /V1 "
87 if env.has_key('NSISFLAGS'):
88 for flag in env['NSISFLAGS']:
91 if env.has_key('NSISDEFINES'):
92 for d in env['NSISDEFINES']:
94 if env['NSISDEFINES'][d]:
95 ret += '=' + quoteIfSpaced(env['NSISDEFINES'][d])
98 if '-bundle.exe' in str(target[0]):
99 ret += '/DSETUPTYPE_BUNDLE=1 '
101 ret += quoteIfSpaced(str(s))
105 def env_toc(target, source, env):
106 '''Generate target from source files'''
107 # this is very tricky because we need to use installed lyx2lyx with
108 # correct lyx2lyx_version.py
109 sys.path.append(env['LYX2LYX_DEST'])
110 sys.path.append(env.Dir('$TOP_SRCDIR/lib/doc').abspath)
113 doc_toc.build_toc(str(target[0]), [file.abspath for file in source])
116 def relativePath(env, path):
117 '''return relative path from top source dir'''
118 # full pathname of path
119 path1 = os.path.normpath(env.File(path).abspath).split(os.sep)
120 path2 = os.path.normpath(env.Dir('$TOP_SRCDIR').abspath).split(os.sep)
121 if path1[:len(path2)] != path2:
122 print "Path %s is not under top source directory" % path
123 return os.path.join(*path1[len(path2):])
126 def env_language_l10n(target, source, env):
127 '''Generate pot file from lib/language'''
128 input = open(env.File(source[0]).abspath)
129 output = open(env.File(target[0]).abspath, 'w')
130 for lineno, line in enumerate(input.readlines()):
133 items = line.split('"')
136 print 'Warning: this line looks strange:'
139 # afrikaans afrikaans "Afrikaans" false iso8859-15 af_ZA ""
144 print >> output, '#: %s:%d\nmsgid "%s"\nmsgstr ""\n' % (relativePath(env, source[0]), lineno+1, items[1])
149 def env_qt4_l10n(target, source, env):
150 '''Generate pot file from src/frontends/qt4/ui/*.ui'''
151 output = open(env.File(target[0]).abspath, 'w')
152 pat = re.compile(r'\s*<string>(.*)</string>')
153 prop = re.compile(r'\s*<property.*name.*=.*shortcut')
155 input = open(env.File(src).abspath)
157 for lineno, line in enumerate(input.readlines()):
158 # looking for a line with <string></string>
162 # skip the line after <property name=shortcut>
166 # get lines that match <string>...</string>
168 (string,) = pat.match(line).groups()
169 string = string.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', r'\"')
170 print >> output, '#: %s:%d\nmsgid "%s"\nmsgstr ""\n' % \
171 (relativePath(env, src), lineno+1, string)
176 def env_layouts_l10n(target, source, env):
177 '''Generate pot file from lib/layouts/*.layout and *.inc'''
178 output = open(env.File(target[0]).abspath, 'w')
179 Style = re.compile(r'^Style\s+(.*)')
180 # include ???LabelString???, but exclude comment lines
181 LabelString = re.compile(r'^[^#]*LabelString\S*\s+(.*)')
182 GuiName = re.compile(r'\s*GuiName\s+(.*)')
183 ListName = re.compile(r'\s*ListName\s+(.*)')
185 input = open(env.File(src).abspath)
186 for lineno, line in enumerate(input.readlines()):
187 # get lines that match <string>...</string>
188 if Style.match(line):
189 (string,) = Style.match(line).groups()
190 string = string.replace('_', ' ')
191 elif LabelString.match(line):
192 (string,) = LabelString.match(line).groups()
193 elif GuiName.match(line):
194 (string,) = GuiName.match(line).groups()
195 elif ListName.match(line):
196 (string,) = ListName.match(line).groups()
199 string = string.replace('\\', '\\\\').replace('"', '')
201 print >> output, '#: %s:%d\nmsgid "%s"\nmsgstr ""\n' % \
202 (relativePath(env, src), lineno+1, string)
207 def createResFromIcon(env, icon_file, rc_file):
208 ''' create a rc file with icon, and return res file (windows only) '''
210 rc_name = env.File(rc_file).abspath
211 dir = os.path.split(rc_name)[0]
212 if not os.path.isdir(dir):
214 rc = open(rc_name, 'w')
215 print >> rc, 'IDI_ICON1 ICON DISCARDABLE "%s"' % \
216 os.path.join(env.Dir('$TOP_SRCDIR').abspath, 'development', 'win32',
217 'packaging', 'icons', icon_file).replace('\\', '\\\\')
219 return env.RES(rc_name)
228 def checkPkgConfig(conf, version):
229 ''' Return false if pkg_config does not exist, or is too old '''
230 conf.Message('Checking for pkg-config...')
231 ret = conf.TryAction('pkg-config --atleast-pkgconfig-version=%s' % version)[0]
236 def checkPackage(conf, pkg):
237 ''' check if pkg is under the control of conf '''
238 conf.Message('Checking for package %s...' % pkg)
239 ret = conf.TryAction("pkg-config --print-errors --exists %s" % pkg)[0]
244 def checkMkdirOneArg(conf):
245 check_mkdir_one_arg_source = """
246 #include <sys/stat.h>
252 conf.Message('Checking for the number of args for mkdir... ')
253 ret = conf.TryLink(check_mkdir_one_arg_source, '.c') or \
254 conf.TryLink('#include <unistd.h>' + check_mkdir_one_arg_source, '.c') or \
255 conf.TryLink('#include <direct.h>' + check_mkdir_one_arg_source, '.c')
263 def checkCXXGlobalCstd(conf):
264 ''' Checking the use of std::tolower or tolower '''
265 check_global_cstd_source = '''
273 conf.Message('Checking for the use of global cstd... ')
274 ret = conf.TryLink(check_global_cstd_source, '.c')
279 def checkSelectArgType(conf):
280 ''' Adapted from autoconf '''
281 conf.Message('Checking for arg types for select... ')
282 for arg234 in ['fd_set *', 'int *', 'void *']:
283 for arg1 in ['int', 'size_t', 'unsigned long', 'unsigned']:
284 for arg5 in ['struct timeval *', 'const struct timeval *']:
285 check_select_source = '''
286 #if HAVE_SYS_SELECT_H
287 # include <sys/select.h>
289 #if HAVE_SYS_SOCKET_H
290 # include <sys/socket.h>
292 extern int select (%s, %s, %s, %s, %s);
297 ''' % (arg1, arg234, arg234, arg234, arg5)
298 ret = conf.TryLink(check_select_source, '.c')
301 return (arg1, arg234, arg5)
302 conf.Result('no (use default)')
303 return ('int', 'int *', 'struct timeval *')
306 def checkBoostLibraries(conf, libs, lib_paths, inc_paths, versions, isDebug):
307 ''' look for boost libraries
309 lib_paths: try these paths for boost libraries
310 inc_paths: try these paths for boost headers
311 versions: supported boost versions
312 isDebug: if true, use debug libraries
314 conf.Message('Checking for boost library %s... ' % ', '.join(libs))
315 libprefix = conf.env['LIBPREFIX']
316 libsuffix = '(%s|%s)' % (conf.env['LIBSUFFIX'], conf.env['SHLIBSUFFIX'])
322 for path in lib_paths:
323 conf.Log("Looking into %s\n" % path)
325 # get all the libs, then filter for the right library
326 files = glob.glob(os.path.join(path, '%sboost_%s-*.*' % (libprefix, lib)))
327 # check things like libboost_iostreams-gcc-mt-d-1_33_1.a
329 conf.Log("Find boost libraries: %s\n" % files)
330 # runtime code includes s,g,y,d,p,n, where we should look for
331 # d,g,y for debug, s,p,n for release
335 lib_files += filter(lambda x: re.search('%sboost_%s-\w+-mt-[^spn]+-%s%s' % (libprefix, lib, ver, libsuffix), x), files)
338 lib_files += filter(lambda x: re.search('%sboost_%s-\w+-mt-([^dgy]+-)*%s%s' % (libprefix, lib, ver, libsuffix), x), files)
339 if len(lib_files) == 0:
340 # use alternative libraries
342 lib_files += filter(lambda x: re.search('%sboost_%s-[\w-]+%s%s' % (libprefix, lib, ver, libsuffix), x), files)
343 if len(lib_files) > 0:
344 # get xxx-gcc-1_33_1 from /usr/local/lib/libboost_xxx-gcc-1_33_1.a
345 name = lib_files[0].split(os.sep)[-1][len(libprefix):]
346 lib_names.append(name.split('.')[0])
347 conf.Log("Qualified libraries: %s\n" % lib_names)
349 conf.Log("No qualified library is found.\n")
351 if len(lib_names) == len(libs):
356 if len(lib_names) == 0:
357 conf.Log("No boost library is found\n")
359 conf.Log("Found boost libraries: %s\n" % lib_names)
361 return (None, None, None)
362 # check version number in boost/version.hpp
363 def isValidBoostDir(dir):
364 version_file = os.path.join(dir, 'boost', 'version.hpp')
365 if not os.path.isfile(version_file):
367 version_file_content = open(version_file).read()
368 version_strings = ['#define BOOST_LIB_VERSION "%s"' % ver for ver in versions]
369 return True in [x in version_file_content for x in version_strings]
370 # check for boost header file
371 for path in inc_paths:
372 conf.Log("Checking for inc path: %s\n" % path)
373 if isValidBoostDir(path):
376 else: # check path/boost_1_xx_x/boost
377 dirs = glob.glob(os.path.join(path, 'boost-*'))
378 if len(dirs) > 0 and isValidBoostDir(dirs[0]):
379 conf.Log("Checing for sub directory: %s\n" % dirs[0])
385 conf.Log('Using boost libraries %s\n' % (', '.join(lib_names)))
386 return (lib_names, lib_path, inc_path)
389 return (None, None, None)
392 def checkCommand(conf, cmd):
393 ''' check the existence of a command
394 return full path to the command, or none
396 conf.Message('Checking for command %s...' % cmd)
398 conf.Result(res is not None)
403 ''' check the existence of nsis compiler, return the fullpath '''
404 conf.Message('Checking for nsis compiler...')
407 # If we can read the registry, get the NSIS command from it
409 k = RegOpenKeyEx(hkey_mod.HKEY_LOCAL_MACHINE,
411 val, tok = RegQueryValueEx(k,None)
412 ret = val + os.path.sep + 'makensis.exe'
413 if os.path.isfile(ret):
414 res = '"' + ret + '"'
418 pass # Couldn't find the key, just act like we can't read the registry
419 # Hope it's on the path
421 res = WhereIs('makensis.exe')
422 conf.Result(res is not None)
426 def checkLC_MESSAGES(conf):
427 ''' check the definition of LC_MESSAGES '''
428 check_LC_MESSAGES = '''
435 conf.Message('Checking for LC_MESSAGES in locale.h... ')
436 ret = conf.TryLink(check_LC_MESSAGES, '.c')
441 def checkIconvConst(conf):
442 ''' check the declaration of iconv '''
443 check_iconv_const = '''
445 // this declaration will fail when there already exists a non const char**
446 // version which returns size_t
447 double iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
452 conf.Message('Checking if the declaration of iconv needs const... ')
453 ret = conf.TryLink(check_iconv_const, '.c')
458 def checkSizeOfWChar(conf):
459 ''' check the size of wchar '''
460 check_sizeof_wchar = '''
461 int i[ ( sizeof(wchar_t)==%d ? 1 : -1 ) ];
467 conf.Message('Checking the size of wchar_t... ')
468 if conf.TryLink(check_sizeof_wchar % 2, '.cpp'):
470 elif conf.TryLink(check_sizeof_wchar % 4, '.cpp'):
474 conf.Result(str(ret))
478 def createConfigFile(conf, config_file,
479 config_pre = '', config_post = '',
480 headers = [], functions = [], types = [], libs = [],
481 custom_tests = [], extra_items = []):
482 ''' create a configuration file, with options
483 config_file: which file to create
484 config_pre: first part of the config file
485 config_post: last part of the config file
486 headers: header files to check, in the form of a list of
487 ('file', 'HAVE_FILE', 'c'/'c++')
488 functions: functions to check, in the form of a list of
489 ('func', 'HAVE_func', 'include lines'/None)
490 types: types to check, in the form of a list of
491 ('type', 'HAVE_TYPE', 'includelines'/None)
492 libs: libraries to check, in the form of a list of
493 ('lib', 'HAVE_LIB', 'LIB_NAME'). HAVE_LIB will be set if 'lib' exists,
494 or any of the libs exists if 'lib' is a list of libs.
495 Optionally, user can provide another key LIB_NAME, that will
496 be set to the detected lib (or None otherwise).
497 custom_tests: extra tests to perform, in the form of a list of
498 (test (True/False), 'key', 'desc', 'true config line', 'false config line')
499 If the last two are ignored, '#define key 1' '/*#undef key */'
501 extra_items: extra configuration lines, in the form of a list of
502 ('config', 'description')
504 The result of each test, as a dictioanry of
505 res['XXX'] = True/False
506 XXX are keys defined in each argument.
508 cont = config_pre + '\n'
510 # add to this string, in appropriate format
511 def configString(lines, desc=''):
513 if lines.strip() != '':
515 text += '/* ' + desc + ' */\n'
516 text += lines + '\n\n'
520 for header in headers:
521 description = "Define to 1 if you have the <%s> header file." % header[0]
522 if (header[2] == 'c' and conf.CheckCHeader(header[0])) or \
523 (header[2] == 'cxx' and conf.CheckCXXHeader(header[0])):
524 result[header[1]] = 1
525 cont += configString('#define %s 1' % header[1], desc = description)
527 result[header[1]] = 0
528 cont += configString('/* #undef %s */' % header[1], desc = description)
530 for func in functions:
531 description = "Define to 1 if you have the `%s' function." % func[0]
532 if conf.CheckFunc(func[0], header=func[2]):
534 cont += configString('#define %s 1' % func[1], desc = description)
537 cont += configString('/* #undef %s */' % func[1], desc = description)
540 description = "Define to 1 if you have the `%s' type." % t[0]
541 if conf.CheckType(t[0], includes=t[2]):
543 cont += configString('#define %s 1' % t[1], desc = description)
546 cont += configString('/* #undef %s */' % t[1], desc = description)
549 description = "Define to 1 if you have the `%s' library (-l%s)." % (lib[0], lib[0])
550 if type(lib[0]) is type(''):
554 # check if any of the lib exists
556 # if user want the name of the lib detected
558 result[lib[2]] = None
560 if conf.CheckLib(ll):
564 cont += configString('#define %s 1' % lib[1], desc = description)
567 if not result[lib[1]]:
568 cont += configString('/* #undef %s */' % lib[1], desc = description)
570 for test in custom_tests:
574 cont += configString('#define %s 1' % test[1], desc = test[2])
576 cont += configString(test[3], desc = test[2])
580 cont += configString('/* #undef %s */' % test[1], desc = test[2])
582 cont += configString(test[4], desc = test[2])
583 # extra items (no key is returned)
584 for item in extra_items:
585 cont += configString(item[0], desc = item[1])
587 cont += '\n' + config_post + '\n'
589 writeToFile(config_file, cont)
593 def installCygwinLDScript(path):
594 ''' Install i386pe.x-no-rdata '''
595 ld_script = os.path.join(path, 'i386pe.x-no-rdata')
596 script = open(ld_script, 'w')
597 script.write('''/* specific linker script avoiding .rdata sections, for normal executables
599 http://www.cygwin.com/ml/cygwin/2004-09/msg01101.html
600 http://www.cygwin.com/ml/cygwin-apps/2004-09/msg00309.html
602 OUTPUT_FORMAT(pei-i386)
603 SEARCH_DIR("/usr/i686-pc-cygwin/lib"); SEARCH_DIR("/usr/lib"); SEARCH_DIR("/usr/lib/w32api");
604 ENTRY(_mainCRTStartup)
607 .text __image_base__ + __section_alignment__ :
614 ___CTOR_LIST__ = .; __CTOR_LIST__ = . ;
615 LONG (-1);*(.ctors); *(.ctor); *(SORT(.ctors.*)); LONG (0);
616 ___DTOR_LIST__ = .; __DTOR_LIST__ = . ;
617 LONG (-1); *(.dtors); *(.dtor); *(SORT(.dtors.*)); LONG (0);
619 /* ??? Why is .gcc_exc here? */
624 /* The Cygwin32 library uses a section to avoid copying certain data
625 on fork. This used to be named ".data". The linker used
626 to include this between __data_start__ and __data_end__, but that
627 breaks building the cygwin32 dll. Instead, we name the section
628 ".data_cygwin_nocopy" and explictly include it after __data_end__. */
629 .data BLOCK(__section_alignment__) :
638 ___RUNTIME_PSEUDO_RELOC_LIST__ = .;
639 __RUNTIME_PSEUDO_RELOC_LIST__ = .;
640 *(.rdata_runtime_pseudo_reloc)
641 ___RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
642 __RUNTIME_PSEUDO_RELOC_LIST_END__ = .;
644 *(.data_cygwin_nocopy)
646 .rdata BLOCK(__section_alignment__) :
649 .pdata BLOCK(__section_alignment__) :
653 .bss BLOCK(__section_alignment__) :
660 .edata BLOCK(__section_alignment__) :
671 .idata BLOCK(__section_alignment__) :
673 /* This cannot currently be handled with grouped sections.
674 See pe.em:sort_sections. */
677 /* These zeroes mark the end of the import list. */
678 LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);
684 .CRT BLOCK(__section_alignment__) :
686 ___crt_xc_start__ = . ;
687 *(SORT(.CRT$XC*)) /* C initialization */
688 ___crt_xc_end__ = . ;
689 ___crt_xi_start__ = . ;
690 *(SORT(.CRT$XI*)) /* C++ initialization */
691 ___crt_xi_end__ = . ;
692 ___crt_xl_start__ = . ;
693 *(SORT(.CRT$XL*)) /* TLS callbacks */
694 /* ___crt_xl_end__ is defined in the TLS Directory support code */
695 ___crt_xp_start__ = . ;
696 *(SORT(.CRT$XP*)) /* Pre-termination */
697 ___crt_xp_end__ = . ;
698 ___crt_xt_start__ = . ;
699 *(SORT(.CRT$XT*)) /* Termination */
700 ___crt_xt_end__ = . ;
702 .tls BLOCK(__section_alignment__) :
710 .endjunk BLOCK(__section_alignment__) :
712 /* end is deprecated, don't use it */
717 .rsrc BLOCK(__section_alignment__) :
722 .reloc BLOCK(__section_alignment__) :
726 .stab BLOCK(__section_alignment__) (NOLOAD) :
730 .stabstr BLOCK(__section_alignment__) (NOLOAD) :
734 /* DWARF debug sections.
735 Symbols in the DWARF debugging sections are relative to the beginning
736 of the section. Unlike other targets that fake this by putting the
737 section VMA at 0, the PE format will not allow it. */
738 /* DWARF 1.1 and DWARF 2. */
739 .debug_aranges BLOCK(__section_alignment__) (NOLOAD) :
743 .debug_pubnames BLOCK(__section_alignment__) (NOLOAD) :
748 .debug_info BLOCK(__section_alignment__) (NOLOAD) :
750 *(.debug_info) *(.gnu.linkonce.wi.*)
752 .debug_abbrev BLOCK(__section_alignment__) (NOLOAD) :
756 .debug_line BLOCK(__section_alignment__) (NOLOAD) :
760 .debug_frame BLOCK(__section_alignment__) (NOLOAD) :
764 .debug_str BLOCK(__section_alignment__) (NOLOAD) :
768 .debug_loc BLOCK(__section_alignment__) (NOLOAD) :
772 .debug_macinfo BLOCK(__section_alignment__) (NOLOAD) :
776 /* SGI/MIPS DWARF 2 extensions. */
777 .debug_weaknames BLOCK(__section_alignment__) (NOLOAD) :
781 .debug_funcnames BLOCK(__section_alignment__) (NOLOAD) :
785 .debug_typenames BLOCK(__section_alignment__) (NOLOAD) :
789 .debug_varnames BLOCK(__section_alignment__) (NOLOAD) :
794 .debug_ranges BLOCK(__section_alignment__) (NOLOAD) :
804 def installCygwinPostinstallScript(path):
805 ''' Install lyx.sh '''
806 postinstall_script = os.path.join(path, 'lyx.sh')
807 script = open(postinstall_script, 'w')
808 script.write(r'''#!/bin/sh
810 # Add /usr/share/lyx/fonts to /etc/fonts/local.conf
811 # if it is not already there.
812 if [ -f /etc/fonts/local.conf ]; then
813 grep -q /usr/share/lyx/fonts /etc/fonts/local.conf
814 if [ $? -ne 0 ]; then
815 sed 's/^<\/fontconfig>/<dir>\/usr\/share\/lyx\/fonts<\/dir>\n<\/fontconfig>/' /etc/fonts/local.conf > /etc/fonts/local.conf.tmp
816 mv -f /etc/fonts/local.conf.tmp /etc/fonts/local.conf
817 fc-cache /usr/share/lyx/fonts
822 return(postinstall_script)
826 # these will be used under win32
832 # does not matter if it fails on other systems
837 def __init__(self, env, logfile, longarg, info):
838 # save the spawn system
840 self.logfile = logfile
841 # clear the logfile (it may not exist)
843 # this will overwrite existing content.
844 writeToFile(logfile, info, append=False)
846 self.longarg = longarg
847 # get hold of the old spawn? (necessary?)
848 self._spawn = env['SPAWN']
851 def spawn(self, sh, escape, cmd, args, spawnenv):
853 newargs = ' '.join(map(escape, args[1:]))
854 cmdline = cmd + " " + newargs
856 # if log is not empty, write to it
857 if self.logfile != '':
858 # this tend to be slow (?) but ensure correct output
859 # Note that cmdline may be long so I do not escape it
861 # since this is not an essential operation, proceed if things go wrong here.
862 writeToFile(self.logfile, cmd + " " + ' '.join(args[1:]) + '\n', append=True)
864 print "Warning: can not write to log file ", self.logfile
866 # if the command is not too long, use the old
867 if not self.longarg or len(cmdline) < 8000:
868 exit_code = self._spawn(sh, escape, cmd, args, spawnenv)
870 sAttrs = win32security.SECURITY_ATTRIBUTES()
871 StartupInfo = win32process.STARTUPINFO()
873 spawnenv[var] = spawnenv[var].encode('ascii', 'replace')
874 # check for any special operating system commands
877 win32file.DeleteFile(arg)
880 # otherwise execute the command.
881 hProcess, hThread, dwPid, dwTid = win32process.CreateProcess(None, cmdline, None, None, 1, 0, spawnenv, None, StartupInfo)
882 win32event.WaitForSingleObject(hProcess, win32event.INFINITE)
883 exit_code = win32process.GetExitCodeProcess(hProcess)
884 win32file.CloseHandle(hProcess);
885 win32file.CloseHandle(hThread);
889 def setLoggedSpawn(env, logfile = '', longarg=False, info=''):
890 ''' This function modify env and allow logging of
891 commands to a logfile. If the argument is too long
892 a win32 spawn will be used instead of the system one
895 # create a new spwn object
896 ls = loggedSpawn(env, logfile, longarg, info)
897 # replace the old SPAWN by the new function
898 env['SPAWN'] = ls.spawn