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
19 --------------------------------------------------------------------------
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
)
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
))
62 PCbuild_dir
= os
.path
.join(source_dir
, 'PCbuild')
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
68 print('Copying Python executables...')
70 dest_dir
, PCbuild_dir
, ['w9xpopen'], [
73 dest_dir
, PCbuild_dir
, [
74 'python_d', 'pythonw_d'], ['exe'], False)
76 dest_dir
, PCbuild_dir
, [
77 'python', 'pythonw'], [
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')
115 # Copy builtin extension modules (pyd files)
116 dlls_dir
= os
.path
.join(dest_dir
, 'DLLs')
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')
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')
134 help='The root of the source tree where Python is built.')
138 help='The location to install the Python distributions.')
143 help='If the destination directory already exists, destroys its contents first.')
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...')
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
)
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))
167 print('Unable to copy files to the destination. The destination already exists.')
171 shutil
.rmtree(args
.dest
)
174 copy_distro(args
.dest
, 'x86', args
.source
, None)
175 copy_distro(args
.dest
, 'x64', args
.source
, 'amd64')