176 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			176 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Python
		
	
	
	
| """ Copies the build output of a custom python interpreter to a directory
 | |
|     structure that mirrors that of an official Python distribution.
 | |
| 
 | |
|     --------------------------------------------------------------------------
 | |
|     File:           install_custom_python.py
 | |
| 
 | |
|     Overview:       Most users build LLDB by linking against the standard
 | |
|                     Python distribution installed on their system.  Occasionally
 | |
|                     a user may want to build their own version of Python, and on
 | |
|                     platforms such as Windows this is a hard requirement.  This
 | |
|                     script will take the build output of a custom interpreter and
 | |
|                     install it into a canonical structure that mirrors that of an
 | |
|                     official Python distribution, thus allowing PYTHONHOME to be
 | |
|                     set appropriately.
 | |
| 
 | |
|     Gotchas:        None.
 | |
| 
 | |
|     Copyright:      None.
 | |
|     --------------------------------------------------------------------------
 | |
| 
 | |
| """
 | |
| 
 | |
| import argparse
 | |
| import itertools
 | |
| import os
 | |
| import shutil
 | |
| import sys
 | |
| 
 | |
| 
 | |
| def copy_one_file(dest_dir, source_dir, filename):
 | |
|     source_path = os.path.join(source_dir, filename)
 | |
|     dest_path = os.path.join(dest_dir, filename)
 | |
|     print 'Copying file %s ==> %s...' % (source_path, dest_path)
 | |
|     shutil.copyfile(source_path, dest_path)
 | |
| 
 | |
| 
 | |
| def copy_named_files(
 | |
|         dest_dir,
 | |
|         source_dir,
 | |
|         files,
 | |
|         extensions,
 | |
|         copy_debug_suffix_also):
 | |
|     for (file, ext) in itertools.product(files, extensions):
 | |
|         copy_one_file(dest_dir, source_dir, file + '.' + ext)
 | |
|         if copy_debug_suffix_also:
 | |
|             copy_one_file(dest_dir, source_dir, file + '_d.' + ext)
 | |
| 
 | |
| 
 | |
| def copy_subdirectory(dest_dir, source_dir, subdir):
 | |
|     dest_dir = os.path.join(dest_dir, subdir)
 | |
|     source_dir = os.path.join(source_dir, subdir)
 | |
|     print 'Copying directory %s ==> %s...' % (source_dir, dest_dir)
 | |
|     shutil.copytree(source_dir, dest_dir)
 | |
| 
 | |
| 
 | |
| def copy_distro(dest_dir, dest_subdir, source_dir, source_prefix):
 | |
|     dest_dir = os.path.join(dest_dir, dest_subdir)
 | |
| 
 | |
|     print 'Copying distribution %s ==> %s' % (source_dir, dest_dir)
 | |
| 
 | |
|     os.mkdir(dest_dir)
 | |
|     PCbuild_dir = os.path.join(source_dir, 'PCbuild')
 | |
|     if source_prefix:
 | |
|         PCbuild_dir = os.path.join(PCbuild_dir, source_prefix)
 | |
|     # First copy the files that go into the root of the new distribution. This
 | |
|     # includes the Python executables, python27(_d).dll, and relevant PDB
 | |
|     # files.
 | |
|     print 'Copying Python executables...'
 | |
|     copy_named_files(
 | |
|         dest_dir, PCbuild_dir, ['w9xpopen'], [
 | |
|             'exe', 'pdb'], False)
 | |
|     copy_named_files(
 | |
|         dest_dir, PCbuild_dir, [
 | |
|             'python_d', 'pythonw_d'], ['exe'], False)
 | |
|     copy_named_files(
 | |
|         dest_dir, PCbuild_dir, [
 | |
|             'python', 'pythonw'], [
 | |
|             'exe', 'pdb'], False)
 | |
|     copy_named_files(dest_dir, PCbuild_dir, ['python27'], ['dll', 'pdb'], True)
 | |
| 
 | |
|     # Next copy everything in the Include directory.
 | |
|     print 'Copying Python include directory'
 | |
|     copy_subdirectory(dest_dir, source_dir, 'Include')
 | |
| 
 | |
|     # Copy Lib folder (builtin Python modules)
 | |
|     print 'Copying Python Lib directory'
 | |
|     copy_subdirectory(dest_dir, source_dir, 'Lib')
 | |
| 
 | |
|     # Copy tools folder.  These are probably not necessary, but we copy them anyway to
 | |
|     # match an official distribution as closely as possible.  Note that we don't just copy
 | |
|     # the subdirectory recursively.  The source distribution ships with many more tools
 | |
|     # than what you get by installing python regularly.  We only copy the tools that appear
 | |
|     # in an installed distribution.
 | |
|     tools_dest_dir = os.path.join(dest_dir, 'Tools')
 | |
|     tools_source_dir = os.path.join(source_dir, 'Tools')
 | |
|     os.mkdir(tools_dest_dir)
 | |
|     copy_subdirectory(tools_dest_dir, tools_source_dir, 'i18n')
 | |
|     copy_subdirectory(tools_dest_dir, tools_source_dir, 'pynche')
 | |
|     copy_subdirectory(tools_dest_dir, tools_source_dir, 'scripts')
 | |
|     copy_subdirectory(tools_dest_dir, tools_source_dir, 'versioncheck')
 | |
|     copy_subdirectory(tools_dest_dir, tools_source_dir, 'webchecker')
 | |
| 
 | |
|     pyd_names = [
 | |
|         '_ctypes',
 | |
|         '_ctypes_test',
 | |
|         '_elementtree',
 | |
|         '_multiprocessing',
 | |
|         '_socket',
 | |
|         '_testcapi',
 | |
|         'pyexpat',
 | |
|         'select',
 | |
|         'unicodedata',
 | |
|         'winsound']
 | |
| 
 | |
|     # Copy builtin extension modules (pyd files)
 | |
|     dlls_dir = os.path.join(dest_dir, 'DLLs')
 | |
|     os.mkdir(dlls_dir)
 | |
|     print 'Copying DLLs directory'
 | |
|     copy_named_files(dlls_dir, PCbuild_dir, pyd_names, ['pyd', 'pdb'], True)
 | |
| 
 | |
|     # Copy libs folder (implibs for the pyd files)
 | |
|     libs_dir = os.path.join(dest_dir, 'libs')
 | |
|     os.mkdir(libs_dir)
 | |
|     print 'Copying libs directory'
 | |
|     copy_named_files(libs_dir, PCbuild_dir, pyd_names, ['lib'], False)
 | |
|     copy_named_files(libs_dir, PCbuild_dir, ['python27'], ['lib'], True)
 | |
| 
 | |
| 
 | |
| parser = argparse.ArgumentParser(
 | |
|     description='Install a custom Python distribution')
 | |
| parser.add_argument(
 | |
|     '--source',
 | |
|     required=True,
 | |
|     help='The root of the source tree where Python is built.')
 | |
| parser.add_argument(
 | |
|     '--dest',
 | |
|     required=True,
 | |
|     help='The location to install the Python distributions.')
 | |
| parser.add_argument(
 | |
|     '--overwrite',
 | |
|     default=False,
 | |
|     action='store_true',
 | |
|     help='If the destination directory already exists, destroys its contents first.')
 | |
| parser.add_argument(
 | |
|     '--silent',
 | |
|     default=False,
 | |
|     action='store_true',
 | |
|     help='If --overwite was specified, suppress confirmation before deleting a directory tree.')
 | |
| 
 | |
| args = parser.parse_args()
 | |
| 
 | |
| args.source = os.path.normpath(args.source)
 | |
| args.dest = os.path.normpath(args.dest)
 | |
| 
 | |
| if not os.path.exists(args.source):
 | |
|     print 'The source directory %s does not exist.  Exiting...'
 | |
|     sys.exit(1)
 | |
| 
 | |
| if os.path.exists(args.dest):
 | |
|     if not args.overwrite:
 | |
|         print 'The destination directory \'%s\' already exists and --overwrite was not specified.  Exiting...' % args.dest
 | |
|         sys.exit(1)
 | |
|     while not args.silent:
 | |
|         print 'Ok to recursively delete \'%s\' and all contents (Y/N)?  Choosing Y will permanently delete the contents.' % args.dest
 | |
|         result = str.upper(sys.stdin.read(1))
 | |
|         if result == 'N':
 | |
|             print 'Unable to copy files to the destination.  The destination already exists.'
 | |
|             sys.exit(1)
 | |
|         elif result == 'Y':
 | |
|             break
 | |
|     shutil.rmtree(args.dest)
 | |
| 
 | |
| os.mkdir(args.dest)
 | |
| copy_distro(args.dest, 'x86', args.source, None)
 | |
| copy_distro(args.dest, 'x64', args.source, 'amd64')
 |