1dd50f742SZachary Turner""" Copies the build output of a custom python interpreter to a directory 2dd50f742SZachary Turner structure that mirrors that of an official Python distribution. 3dd50f742SZachary Turner 4dd50f742SZachary Turner -------------------------------------------------------------------------- 5dd50f742SZachary Turner File: install_custom_python.py 6dd50f742SZachary Turner 7dd50f742SZachary Turner Overview: Most users build LLDB by linking against the standard 8dd50f742SZachary Turner Python distribution installed on their system. Occasionally 9dd50f742SZachary Turner a user may want to build their own version of Python, and on 10dd50f742SZachary Turner platforms such as Windows this is a hard requirement. This 11dd50f742SZachary Turner script will take the build output of a custom interpreter and 12dd50f742SZachary Turner install it into a canonical structure that mirrors that of an 13dd50f742SZachary Turner official Python distribution, thus allowing PYTHONHOME to be 14dd50f742SZachary Turner set appropriately. 15dd50f742SZachary Turner 16dd50f742SZachary Turner Gotchas: None. 17dd50f742SZachary Turner 18dd50f742SZachary Turner Copyright: None. 19dd50f742SZachary Turner -------------------------------------------------------------------------- 20dd50f742SZachary Turner 21dd50f742SZachary Turner""" 22dd50f742SZachary Turner 23dd50f742SZachary Turnerimport argparse 24dd50f742SZachary Turnerimport itertools 25dd50f742SZachary Turnerimport os 26dd50f742SZachary Turnerimport shutil 27dd50f742SZachary Turnerimport sys 28dd50f742SZachary Turner 29b9c1b51eSKate Stone 30dd50f742SZachary Turnerdef copy_one_file(dest_dir, source_dir, filename): 31dd50f742SZachary Turner source_path = os.path.join(source_dir, filename) 32dd50f742SZachary Turner dest_path = os.path.join(dest_dir, filename) 33*602e47c5SDavid Spickett print("Copying file %s ==> %s..." % (source_path, dest_path)) 34dd50f742SZachary Turner shutil.copyfile(source_path, dest_path) 35dd50f742SZachary Turner 36b9c1b51eSKate Stone 37*602e47c5SDavid Spickettdef copy_named_files(dest_dir, source_dir, files, extensions, copy_debug_suffix_also): 38*602e47c5SDavid Spickett for file, ext in itertools.product(files, extensions): 39*602e47c5SDavid Spickett copy_one_file(dest_dir, source_dir, file + "." + ext) 40dd50f742SZachary Turner if copy_debug_suffix_also: 41*602e47c5SDavid Spickett copy_one_file(dest_dir, source_dir, file + "_d." + ext) 42dd50f742SZachary Turner 43b9c1b51eSKate Stone 44dd50f742SZachary Turnerdef copy_subdirectory(dest_dir, source_dir, subdir): 45dd50f742SZachary Turner dest_dir = os.path.join(dest_dir, subdir) 46dd50f742SZachary Turner source_dir = os.path.join(source_dir, subdir) 47*602e47c5SDavid Spickett print("Copying directory %s ==> %s..." % (source_dir, dest_dir)) 48dd50f742SZachary Turner shutil.copytree(source_dir, dest_dir) 49dd50f742SZachary Turner 50b9c1b51eSKate Stone 51dd50f742SZachary Turnerdef copy_distro(dest_dir, dest_subdir, source_dir, source_prefix): 52dd50f742SZachary Turner dest_dir = os.path.join(dest_dir, dest_subdir) 53dd50f742SZachary Turner 54*602e47c5SDavid Spickett print("Copying distribution %s ==> %s" % (source_dir, dest_dir)) 55dd50f742SZachary Turner 56dd50f742SZachary Turner os.mkdir(dest_dir) 57*602e47c5SDavid Spickett PCbuild_dir = os.path.join(source_dir, "PCbuild") 58dd50f742SZachary Turner if source_prefix: 59dd50f742SZachary Turner PCbuild_dir = os.path.join(PCbuild_dir, source_prefix) 60dd50f742SZachary Turner # First copy the files that go into the root of the new distribution. This 61b9c1b51eSKate Stone # includes the Python executables, python27(_d).dll, and relevant PDB 62b9c1b51eSKate Stone # files. 63*602e47c5SDavid Spickett print("Copying Python executables...") 64*602e47c5SDavid Spickett copy_named_files(dest_dir, PCbuild_dir, ["w9xpopen"], ["exe", "pdb"], False) 65*602e47c5SDavid Spickett copy_named_files(dest_dir, PCbuild_dir, ["python_d", "pythonw_d"], ["exe"], False) 66b9c1b51eSKate Stone copy_named_files( 67*602e47c5SDavid Spickett dest_dir, PCbuild_dir, ["python", "pythonw"], ["exe", "pdb"], False 68*602e47c5SDavid Spickett ) 69*602e47c5SDavid Spickett copy_named_files(dest_dir, PCbuild_dir, ["python27"], ["dll", "pdb"], True) 70dd50f742SZachary Turner 71dd50f742SZachary Turner # Next copy everything in the Include directory. 72*602e47c5SDavid Spickett print("Copying Python include directory") 73*602e47c5SDavid Spickett copy_subdirectory(dest_dir, source_dir, "Include") 74dd50f742SZachary Turner 75dd50f742SZachary Turner # Copy Lib folder (builtin Python modules) 76*602e47c5SDavid Spickett print("Copying Python Lib directory") 77*602e47c5SDavid Spickett copy_subdirectory(dest_dir, source_dir, "Lib") 78dd50f742SZachary Turner 79dd50f742SZachary Turner # Copy tools folder. These are probably not necessary, but we copy them anyway to 80dd50f742SZachary Turner # match an official distribution as closely as possible. Note that we don't just copy 81dd50f742SZachary Turner # the subdirectory recursively. The source distribution ships with many more tools 82dd50f742SZachary Turner # than what you get by installing python regularly. We only copy the tools that appear 83dd50f742SZachary Turner # in an installed distribution. 84*602e47c5SDavid Spickett tools_dest_dir = os.path.join(dest_dir, "Tools") 85*602e47c5SDavid Spickett tools_source_dir = os.path.join(source_dir, "Tools") 86dd50f742SZachary Turner os.mkdir(tools_dest_dir) 87*602e47c5SDavid Spickett copy_subdirectory(tools_dest_dir, tools_source_dir, "i18n") 88*602e47c5SDavid Spickett copy_subdirectory(tools_dest_dir, tools_source_dir, "pynche") 89*602e47c5SDavid Spickett copy_subdirectory(tools_dest_dir, tools_source_dir, "scripts") 90*602e47c5SDavid Spickett copy_subdirectory(tools_dest_dir, tools_source_dir, "versioncheck") 91*602e47c5SDavid Spickett copy_subdirectory(tools_dest_dir, tools_source_dir, "webchecker") 92dd50f742SZachary Turner 93b9c1b51eSKate Stone pyd_names = [ 94*602e47c5SDavid Spickett "_ctypes", 95*602e47c5SDavid Spickett "_ctypes_test", 96*602e47c5SDavid Spickett "_elementtree", 97*602e47c5SDavid Spickett "_multiprocessing", 98*602e47c5SDavid Spickett "_socket", 99*602e47c5SDavid Spickett "_testcapi", 100*602e47c5SDavid Spickett "pyexpat", 101*602e47c5SDavid Spickett "select", 102*602e47c5SDavid Spickett "unicodedata", 103*602e47c5SDavid Spickett "winsound", 104*602e47c5SDavid Spickett ] 105dd50f742SZachary Turner 106dd50f742SZachary Turner # Copy builtin extension modules (pyd files) 107*602e47c5SDavid Spickett dlls_dir = os.path.join(dest_dir, "DLLs") 108dd50f742SZachary Turner os.mkdir(dlls_dir) 109*602e47c5SDavid Spickett print("Copying DLLs directory") 110*602e47c5SDavid Spickett copy_named_files(dlls_dir, PCbuild_dir, pyd_names, ["pyd", "pdb"], True) 111dd50f742SZachary Turner 112dd50f742SZachary Turner # Copy libs folder (implibs for the pyd files) 113*602e47c5SDavid Spickett libs_dir = os.path.join(dest_dir, "libs") 114dd50f742SZachary Turner os.mkdir(libs_dir) 115*602e47c5SDavid Spickett print("Copying libs directory") 116*602e47c5SDavid Spickett copy_named_files(libs_dir, PCbuild_dir, pyd_names, ["lib"], False) 117*602e47c5SDavid Spickett copy_named_files(libs_dir, PCbuild_dir, ["python27"], ["lib"], True) 118dd50f742SZachary Turner 119dd50f742SZachary Turner 120*602e47c5SDavid Spickettparser = argparse.ArgumentParser(description="Install a custom Python distribution") 121b9c1b51eSKate Stoneparser.add_argument( 122*602e47c5SDavid Spickett "--source", required=True, help="The root of the source tree where Python is built." 123*602e47c5SDavid Spickett) 124b9c1b51eSKate Stoneparser.add_argument( 125*602e47c5SDavid Spickett "--dest", required=True, help="The location to install the Python distributions." 126*602e47c5SDavid Spickett) 127b9c1b51eSKate Stoneparser.add_argument( 128*602e47c5SDavid Spickett "--overwrite", 129b9c1b51eSKate Stone default=False, 130*602e47c5SDavid Spickett action="store_true", 131*602e47c5SDavid Spickett help="If the destination directory already exists, destroys its contents first.", 132*602e47c5SDavid Spickett) 133b9c1b51eSKate Stoneparser.add_argument( 134*602e47c5SDavid Spickett "--silent", 135b9c1b51eSKate Stone default=False, 136*602e47c5SDavid Spickett action="store_true", 137*602e47c5SDavid Spickett help="If --overwite was specified, suppress confirmation before deleting a directory tree.", 138*602e47c5SDavid Spickett) 139dd50f742SZachary Turner 140dd50f742SZachary Turnerargs = parser.parse_args() 141dd50f742SZachary Turner 142dd50f742SZachary Turnerargs.source = os.path.normpath(args.source) 143dd50f742SZachary Turnerargs.dest = os.path.normpath(args.dest) 144dd50f742SZachary Turner 145dd50f742SZachary Turnerif not os.path.exists(args.source): 146*602e47c5SDavid Spickett print("The source directory %s does not exist. Exiting...") 147dd50f742SZachary Turner sys.exit(1) 148dd50f742SZachary Turner 149dd50f742SZachary Turnerif os.path.exists(args.dest): 150dd50f742SZachary Turner if not args.overwrite: 151*602e47c5SDavid Spickett print( 152*602e47c5SDavid Spickett "The destination directory '%s' already exists and --overwrite was not specified. Exiting..." 153*602e47c5SDavid Spickett % args.dest 154*602e47c5SDavid Spickett ) 155dd50f742SZachary Turner sys.exit(1) 156dd50f742SZachary Turner while not args.silent: 157*602e47c5SDavid Spickett print( 158*602e47c5SDavid Spickett "Ok to recursively delete '%s' and all contents (Y/N)? Choosing Y will permanently delete the contents." 159*602e47c5SDavid Spickett % args.dest 160*602e47c5SDavid Spickett ) 161dd50f742SZachary Turner result = str.upper(sys.stdin.read(1)) 162*602e47c5SDavid Spickett if result == "N": 163*602e47c5SDavid Spickett print( 164*602e47c5SDavid Spickett "Unable to copy files to the destination. The destination already exists." 165*602e47c5SDavid Spickett ) 166dd50f742SZachary Turner sys.exit(1) 167*602e47c5SDavid Spickett elif result == "Y": 168dd50f742SZachary Turner break 169dd50f742SZachary Turner shutil.rmtree(args.dest) 170dd50f742SZachary Turner 171dd50f742SZachary Turneros.mkdir(args.dest) 172*602e47c5SDavid Spickettcopy_distro(args.dest, "x86", args.source, None) 173*602e47c5SDavid Spickettcopy_distro(args.dest, "x64", args.source, "amd64") 174