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
)
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
))
57 PCbuild_dir
= os
.path
.join(source_dir
, "PCbuild")
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
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)
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")
106 # Copy builtin extension modules (pyd files)
107 dlls_dir
= os
.path
.join(dest_dir
, "DLLs")
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")
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")
122 "--source", required
=True, help="The root of the source tree where Python is built."
125 "--dest", required
=True, help="The location to install the Python distributions."
131 help="If the destination directory already exists, destroys its contents first.",
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...")
149 if os
.path
.exists(args
.dest
):
150 if not args
.overwrite
:
152 "The destination directory '%s' already exists and --overwrite was not specified. Exiting..."
156 while not args
.silent
:
158 "Ok to recursively delete '%s' and all contents (Y/N)? Choosing Y will permanently delete the contents."
161 result
= str.upper(sys
.stdin
.read(1))
164 "Unable to copy files to the destination. The destination already exists."
169 shutil
.rmtree(args
.dest
)
172 copy_distro(args
.dest
, "x86", args
.source
, None)
173 copy_distro(args
.dest
, "x64", args
.source
, "amd64")