[docs] Update HowToReleaseLLVM documentation.
[llvm-project.git] / lldb / scripts / install_custom_python.py
blob6e263fa714e0079f7ac7f829b89b42d719885a08
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(
38 dest_dir,
39 source_dir,
40 files,
41 extensions,
42 copy_debug_suffix_also):
43 for (file, ext) in itertools.product(files, extensions):
44 copy_one_file(dest_dir, source_dir, file + '.' + ext)
45 if copy_debug_suffix_also:
46 copy_one_file(dest_dir, source_dir, file + '_d.' + ext)
49 def copy_subdirectory(dest_dir, source_dir, subdir):
50 dest_dir = os.path.join(dest_dir, subdir)
51 source_dir = os.path.join(source_dir, subdir)
52 print('Copying directory %s ==> %s...' % (source_dir, dest_dir))
53 shutil.copytree(source_dir, dest_dir)
56 def copy_distro(dest_dir, dest_subdir, source_dir, source_prefix):
57 dest_dir = os.path.join(dest_dir, dest_subdir)
59 print('Copying distribution %s ==> %s' % (source_dir, dest_dir))
61 os.mkdir(dest_dir)
62 PCbuild_dir = os.path.join(source_dir, 'PCbuild')
63 if source_prefix:
64 PCbuild_dir = os.path.join(PCbuild_dir, source_prefix)
65 # First copy the files that go into the root of the new distribution. This
66 # includes the Python executables, python27(_d).dll, and relevant PDB
67 # files.
68 print('Copying Python executables...')
69 copy_named_files(
70 dest_dir, PCbuild_dir, ['w9xpopen'], [
71 'exe', 'pdb'], False)
72 copy_named_files(
73 dest_dir, PCbuild_dir, [
74 'python_d', 'pythonw_d'], ['exe'], False)
75 copy_named_files(
76 dest_dir, PCbuild_dir, [
77 'python', 'pythonw'], [
78 'exe', 'pdb'], False)
79 copy_named_files(dest_dir, PCbuild_dir, ['python27'], ['dll', 'pdb'], True)
81 # Next copy everything in the Include directory.
82 print('Copying Python include directory')
83 copy_subdirectory(dest_dir, source_dir, 'Include')
85 # Copy Lib folder (builtin Python modules)
86 print('Copying Python Lib directory')
87 copy_subdirectory(dest_dir, source_dir, 'Lib')
89 # Copy tools folder. These are probably not necessary, but we copy them anyway to
90 # match an official distribution as closely as possible. Note that we don't just copy
91 # the subdirectory recursively. The source distribution ships with many more tools
92 # than what you get by installing python regularly. We only copy the tools that appear
93 # in an installed distribution.
94 tools_dest_dir = os.path.join(dest_dir, 'Tools')
95 tools_source_dir = os.path.join(source_dir, 'Tools')
96 os.mkdir(tools_dest_dir)
97 copy_subdirectory(tools_dest_dir, tools_source_dir, 'i18n')
98 copy_subdirectory(tools_dest_dir, tools_source_dir, 'pynche')
99 copy_subdirectory(tools_dest_dir, tools_source_dir, 'scripts')
100 copy_subdirectory(tools_dest_dir, tools_source_dir, 'versioncheck')
101 copy_subdirectory(tools_dest_dir, tools_source_dir, 'webchecker')
103 pyd_names = [
104 '_ctypes',
105 '_ctypes_test',
106 '_elementtree',
107 '_multiprocessing',
108 '_socket',
109 '_testcapi',
110 'pyexpat',
111 'select',
112 'unicodedata',
113 'winsound']
115 # Copy builtin extension modules (pyd files)
116 dlls_dir = os.path.join(dest_dir, 'DLLs')
117 os.mkdir(dlls_dir)
118 print('Copying DLLs directory')
119 copy_named_files(dlls_dir, PCbuild_dir, pyd_names, ['pyd', 'pdb'], True)
121 # Copy libs folder (implibs for the pyd files)
122 libs_dir = os.path.join(dest_dir, 'libs')
123 os.mkdir(libs_dir)
124 print('Copying libs directory')
125 copy_named_files(libs_dir, PCbuild_dir, pyd_names, ['lib'], False)
126 copy_named_files(libs_dir, PCbuild_dir, ['python27'], ['lib'], True)
129 parser = argparse.ArgumentParser(
130 description='Install a custom Python distribution')
131 parser.add_argument(
132 '--source',
133 required=True,
134 help='The root of the source tree where Python is built.')
135 parser.add_argument(
136 '--dest',
137 required=True,
138 help='The location to install the Python distributions.')
139 parser.add_argument(
140 '--overwrite',
141 default=False,
142 action='store_true',
143 help='If the destination directory already exists, destroys its contents first.')
144 parser.add_argument(
145 '--silent',
146 default=False,
147 action='store_true',
148 help='If --overwite was specified, suppress confirmation before deleting a directory tree.')
150 args = parser.parse_args()
152 args.source = os.path.normpath(args.source)
153 args.dest = os.path.normpath(args.dest)
155 if not os.path.exists(args.source):
156 print('The source directory %s does not exist. Exiting...')
157 sys.exit(1)
159 if os.path.exists(args.dest):
160 if not args.overwrite:
161 print('The destination directory \'%s\' already exists and --overwrite was not specified. Exiting...' % args.dest)
162 sys.exit(1)
163 while not args.silent:
164 print('Ok to recursively delete \'%s\' and all contents (Y/N)? Choosing Y will permanently delete the contents.' % args.dest)
165 result = str.upper(sys.stdin.read(1))
166 if result == 'N':
167 print('Unable to copy files to the destination. The destination already exists.')
168 sys.exit(1)
169 elif result == 'Y':
170 break
171 shutil.rmtree(args.dest)
173 os.mkdir(args.dest)
174 copy_distro(args.dest, 'x86', args.source, None)
175 copy_distro(args.dest, 'x64', args.source, 'amd64')