[Workflow] Try to fix code-formatter failing to find changes in some cases.
[llvm-project.git] / lldb / scripts / install_custom_python.py
blob04df6fbc3ceae03a5c17fc905715735237a6e8a9
1 """ Copies the build output of a custom python interpreter to a directory
2 structure that mirrors that of an official Python distribution.
4 --------------------------------------------------------------------------
5 File: install_custom_python.py
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.
16 Gotchas: None.
18 Copyright: None.
19 --------------------------------------------------------------------------
21 """
23 import argparse
24 import itertools
25 import os
26 import shutil
27 import sys
30 def 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)
33 print("Copying file %s ==> %s..." % (source_path, dest_path))
34 shutil.copyfile(source_path, dest_path)
37 def 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)
40 if copy_debug_suffix_also:
41 copy_one_file(dest_dir, source_dir, file + "_d." + ext)
44 def 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)
47 print("Copying directory %s ==> %s..." % (source_dir, dest_dir))
48 shutil.copytree(source_dir, dest_dir)
51 def copy_distro(dest_dir, dest_subdir, source_dir, source_prefix):
52 dest_dir = os.path.join(dest_dir, dest_subdir)
54 print("Copying distribution %s ==> %s" % (source_dir, dest_dir))
56 os.mkdir(dest_dir)
57 PCbuild_dir = os.path.join(source_dir, "PCbuild")
58 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
61 # includes the Python executables, python27(_d).dll, and relevant PDB
62 # files.
63 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)
66 copy_named_files(
67 dest_dir, PCbuild_dir, ["python", "pythonw"], ["exe", "pdb"], False
69 copy_named_files(dest_dir, PCbuild_dir, ["python27"], ["dll", "pdb"], True)
71 # Next copy everything in the Include directory.
72 print("Copying Python include directory")
73 copy_subdirectory(dest_dir, source_dir, "Include")
75 # Copy Lib folder (builtin Python modules)
76 print("Copying Python Lib directory")
77 copy_subdirectory(dest_dir, source_dir, "Lib")
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.
84 tools_dest_dir = os.path.join(dest_dir, "Tools")
85 tools_source_dir = os.path.join(source_dir, "Tools")
86 os.mkdir(tools_dest_dir)
87 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")
93 pyd_names = [
94 "_ctypes",
95 "_ctypes_test",
96 "_elementtree",
97 "_multiprocessing",
98 "_socket",
99 "_testcapi",
100 "pyexpat",
101 "select",
102 "unicodedata",
103 "winsound",
106 # Copy builtin extension modules (pyd files)
107 dlls_dir = os.path.join(dest_dir, "DLLs")
108 os.mkdir(dlls_dir)
109 print("Copying DLLs directory")
110 copy_named_files(dlls_dir, PCbuild_dir, pyd_names, ["pyd", "pdb"], True)
112 # Copy libs folder (implibs for the pyd files)
113 libs_dir = os.path.join(dest_dir, "libs")
114 os.mkdir(libs_dir)
115 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)
120 parser = argparse.ArgumentParser(description="Install a custom Python distribution")
121 parser.add_argument(
122 "--source", required=True, help="The root of the source tree where Python is built."
124 parser.add_argument(
125 "--dest", required=True, help="The location to install the Python distributions."
127 parser.add_argument(
128 "--overwrite",
129 default=False,
130 action="store_true",
131 help="If the destination directory already exists, destroys its contents first.",
133 parser.add_argument(
134 "--silent",
135 default=False,
136 action="store_true",
137 help="If --overwite was specified, suppress confirmation before deleting a directory tree.",
140 args = parser.parse_args()
142 args.source = os.path.normpath(args.source)
143 args.dest = os.path.normpath(args.dest)
145 if not os.path.exists(args.source):
146 print("The source directory %s does not exist. Exiting...")
147 sys.exit(1)
149 if os.path.exists(args.dest):
150 if not args.overwrite:
151 print(
152 "The destination directory '%s' already exists and --overwrite was not specified. Exiting..."
153 % args.dest
155 sys.exit(1)
156 while not args.silent:
157 print(
158 "Ok to recursively delete '%s' and all contents (Y/N)? Choosing Y will permanently delete the contents."
159 % args.dest
161 result = str.upper(sys.stdin.read(1))
162 if result == "N":
163 print(
164 "Unable to copy files to the destination. The destination already exists."
166 sys.exit(1)
167 elif result == "Y":
168 break
169 shutil.rmtree(args.dest)
171 os.mkdir(args.dest)
172 copy_distro(args.dest, "x86", args.source, None)
173 copy_distro(args.dest, "x64", args.source, "amd64")