blob: 04df6fbc3ceae03a5c17fc905715735237a6e8a9 [file] [log] [blame]
Zachary Turnerdd50f742015-04-10 22:58:56 +00001""" Copies the build output of a custom python interpreter to a directory
2 structure that mirrors that of an official Python distribution.
3
4 --------------------------------------------------------------------------
5 File: install_custom_python.py
6
7 Overview: Most users build LLDB by linking against the standard
8 Python distribution installed on their system. Occasionally
9 a user may want to build their own version of Python, and on
10 platforms such as Windows this is a hard requirement. This
11 script will take the build output of a custom interpreter and
12 install it into a canonical structure that mirrors that of an
13 official Python distribution, thus allowing PYTHONHOME to be
14 set appropriately.
15
16 Gotchas: None.
17
18 Copyright: None.
19 --------------------------------------------------------------------------
20
21"""
22
23import argparse
24import itertools
25import os
26import shutil
27import sys
28
Kate Stoneb9c1b512016-09-06 20:57:50 +000029
Zachary Turnerdd50f742015-04-10 22:58:56 +000030def copy_one_file(dest_dir, source_dir, filename):
31 source_path = os.path.join(source_dir, filename)
32 dest_path = os.path.join(dest_dir, filename)
David Spickett602e47c2023-09-14 08:54:02 +010033 print("Copying file %s ==> %s..." % (source_path, dest_path))
Zachary Turnerdd50f742015-04-10 22:58:56 +000034 shutil.copyfile(source_path, dest_path)
35
Kate Stoneb9c1b512016-09-06 20:57:50 +000036
David Spickett602e47c2023-09-14 08:54:02 +010037def copy_named_files(dest_dir, source_dir, files, extensions, copy_debug_suffix_also):
38 for file, ext in itertools.product(files, extensions):
39 copy_one_file(dest_dir, source_dir, file + "." + ext)
Zachary Turnerdd50f742015-04-10 22:58:56 +000040 if copy_debug_suffix_also:
David Spickett602e47c2023-09-14 08:54:02 +010041 copy_one_file(dest_dir, source_dir, file + "_d." + ext)
Zachary Turnerdd50f742015-04-10 22:58:56 +000042
Kate Stoneb9c1b512016-09-06 20:57:50 +000043
Zachary Turnerdd50f742015-04-10 22:58:56 +000044def copy_subdirectory(dest_dir, source_dir, subdir):
45 dest_dir = os.path.join(dest_dir, subdir)
46 source_dir = os.path.join(source_dir, subdir)
David Spickett602e47c2023-09-14 08:54:02 +010047 print("Copying directory %s ==> %s..." % (source_dir, dest_dir))
Zachary Turnerdd50f742015-04-10 22:58:56 +000048 shutil.copytree(source_dir, dest_dir)
49
Kate Stoneb9c1b512016-09-06 20:57:50 +000050
Zachary Turnerdd50f742015-04-10 22:58:56 +000051def copy_distro(dest_dir, dest_subdir, source_dir, source_prefix):
52 dest_dir = os.path.join(dest_dir, dest_subdir)
53
David Spickett602e47c2023-09-14 08:54:02 +010054 print("Copying distribution %s ==> %s" % (source_dir, dest_dir))
Zachary Turnerdd50f742015-04-10 22:58:56 +000055
56 os.mkdir(dest_dir)
David Spickett602e47c2023-09-14 08:54:02 +010057 PCbuild_dir = os.path.join(source_dir, "PCbuild")
Zachary Turnerdd50f742015-04-10 22:58:56 +000058 if source_prefix:
59 PCbuild_dir = os.path.join(PCbuild_dir, source_prefix)
60 # First copy the files that go into the root of the new distribution. This
Kate Stoneb9c1b512016-09-06 20:57:50 +000061 # includes the Python executables, python27(_d).dll, and relevant PDB
62 # files.
David Spickett602e47c2023-09-14 08:54:02 +010063 print("Copying Python executables...")
64 copy_named_files(dest_dir, PCbuild_dir, ["w9xpopen"], ["exe", "pdb"], False)
65 copy_named_files(dest_dir, PCbuild_dir, ["python_d", "pythonw_d"], ["exe"], False)
Kate Stoneb9c1b512016-09-06 20:57:50 +000066 copy_named_files(
David Spickett602e47c2023-09-14 08:54:02 +010067 dest_dir, PCbuild_dir, ["python", "pythonw"], ["exe", "pdb"], False
68 )
69 copy_named_files(dest_dir, PCbuild_dir, ["python27"], ["dll", "pdb"], True)
Zachary Turnerdd50f742015-04-10 22:58:56 +000070
71 # Next copy everything in the Include directory.
David Spickett602e47c2023-09-14 08:54:02 +010072 print("Copying Python include directory")
73 copy_subdirectory(dest_dir, source_dir, "Include")
Zachary Turnerdd50f742015-04-10 22:58:56 +000074
75 # Copy Lib folder (builtin Python modules)
David Spickett602e47c2023-09-14 08:54:02 +010076 print("Copying Python Lib directory")
77 copy_subdirectory(dest_dir, source_dir, "Lib")
Zachary Turnerdd50f742015-04-10 22:58:56 +000078
79 # Copy tools folder. These are probably not necessary, but we copy them anyway to
80 # match an official distribution as closely as possible. Note that we don't just copy
81 # the subdirectory recursively. The source distribution ships with many more tools
82 # than what you get by installing python regularly. We only copy the tools that appear
83 # in an installed distribution.
David Spickett602e47c2023-09-14 08:54:02 +010084 tools_dest_dir = os.path.join(dest_dir, "Tools")
85 tools_source_dir = os.path.join(source_dir, "Tools")
Zachary Turnerdd50f742015-04-10 22:58:56 +000086 os.mkdir(tools_dest_dir)
David Spickett602e47c2023-09-14 08:54:02 +010087 copy_subdirectory(tools_dest_dir, tools_source_dir, "i18n")
88 copy_subdirectory(tools_dest_dir, tools_source_dir, "pynche")
89 copy_subdirectory(tools_dest_dir, tools_source_dir, "scripts")
90 copy_subdirectory(tools_dest_dir, tools_source_dir, "versioncheck")
91 copy_subdirectory(tools_dest_dir, tools_source_dir, "webchecker")
Zachary Turnerdd50f742015-04-10 22:58:56 +000092
Kate Stoneb9c1b512016-09-06 20:57:50 +000093 pyd_names = [
David Spickett602e47c2023-09-14 08:54:02 +010094 "_ctypes",
95 "_ctypes_test",
96 "_elementtree",
97 "_multiprocessing",
98 "_socket",
99 "_testcapi",
100 "pyexpat",
101 "select",
102 "unicodedata",
103 "winsound",
104 ]
Zachary Turnerdd50f742015-04-10 22:58:56 +0000105
106 # Copy builtin extension modules (pyd files)
David Spickett602e47c2023-09-14 08:54:02 +0100107 dlls_dir = os.path.join(dest_dir, "DLLs")
Zachary Turnerdd50f742015-04-10 22:58:56 +0000108 os.mkdir(dlls_dir)
David Spickett602e47c2023-09-14 08:54:02 +0100109 print("Copying DLLs directory")
110 copy_named_files(dlls_dir, PCbuild_dir, pyd_names, ["pyd", "pdb"], True)
Zachary Turnerdd50f742015-04-10 22:58:56 +0000111
112 # Copy libs folder (implibs for the pyd files)
David Spickett602e47c2023-09-14 08:54:02 +0100113 libs_dir = os.path.join(dest_dir, "libs")
Zachary Turnerdd50f742015-04-10 22:58:56 +0000114 os.mkdir(libs_dir)
David Spickett602e47c2023-09-14 08:54:02 +0100115 print("Copying libs directory")
116 copy_named_files(libs_dir, PCbuild_dir, pyd_names, ["lib"], False)
117 copy_named_files(libs_dir, PCbuild_dir, ["python27"], ["lib"], True)
Zachary Turnerdd50f742015-04-10 22:58:56 +0000118
119
David Spickett602e47c2023-09-14 08:54:02 +0100120parser = argparse.ArgumentParser(description="Install a custom Python distribution")
Kate Stoneb9c1b512016-09-06 20:57:50 +0000121parser.add_argument(
David Spickett602e47c2023-09-14 08:54:02 +0100122 "--source", required=True, help="The root of the source tree where Python is built."
123)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000124parser.add_argument(
David Spickett602e47c2023-09-14 08:54:02 +0100125 "--dest", required=True, help="The location to install the Python distributions."
126)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000127parser.add_argument(
David Spickett602e47c2023-09-14 08:54:02 +0100128 "--overwrite",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000129 default=False,
David Spickett602e47c2023-09-14 08:54:02 +0100130 action="store_true",
131 help="If the destination directory already exists, destroys its contents first.",
132)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000133parser.add_argument(
David Spickett602e47c2023-09-14 08:54:02 +0100134 "--silent",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000135 default=False,
David Spickett602e47c2023-09-14 08:54:02 +0100136 action="store_true",
137 help="If --overwite was specified, suppress confirmation before deleting a directory tree.",
138)
Zachary Turnerdd50f742015-04-10 22:58:56 +0000139
140args = parser.parse_args()
141
142args.source = os.path.normpath(args.source)
143args.dest = os.path.normpath(args.dest)
144
145if not os.path.exists(args.source):
David Spickett602e47c2023-09-14 08:54:02 +0100146 print("The source directory %s does not exist. Exiting...")
Zachary Turnerdd50f742015-04-10 22:58:56 +0000147 sys.exit(1)
148
149if os.path.exists(args.dest):
150 if not args.overwrite:
David Spickett602e47c2023-09-14 08:54:02 +0100151 print(
152 "The destination directory '%s' already exists and --overwrite was not specified. Exiting..."
153 % args.dest
154 )
Zachary Turnerdd50f742015-04-10 22:58:56 +0000155 sys.exit(1)
156 while not args.silent:
David Spickett602e47c2023-09-14 08:54:02 +0100157 print(
158 "Ok to recursively delete '%s' and all contents (Y/N)? Choosing Y will permanently delete the contents."
159 % args.dest
160 )
Zachary Turnerdd50f742015-04-10 22:58:56 +0000161 result = str.upper(sys.stdin.read(1))
David Spickett602e47c2023-09-14 08:54:02 +0100162 if result == "N":
163 print(
164 "Unable to copy files to the destination. The destination already exists."
165 )
Zachary Turnerdd50f742015-04-10 22:58:56 +0000166 sys.exit(1)
David Spickett602e47c2023-09-14 08:54:02 +0100167 elif result == "Y":
Zachary Turnerdd50f742015-04-10 22:58:56 +0000168 break
169 shutil.rmtree(args.dest)
170
171os.mkdir(args.dest)
David Spickett602e47c2023-09-14 08:54:02 +0100172copy_distro(args.dest, "x86", args.source, None)
173copy_distro(args.dest, "x64", args.source, "amd64")