def write_dmg(self, output): # pkg-dmg expects a folder corresponding to the top of the image, so # we need to move our Reinteract.app folder down a level sourcefolder = join(self.tempdir, "Reinteract-tmp") os.makedirs(sourcefolder) shutil.move(self.treedir, join(sourcefolder, "Reinteract.app")) command = ["pkg-dmg"] command.extend(("--source", sourcefolder)) command.extend(("--target", output)) # This exact Volume Name is important, since the .DS_Store file contains # a reference to /Volumes/Reinteract/.background/reinteract-background.png # I don't know if a relative path is possible. command.extend(("--volname", "Reinteract")) command.extend(("--mkdir", ".background")) command.extend( ( "--copy", join(self.topdir, "tools/build_bundle/reinteract-dmg-background.png") + ":" + ".background/reinteract-background.png", ) ) command.extend(("--copy", join(self.topdir, "tools/build_bundle/reinteract.dsstore") + ":" + ".DS_Store")) command.extend(("--symlink", "/Applications:Applications")) check_call(command)
def add_file(self, source, directory, **attributes): # We override to add special handling for binary files if ((source.endswith(".so") or source.endswith(".dylib")) and source.startswith(self.jhbuild_install_dir)): relative_path = source[len(self.jhbuild_install_dir) + 1:] # We find a correspoding binary for each arch and join them # together with the lipo command fat_tmp = join(self.tempdir, basename(source)) lipo_command = ['lipo', '-create', '-output', fat_tmp] for arch, install_dir in self.arches.iteritems(): arch_source = join(install_dir, relative_path) arch_tmp = join(self.tempdir, arch + '-' + basename(source)) shutil.copy(arch_source, arch_tmp) # Before running lipo on the library, rewrite dependency # paths in it to be relative to the executable self.repoint_libraries(arch_tmp, install_dir) lipo_command.extend(('-arch', arch, arch_tmp)) check_call(lipo_command) Builder.add_file(self, fat_tmp, directory, **attributes) else: Builder.add_file(self, source, directory, **attributes)
def write_dmg(self, output): # pkg-dmg expects a folder corresponding to the top of the image, so # we need to move our Reinteract.app folder down a level sourcefolder = join(self.tempdir, "Reinteract-tmp") os.makedirs(sourcefolder) shutil.move(self.treedir, join(sourcefolder, "Reinteract.app")) command = ['pkg-dmg'] command.extend(('--source', sourcefolder)) command.extend(('--target', output)) # This exact Volume Name is important, since the .DS_Store file contains # a reference to /Volumes/Reinteract/.background/reinteract-background.png # I don't know if a relative path is possible. command.extend(('--volname', 'Reinteract')) command.extend(('--mkdir', '.background')) command.extend( ('--copy', join(self.topdir, 'tools/build_bundle/reinteract-dmg-background.png') + ':' + ".background/reinteract-background.png")) command.extend( ('--copy', join(self.topdir, 'tools/build_bundle/reinteract.dsstore') + ':' + ".DS_Store")) command.extend(('--symlink', '/Applications:Applications')) check_call(command)
def compile_wrapper_python26(self): # For Python-2.6 we build with Visual Studio; trying to get a # MingW32-built .exe to load the extensions we bundle for Python-2.6 # seems very difficult. We hope that our version of Visual Studio # was close enough to the version that Python is built with so # that if Python runs, we run. # # We use some distutils internals to locate the Visual Studio # command line tools # from distutils.msvc9compiler import MSVCCompiler compiler = MSVCCompiler() # This looks for the tools and then adds them to os.environ['Path'] compiler.initialize() python_topdir = os.path.dirname(os.path.dirname(shutil.__file__)) python_include = os.path.join(python_topdir, "include") python_lib = os.path.join(python_topdir, "libs") wrapper_c = os.path.join(self.topdir, "tools", "build_msi", "wrapper.c") wrapper_rc = os.path.join(self.tempdir, "wrapper.rc") f = open(wrapper_rc, "w") f.write("""LANGUAGE 0, 0 100 ICON %s """ % os.path.join(self.treedir, "Reinteract.ico")) f.close() # We can use distutils to do the basic compilation objects = compiler.compile([wrapper_c, wrapper_rc], output_dir=self.tempdir, include_dirs=[python_include]) # But have to do the linking a bit more manually since distutils # doesn't know how to handle creating .exe files wrapper = os.path.join(self.tempdir, "Reinteract.exe") manifest = os.path.join(self.tempdir, "Reinteract.exe.manifest") extra_libs = [ 'user32.lib', # For MessageBox ] check_call([ compiler.linker, "/MANIFEST", "/MANIFESTFILE:" + manifest, "/LIBPATH:" + python_lib, "/OUT:" + wrapper ] + objects + extra_libs) # Embed the manifest into the executable check_call([ 'mt.exe', '-manifest', manifest, '-outputresource:' + wrapper + ';1' ]) self.add_file(wrapper, 'bin', feature='core')
def compile_wrapper_python26(self): # For Python-2.6 we build with Visual Studio; trying to get a # MingW32-built .exe to load the extensions we bundle for Python-2.6 # seems very difficult. We hope that our version of Visual Studio # was close enough to the version that Python is built with so # that if Python runs, we run. # # We use some distutils internals to locate the Visual Studio # command line tools # from distutils.msvc9compiler import MSVCCompiler compiler = MSVCCompiler() # This looks for the tools and then adds them to os.environ['Path'] compiler.initialize() python_topdir = os.path.dirname(os.path.dirname(shutil.__file__)) python_include = os.path.join(python_topdir, "include") python_lib = os.path.join(python_topdir, "libs") wrapper_c = os.path.join(self.topdir, "tools", "build_msi", "wrapper.c") wrapper_rc = os.path.join(self.tempdir, "wrapper.rc") f = open(wrapper_rc, "w") f.write("""LANGUAGE 0, 0 100 ICON %s """ % os.path.join(self.treedir, "Reinteract.ico")) f.close() # We can use distutils to do the basic compilation objects = compiler.compile([wrapper_c, wrapper_rc], output_dir=self.tempdir, include_dirs=[python_include]) # But have to do the linking a bit more manually since distutils # doesn't know how to handle creating .exe files wrapper = os.path.join(self.tempdir, "Reinteract.exe") manifest = os.path.join(self.tempdir, "Reinteract.exe.manifest") extra_libs = [ 'user32.lib', # For MessageBox ] check_call([compiler.linker, "/MANIFEST", "/MANIFESTFILE:" + manifest, "/LIBPATH:" + python_lib, "/OUT:" + wrapper] + objects + extra_libs) # Embed the manifest into the executable check_call(['mt.exe', '-manifest', manifest, '-outputresource:' + wrapper + ';1']) self.add_file(wrapper, 'bin', feature='core')
def command_build(self): script_common.command_build(self) # Set up tools. if not isinstance(self.ci, ci_cli) and toolset_info[self.toolset]['command']: os.environ['PATH'] = os.pathsep.join([ os.path.dirname(toolset_info[self.toolset]['command']), os.environ['PATH']]) # Bootstrap Boost Build engine. os.chdir(self.b2_dir) if sys.platform == 'win32': utils.check_call(".\\bootstrap.bat") else: utils.check_call("./bootstrap.sh") os.environ['PATH'] = os.pathsep.join([self.b2_dir, os.environ['PATH']]) os.environ['BOOST_BUILD_PATH'] = self.b2_dir # Run the limited tests. print("--- Testing %s ---"%(self.repo_dir)) os.chdir(os.path.join(self.repo_dir,'test')) toolset_to_test = "" if self.toolset: if not isinstance(self.ci, ci_cli): toolset_to_test = toolset_info[self.toolset]['toolset'] else: toolset_to_test = self.toolset self.b2( '-d1', '-p0', 'preserve-test-targets=off', '--dump-tests', '--verbose-test', '--build-dir=%s'%(self.build_dir), '--out-xml=%s'%(os.path.join(self.build_dir,'regression.xml')), '' if not toolset_to_test else 'toolset=%s'%(toolset_to_test), '' if not self.address_model else 'address-model=%s'%(self.address_model), 'variant=%s'%(self.variant), self.target ) # Generate a readable test report. import build_log log_main = build_log.Main([ '--output=console', os.path.join(self.build_dir,'regression.xml')]) # And exit with an error if the report contains failures. # This lets the CI notice the error and report a failed build. # And hence trigger the failure machinery, like sending emails. if log_main.failed: self.ci.finish(-1)
def command_before_cache(self): script_common.command_before_cache(self) os.chdir(self.boost_root) utils.check_call("git","clean","-dfqx") utils.check_call("git","submodule","--quiet","foreach","git","clean","-dfqx") utils.check_call("git","status","-bs") utils.check_call("git","submodule","foreach","git","status","-bs")
def command_before_build(self): script_common.command_before_build(self) # Clone boost super-project. if self.repo != 'boost': utils.git_clone('boost', self.branch, cwd=self.ci.work_dir, no_submodules=True) utils.check_call("git", "submodule", "update", "--quiet", "--init", "tools/build") utils.check_call("git", "submodule", "update", "--quiet", "--init", "tools/boostdep") # The global jamfiles require config as they trigger build config checks. utils.check_call("git", "submodule", "update", "--quiet", "--init", "libs/config") # Find the path for the submodule of the repo we are testing. if self.repo != 'boost': self.repo_dir = os.path.join(self.boost_root, self.repo_path) if self.repo != 'boost': # Copy in the existing library tree checkout. shutil.rmtree(self.repo_path) shutil.copytree(self.root_dir, self.repo_path) # Fetch the dependencies for the library we are testing. if self.repo != 'boost': os.chdir(self.boost_root) utils.check_call(sys.executable, 'tools/boostdep/depinst/depinst.py', self.repo) # Create config file for toolset. if not isinstance(self.ci, ci_cli): cxxflags = None if self.cxxflags: cxxflags = self.cxxflags.split() cxxflags = " <cxxflags>".join(cxxflags) utils.make_file( os.path.join(self.boost_root, 'project-config.jam'), """ using %(toolset)s : %(version)s : %(command)s : %(cxxflags)s ; using python : %(pyversion)s : "%(python)s" ; """ % { 'toolset': toolset_info[self.toolset]['toolset'], 'version': toolset_info[self.toolset]['version'], 'command': toolset_info[self.toolset]['command'], 'cxxflags': "<cxxflags>" + cxxflags if cxxflags else "", 'pyversion': "%s.%s" % (sys.version_info[0], sys.version_info[1]), 'python': sys.executable.replace("\\", "\\\\") })
def repoint_libraries(self, binary, install_dir): # Rewrite paths to shared libaries inside binary to be relative to # the executable instead of pointing to absolute paths in install_dir otool = subprocess.Popen(args=["otool", "-L", binary], stdout=subprocess.PIPE) first = True for line in otool.stdout: # First line is the identification name of the library, subsequent lines are indented if not line.startswith("\t"): continue path = line.strip().split()[0] if not path.startswith(install_dir): continue relative_path = path[len(install_dir) + 1 :] check_call(["install_name_tool", "-change", path, "@executable_path/../Resources/" + relative_path, binary]) otool.wait()
def compile_wrapper_python25(self): # On Python-2.5 we build with MingW32; this avoids creating # a dependency on the Visual Studio runtime. # python_topdir = os.path.dirname(os.path.dirname(shutil.__file__)) python_include = os.path.join(python_topdir, "include") python_lib = os.path.join(python_topdir, "libs") wrapper_c = os.path.join(self.topdir, "tools", "build_msi", "wrapper.c") wrapper_o = os.path.join(self.tempdir, "wrapper.o") check_call(['gcc', '-o', wrapper_o, '-c', '-O2', '-Wall', '-I', python_include, wrapper_c]) wrapper_rc = os.path.join(self.tempdir, "wrapper.rc") wrapper_res_o = os.path.join(self.tempdir, "wrapper.res.o") f = open(wrapper_rc, "w") f.write("""LANGUAGE 0, 0 100 ICON %s """ % os.path.join(self.treedir, "Reinteract.ico")) f.close() check_call(['windres', '-O', 'COFF', '-o', wrapper_res_o, wrapper_rc]) wrapper = os.path.join(self.tempdir, "Reinteract.exe") lpython = "-lpython%d%d" % (sys.version_info[0], sys.version_info[1]) check_call(['gcc', '-mwindows', '-o', wrapper, '-L', python_lib, wrapper_o, wrapper_res_o, lpython]) self.add_file(wrapper, 'bin', feature='core')
def compile_wrapper_python25(self): # On Python-2.5 we build with MingW32; this avoids creating # a dependency on the Visual Studio runtime. # python_topdir = os.path.dirname(os.path.dirname(shutil.__file__)) python_include = os.path.join(python_topdir, "include") python_lib = os.path.join(python_topdir, "libs") wrapper_c = os.path.join(self.topdir, "tools", "build_msi", "wrapper.c") wrapper_o = os.path.join(self.tempdir, "wrapper.o") check_call([ 'gcc', '-o', wrapper_o, '-c', '-O2', '-Wall', '-I', python_include, wrapper_c ]) wrapper_rc = os.path.join(self.tempdir, "wrapper.rc") wrapper_res_o = os.path.join(self.tempdir, "wrapper.res.o") f = open(wrapper_rc, "w") f.write("""LANGUAGE 0, 0 100 ICON %s """ % os.path.join(self.treedir, "Reinteract.ico")) f.close() check_call(['windres', '-O', 'COFF', '-o', wrapper_res_o, wrapper_rc]) wrapper = os.path.join(self.tempdir, "Reinteract.exe") lpython = "-lpython%d%d" % (sys.version_info[0], sys.version_info[1]) check_call([ 'gcc', '-mwindows', '-o', wrapper, '-L', python_lib, wrapper_o, wrapper_res_o, lpython ]) self.add_file(wrapper, 'bin', feature='core')
def repoint_libraries(self, binary, install_dir): # Rewrite paths to shared libaries inside binary to be relative to # the executable instead of pointing to absolute paths in install_dir otool = subprocess.Popen(args=['otool', '-L', binary], stdout=subprocess.PIPE) first = True for line in otool.stdout: # First line is the identification name of the library, subsequent lines are indented if not line.startswith('\t'): continue path = line.strip().split()[0] if not path.startswith(install_dir): continue relative_path = path[len(install_dir) + 1:] check_call([ 'install_name_tool', '-change', path, '@executable_path/../Resources/' + relative_path, binary ]) otool.wait()
def compile_wrapper(self): python_topdir = os.path.dirname(os.path.dirname(shutil.__file__)) python_include = os.path.join(python_topdir, "include") python_lib = os.path.join(python_topdir, "libs") wrapper_c = os.path.join(self.topdir, "tools", "build_msi", "wrapper.c") wrapper_o = os.path.join(self.tempdir, "wrapper.o") check_call(['gcc', '-o', wrapper_o, '-c', '-O2', '-Wall', '-I', python_include, wrapper_c]) wrapper_rc = os.path.join(self.tempdir, "wrapper.rc") wrapper_res_o = os.path.join(self.tempdir, "wrapper.res.o") f = open(wrapper_rc, "w") f.write("""LANGUAGE 0, 0 100 ICON %s """ % os.path.join(self.treedir, "Reinteract.ico")) f.close() check_call(['windres', '-O', 'COFF', '-o', wrapper_res_o, wrapper_rc]) wrapper = os.path.join(self.tempdir, "Reinteract.exe") check_call(['gcc', '-mwindows', '-o', wrapper, '-L', python_lib, wrapper_o, wrapper_res_o, '-lpython25']) self.add_file(wrapper, 'bin', feature='core')
def build(self): version = self.get_version() python_version = "python%d.%d" % (sys.version_info[0], sys.version_info[1]) full_version = version + "-" + python_version output = self.output % {'version': full_version} _logger.info("Will write output to %s", output) self.component_namespace = uuid.uuid5(COMPONENT_NAMESPACE, full_version) self.add_files_from_am('', '', feature='core') self.substitute_pyw(full_version) # This is a XDG icon-specification organized directory with a SVG in it, not useful shutil.rmtree(os.path.join(self.treedir, 'icons')) self.add_file('data/Reinteract.ico', '', feature='core') self.add_feature_component('core', 'ReinteractShortcut') if python_version == 'python2.5': self.compile_wrapper_python25() else: self.compile_wrapper_python26() self.add_external_module('cairo', 'external', feature='pygtk') self.add_external_module('glib', 'external', feature='pygtk') self.add_external_module('gobject', 'external', feature='pygtk') self.add_external_module('atk', 'external', feature='pygtk') self.add_external_module('pango', 'external', feature='pygtk') self.add_external_module('pangocairo', 'external', feature='pygtk') self.add_external_module('gtk', 'external', feature='pygtk') self.add_external_module('numpy', 'external', feature='scipy') self.add_external_module('matplotlib', 'external', feature='scipy') # More matlab stuff self.add_external_module('mpl_toolkits', 'external', feature='scipy') # Some external deps installed with matplotlib self.add_external_module('dateutil', 'external', feature='scipy') self.add_external_module('pytz', 'external', feature='scipy') # matlab-like toplevel module installed with matplotlib self.add_external_module('pylab', 'external', feature='scipy') self.add_gtk_files() self.compile_python() self.generate_components() self.generate_feature('core', allow_absent='no', title='Reinteract', description='The Reinteract Application') self.generate_feature( 'gtk', allow_absent='yes', title='GTK+', description='Private copies of GTK+, GLib, Pango, ATK, and Cairo') self.generate_feature( 'pygtk', allow_absent='yes', title='PyGTK ', description= 'Private copies of the PyGTK and Pycairo language bindings') self.generate_feature( 'scipy', allow_absent='yes', title='SciPy', description='Private copies of the numpy and matplotlib modules') wxs = TEMPLATE % { 'product_guid': uuid.uuid5(PRODUCT_NAMESPACE, full_version), 'version': version, 'upgrade_code': UPGRADE_CODE, 'shortcut_component_guid': self.generate_component_guid("{shortcut}"), 'bindir_id': self.directory_ids['bin'], 'generated': self.generated.getvalue(), } wxsfile = os.path.join(self.tempdir, 'Reinteract.wxs') f = open(wxsfile, "w") f.write(wxs) f.close() wxsfiles = [wxsfile] localization_file = None for w in self.main_am['WIX_FILES'].split(): absw = os.path.join(self.topdir, w) if w.endswith(".wxs"): wxsfiles.append(absw) elif w.endswith(".wxl"): localization_file = absw else: shutil.copy(absw, self.treedir) wixobjfiles = [] for w in wxsfiles: wixobjfile = os.path.join(self.tempdir, os.path.basename(w)) wixobjfile = re.sub(".wxs$", ".wixobj", wixobjfile) check_call(['candle', '-o', wixobjfile, w]) wixobjfiles.append(wixobjfile) # WixUtilExtension is used for WixShellExec # WixUIExtension is used for the ErrorDlg, FilesInUse, MsiRMFilesInUse dialogs light_cmd = [ 'light', '-ext', 'WixUtilExtension', '-ext', 'WixUIExtension' ] # Where to look for source files light_cmd.extend(['-b', self.treedir]) # File holding localization strings that we used to override some strings in # the WixUI dialogs if localization_file is not None: light_cmd.extend(['-loc', localization_file]) # Where to write the output light_cmd.extend(['-o', output]) # Object files to build into the result light_cmd.extend(wixobjfiles) check_call(light_cmd) manifestfile = output + ".manifest" f = open(manifestfile, "w") for x in sorted(self.manifest): print >> f, x f.close()
def command_before_cache(self): script_common.command_before_cache(self) os.chdir(self.b2_dir) utils.check_call("git","clean","-dfqx") utils.check_call("git","status","-bs")
def command_build(self): script_common.command_build(self) # Set up tools. utils.makedirs(os.path.join(self.build_dir, 'dist', 'bin')) if not isinstance(self.ci, ci_cli) and toolset_info[self.toolset]['command']: os.environ['PATH'] = os.pathsep.join([ os.path.dirname(toolset_info[self.toolset]['command']), os.path.join(self.build_dir, 'dist', 'bin'), os.environ['PATH'] ]) else: os.environ['PATH'] = os.pathsep.join([ os.path.join(self.build_dir, 'dist', 'bin'), os.environ['PATH'] ]) os.environ['BOOST_BUILD_PATH'] = self.build_dir # Bootstrap Boost Build engine. os.chdir(os.path.join(self.boost_root, "tools", "build")) if sys.platform == 'win32': utils.check_call(".\\bootstrap.bat") shutil.copy2("b2.exe", os.path.join(self.build_dir, "dist", "bin", "b2.exe")) else: utils.check_call("./bootstrap.sh") shutil.copy2("b2", os.path.join(self.build_dir, "dist", "bin", "b2")) utils.check_call("git", "clean", "-dfqx") # Run the limited tests. if self.repo != 'boost': print("--- Testing %s ---" % (self.repo_path)) os.chdir(os.path.join(self.boost_root, 'status')) to_test = self.repo_path.split("/") del to_test[0] toolset_to_test = "" if self.toolset: if not isinstance(self.ci, ci_cli): toolset_to_test = toolset_info[self.toolset]['toolset'] else: toolset_to_test = self.toolset self.b2( '-d1', '-p0', '--include-tests=%s' % ("/".join(to_test)), 'preserve-test-targets=off', '--dump-tests', '--build-dir=%s' % (self.build_dir), '--out-xml=%s' % (os.path.join(self.build_dir, 'regression.xml')), '' if not toolset_to_test else 'toolset=%s' % (toolset_to_test), '' if not self.address_model else 'address-model=%s' % (self.address_model), 'variant=%s' % (self.variant), '--test-type=%s' % (self.target), '--verbose-test') # Generate a readable test report. import build_log log_main = build_log.Main([ '--output=console', os.path.join(self.build_dir, 'regression.xml') ]) # And exit with an error if the report contains failures. # This lets the CI notice the error and report a failed build. # And hence trigger the failure machinery, like sending emails. if log_main.failed: self.ci.finish(-1)
def build(self): version = self.get_version() output = self.output % { 'version' : version } _logger.info("Will write output to %s", output) self.component_namespace = uuid.uuid5(COMPONENT_NAMESPACE, version) self.add_files_from_am('', '', feature='core') self.add_file('bin/Reinteract.pyw', 'bin', feature='core') # This is a XDG icon-specification organized directory with a SVG in it, not useful shutil.rmtree(os.path.join(self.treedir, 'icons')) self.add_file('data/Reinteract.ico', '', feature='core') self.add_feature_component('core', 'ReinteractShortcut') self.compile_wrapper() self.add_external_module('cairo', 'external', feature='pygtk') self.add_external_module('gobject', 'external', feature='pygtk') self.add_external_module('atk', 'external', feature='pygtk') self.add_external_module('pango', 'external', feature='pygtk') self.add_external_module('pangocairo', 'external', feature='pygtk') self.add_external_module('gtk', 'external', feature='pygtk') self.add_external_module('numpy', 'external', feature='scipy') self.add_external_module('matplotlib', 'external', feature='scipy') # More matlab stuff self.add_external_module('mpl_toolkits', 'external', feature='scipy') # Some external deps installed with matplotlib self.add_external_module('configobj', 'external', feature='scipy') self.add_external_module('dateutil', 'external', feature='scipy') self.add_external_module('pytz', 'external', feature='scipy') # matlab-like toplevel module installed with matplotlib self.add_external_module('pylab', 'external', feature='scipy') self.add_gtk_files() self.compile_python() self.generate_components() self.generate_feature('core', allow_absent='no', title='Reinteract', description='The Reinteract Application') self.generate_feature('gtk', allow_absent='yes', title='GTK+', description='Private copies of GTK+, GLib, Pango, ATK, and Cairo') self.generate_feature('pygtk', allow_absent='yes', title='PyGTK ', description='Private copies of the PyGTK and Pycairo language bindings') self.generate_feature('scipy', allow_absent='yes', title='SciPy', description='Private copies of the numpy and matplotlib modules') wxs = TEMPLATE % { 'product_guid' : uuid.uuid5(PRODUCT_NAMESPACE, version), 'version' : version, 'upgrade_code' : UPGRADE_CODE, 'shortcut_component_guid' : self.generate_component_guid("{shortcut}"), 'bindir_id' : self.directory_ids['bin'], 'generated' : self.generated.getvalue(), } wxsfile = os.path.join(self.tempdir, 'Reinteract.wxs') f = open(wxsfile, "w") f.write(wxs) f.close() wxsfiles = [wxsfile] localization_file = None for w in self.main_am['WIX_FILES'].split(): absw = os.path.join(self.topdir, w) if w.endswith(".wxs"): wxsfiles.append(absw) elif w.endswith(".wxl"): localization_file = absw else: shutil.copy(absw, self.treedir) wixobjfiles = [] for w in wxsfiles: wixobjfile = os.path.join(self.tempdir, os.path.basename(w)) wixobjfile = re.sub(".wxs$", ".wixobj", wixobjfile) check_call(['candle', '-o', wixobjfile, w]) wixobjfiles.append(wixobjfile) # WixUtilExtension is used for WixShellExec # WixUIExtension is used for the ErrorDlg, FilesInUse, MsiRMFilesInUse dialogs light_cmd = ['light', '-ext', 'WixUtilExtension', '-ext', 'WixUIExtension'] # Where to look for source files light_cmd.extend(['-b', self.treedir]) # File holding localization strings that we used to override some strings in # the WixUI dialogs if localization_file != None: light_cmd.extend(['-loc', localization_file]) # Where to write the output light_cmd.extend(['-o', output]) # Object files to build into the result light_cmd.extend(wixobjfiles) check_call(light_cmd) manifestfile = output + ".manifest" f = open(manifestfile, "w") for x in sorted(self.manifest): print >>f, x f.close()